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
- Create a source in your dashboard under Settings → Inbound events. You get a URL with a credential built into it, shown once.
- Paste that URL into the sending app, and send a test event from it.
- Open the source’s Events & fields: the event appears there, and you pick the field holding the customer’s phone number by clicking it.
- 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.
The endpoint
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 answers429 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:
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:
<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 andcharge/failed as the topic. You can do that from their API:
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 undertrigger.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 sendscharge/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.
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 answers200 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 returning404 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.
