Skip to main content
Most of this documentation describes iBubbl talking to you. This page is the other direction: another app posts an event to iBubbl, and a workflow you built runs. It works with any app that can send a webhook — a form builder, a scheduling tool, your store, Zapier or Make. The case it was first built for: a customer’s card is declined on a subscription renewal, and you want to text them about it while they can still fix it.
Not to be confused with Webhooks, which is iBubbl sending events to your server. This page is about events arriving at iBubbl.

How it fits together

  1. Create a source in your dashboard under Settings → Inbound events. You get a URL with a credential built into it, shown once.
  2. Paste that URL into the sending app, and send a test event from it.
  3. Open the source’s Events & fields: the event appears there, and you pick the field holding the customer’s phone number by clicking it.
  4. Build a workflow whose trigger is Webhook received, pointed at that source. Its event name, Event ID and message fields can all be picked from the same event.
When an event arrives, iBubbl checks it (see Source types), finds the customer’s phone number in the payload, and starts your workflow.

The endpoint

This is the one endpoint in the API that takes no Authorization header — the credential is the token in the URL. That is not a shortcut: many apps, Recharge among them, let you configure only a destination URL and give you no way to set a header. Treat the URL like a password. If it leaks, use New URL on the source (the old URL stops working at once) or revoke the source. Bodies may be JSON or application/x-www-form-urlencoded form data, up to 256 KB. multipart/form-data isn’t supported: such a request is accepted but recorded as Event wasn’t JSON or form data, and starts nothing.

What you get back

runs_started is 0 whenever the event was accepted but nothing ran — no workflow was listening, or the event was a repeat of one already handled. That is normal. When it is unexpectedly 0, the source’s row in Settings → Inbound events says which of those it was. Errors are limited to 403 (signature did not match), 404 (no such source, or it was revoked), 413 (body over 256 KB) and, for secret-URL sources only, 429 (over 60 events a minute, while a workflow is listening on the source — see Source types). Everything else answers 200, deliberately — see Delivery. (Only POST is accepted; a GET to the URL returns 405.)

Source types

Any app (secret URL)

Most apps can’t sign a request in a way iBubbl could check, so for these the long, random URL is the credential — the same approach as Zapier’s and Make’s catch hooks. Create the source, paste the URL into the app, and send a test event. A secret-URL source accepts at most 60 events a minute. Over that, the answer depends on whether any active workflow is listening on the source: if one is, iBubbl answers 429 so the app retries later; if none is, the event is accepted (200) and dropped, since it couldn’t have started anything. Dropped events don’t appear in the source’s recent events. Recharge sources are never rate limited. For example:
Event name. iBubbl reads it from an X-Event-Topic or X-iBubbl-Topic header, or a top-level topic, type, event or event_type field. If the app puts it somewhere else, choose The event name is somewhere inside the payload on the trigger and pick the field. Phone number. By default iBubbl looks for phone, phone_number or contact.phone. If the app puts it elsewhere — lead.phone above — pick it in the source’s Events & fields. First and last name work the same way.

iBubbl-signed

For senders you control. iBubbl creates a signing secret (whsec_…, shown once). Sign each request with:
where <hex> is the HMAC-SHA256, keyed with the secret, of <t>. followed by the raw request body. Requests more than 5 minutes off from t are rejected. This is the same scheme iBubbl uses to sign the webhooks it sends you.

Connecting Recharge

In Recharge, create a webhook with your iBubbl URL as the address and charge/failed as the topic. You can do that from their API:
When you create the source in iBubbl, paste your API Client Secret — not your API token. They are different values. Find it in Recharge under Tools and apps → API tokens → your token → Edit admin API token.Pasting the token instead is the most common setup mistake, and it shows up as every event failing with “Signature did not match”.
Recharge signs each request with an X-Recharge-Hmac-Sha256 header. Despite the name, the value is not an HMAC — it is a plain SHA-256 of your client secret followed by the raw request body. iBubbl handles that for you; it is worth knowing only if you are comparing against your own verifier.

Writing the message

The whole event is available to your message template under trigger.event, rooted at the app’s own payload. Insert field on the Send message step lists the fields of the latest event and writes the right syntax for you. Recharge wraps a charge, so:
customer_hash comes in the payload, so the link costs no extra API call. (It is charge.customer_hash in Recharge’s 2021-01 API format. In the 2021-11 format the charge carries it as charge.customer.hash instead — use Insert field on a real event to see which one your store sends.) Link to the portal root rather than a deeper page: the exact path differs depending on which Recharge portal your store runs, and Recharge is migrating merchants between them. Once the customer updates their card, Recharge reschedules the retry itself — so “update your card and we’ll take care of the rest” is literally true.

Repeat events

Apps resend events. Recharge in particular sends charge/failed every time it retries a charge, and how many times that is depends on the retry settings in your own Recharge account. Without protection, a single declined card would text the customer on every one of those retries. The Event ID path on your trigger is what prevents it, and every Webhook received trigger needs one. It points at the field identifying the underlying object — for Recharge, charge.id. An event resolving to an ID that already started a run starts nothing new; the source records it as Already handled.
Paths start inside the sending app’s payload. Recharge wraps everything in a charge object, so the path is charge.id — not id.A path is field names separated by dots; a number selects an array element (line_items.0.sku). Don’t write a $. prefix: $.charge.id matches nothing.A path that matches nothing is treated as a configuration error: no workflow runs, and the source reports Event ID path not found. Sending nothing is the safer failure here than sending one message per retry.
Because the ID identifies the object rather than the delivery, this is permanent for that charge. To send a second, different message later in the dunning cycle, build a separate workflow on the charge/max_retries_reached topic.

Finding the customer

iBubbl looks for a phone number in the payload — for Recharge, in the billing address, or the shipping address when the billing phone is blank; for other sources, where you pointed it (see Any app) — and converts it to international format. Numbers arrive as the shopper typed them, so (310) 384-3698 and 3103843698 both work. A number without a leading + is read in the country named by a two-letter country_code or country field in the payload when there is one, otherwise in the source’s default country (the US unless it was set otherwise). A billing phone that can’t be read is not replaced by the shipping one. A number that cannot be read as a real phone number is rejected, not guessed at, and the event starts nothing. That matters more than it looks: the message you are sending carries a link to that customer’s account, so a number resolved onto the wrong person would hand a stranger access to someone else’s subscription. Events for customers with no phone number on file therefore do nothing, and the source reports No phone number in event. If your store collects phone numbers from only some customers, this feature reaches only those customers. A contact is created (or an existing one’s missing name filled in) only when a workflow starts for the event. Events nothing is listening for add no one to your contacts.

Delivery and retries

iBubbl answers 200 to anything it has verified, even when the event goes nowhere. That is on purpose. Recharge treats 408, 429 and 5xx as failures, retries 19 times over 48 hours, and then deletes the webhook registration and emails you. An endpoint that returned 500 on an unrecognised payload would eventually unsubscribe you without either side noticing. It also means the reason an event did nothing cannot live in the HTTP response. It lives on the source instead. Settings → Inbound events shows each source’s recent events — the newest 20, kept for 30 days — with what happened to each: Events dropped over a secret-URL source’s rate limit (with no workflow listening) are not recorded here.

New URL and revoking

New URL gives a source a new URL; the old one starts returning 404 at once, and the source keeps its settings and history. Update the sending app with the new URL. Do this if a URL leaks. Revoking a source is also immediate: its URL starts returning 404 and the source stops listening for good.