- Your own endpoint — you expose an HTTP endpoint, Airdun calls it and maps the JSON response onto named fields you define.
- Stripe metadata — you sync your data onto the
metadataof your Stripe Customer and Subscription objects, and Airdun reads it from Stripe directly. Nothing to host.
Airdun is the client. There is no ingest API and no way to push data to Airdun. Enrichment is a read, performed by Airdun — against an endpoint you host, or against the metadata you keep on Stripe.
When Airdun reads your data
Whichever source is active, it is read at two moments — never once per message, and never on a fixed schedule:- At case creation. The response is projected into a snapshot written onto the case. Every downstream step reads that snapshot.
- Refresh during the case. When Airdun’s recovery engine evaluates an open case and the snapshot is older than 6 hours, the source is read again and the snapshot is replaced. On these refresh calls the timeout is capped at 4 seconds, even if you configured a longer one.
Reading from Stripe metadata
If you already sync your data to Stripe — or would rather not host an endpoint — Airdun can read themetadata you keep on your Stripe objects instead.
For each read, Airdun fetches the customer and one subscription live from Stripe, through the Stripe connection you already granted, and assembles them into a single JSON document your field paths are evaluated against:
- Paths start at the document root:
$.customer.metadata.team_size,$.subscription.metadata.plan. - The subscription is the one attached to the case’s failing invoice; outside a case (tests, previews), the customer’s most recent one.
subscriptionisnullwhen the customer has none. - There is nothing to host, authenticate, or rotate — the read rides on the existing Stripe connection.
Limits and value formats
Stripe’s own metadata limits apply: 50 keys per object, 40 characters per key name, 500 characters per value — and every value is a string. Store values so they survive type coercion:
Keep metadata keys identifier-shaped (
plan_tier, not plan-tier) so the path syntax can reach them.
Freshness
Airdun reads Stripe live at case creation and on refresh, but the values themselves are whatever your last sync wrote. If your sync lags, recovery runs on lagged data — Airdun has no way to detect this, and the snapshot timestamp reflects the read, not your sync. The endpoint source does not have this limitation.Testing the sync
Use Test Stripe sync in the dashboard: pick a real customer and Airdun shows the raw customer and subscription document alongside the projected fields. The field dialog also includes a metadata explorer that lists the keys actually present on a sample customer, so you can map them without guessing. If a test finds no metadata at all, your sync has most likely never written to Stripe.Your own endpoint: the contract
URL
Your URL must contain the{customer_id} placeholder:
- The placeholder is replaced with the Stripe customer ID (
cus_…), URL-encoded. - Only the first occurrence of
{customer_id}is substituted. - HTTPS is required. Plain HTTP is accepted only for
localhostand127.0.0.1. - Maximum length: 2048 characters.
Authentication
Three modes are available. Airdun stores your secret encrypted at rest (AES-256-GCM).NONE
NONE
No authentication header is sent. Only appropriate if your endpoint is protected some other way — the Stripe customer ID is not a secret.
BEARER
BEARER
Airdun sends:
API_KEY
API_KEY
Airdun sends your secret as the raw value of a header you name — no The header name is required when this mode is selected. Maximum 128 characters.
Bearer prefix, no scheme:Custom headers
You can add up to 20 additional headers (name ≤ 128 chars, value ≤ 1024 chars).Timeout and failure
- Timeout is configurable from 500 ms to 30 000 ms. Default: 3000 ms. The configured value applies in full at case creation; refresh calls cap it at 4000 ms.
- There are no retries. Each call is a single request. If it fails, it fails — the next opportunity is the next refresh.
- The strategy and message-generation models receive no enrichment context.
- Escalation rules that reference an
enrichment.*field are skipped. Rules that do not reference enrichment still evaluate normally.
A response that is valid JSON but does not match your field mapping is not an error. Unmatched paths simply resolve to
null, and the case proceeds silently. Check the call log in your dashboard if fields arrive empty.Mapping the response to fields
Airdun does not care about your response shape. You define up to 100 fields, each of which extracts one value from the JSON. The mapping works the same for both sources — with the endpoint, paths run against your response body; with Stripe metadata, they run against the{ customer, subscription } document shown above.
Every field is optional. A path that does not resolve yields
null for that field and nothing else happens — the other fields are unaffected and the case proceeds. There is no way to declare a field mandatory, and a missing field is never an error.
Supported path syntax
The path syntax is a deliberately small subset and is not general-purpose JSONPath. A path must match:$:
- Dot access on identifier-shaped keys —
$.plan.name - Numeric array indexing —
$.seats[0].email
Type coercion
The declaredtype controls how the extracted value is coerced. Anything that cannot be coerced becomes null.
Where enriched data is used
Once snapshotted, your fields feed the same consumers whichever source produced them:Recovery strategy
Fields are passed to the model that designs the recovery plan, as a
name → value map. They influence channel ordering, touchpoint count, and timing.Message generation
The same context is available to the model that writes each message.
Escalation rules
Fields are addressable as
enrichment.<field_name> in escalation conditions — for example enrichment.plan.Language resolution
One field can be nominated to carry the customer’s language. See below.
Phone resolution
One field can be nominated to carry the customer’s phone number, used for SMS and WhatsApp outreach. See below.
Language field
You can nominate one of your fields as the language field. Itsname must match an existing field name.
Airdun resolves a customer’s language in this order, taking the first that yields a value:
- The language declared on the customer in Airdun
- Stripe’s
preferred_locales - Your nominated enrichment field
- A country-to-language mapping
- The workspace fallback language
Phone field
You can also nominate one field as the phone field. Itsname must match an existing field, and that field must be of type STRING — a NUMBER field would drop the leading + or 0 and the value would silently fail to parse.
When the field resolves to a valid phone number, it takes priority over the phone number on the Stripe customer for SMS and WhatsApp outreach. A value that does not parse to a usable number ("N/A", a malformed string) is ignored and the Stripe phone is used instead.
Example
Your endpoint:
With
locale nominated as the language field, and an escalation rule on enrichment.revenue_ltv_usd.
Testing and observability
Use Test endpoint (endpoint source) or Test Stripe sync (Stripe source) in the dashboard to fire a real read with a customer of your choice. This performs an actual call and shows you the raw response alongside the projected fields — the fastest way to check a path, an auth header, or whether your sync writes what you think it writes. Every read Airdun performs is recorded, including failures, with its status, duration, source, and error category (timeout, network, http_4xx, http_5xx, http_other, stripe_error, or unknown). Each entry is tagged with its trigger — case creation, mid-case refresh, or a manual test. Review them in the call log in your dashboard.
Enrichment can also be switched off without deleting the configuration: the source, auth, and field mappings are kept, but no reads are made and new cases open with an empty snapshot.
Recovery cases fired from the playground do not read either source — the customer is synthetic, so the lookup would be meaningless. The snapshot for those cases is whatever the playground supplies.
Implementation notes (endpoint source)
- Respond fast. The default budget is 3 seconds with no retry. Serve from a cache or a precomputed table rather than doing expensive joins on the request path.
- Handle unknown IDs. Stripe customer IDs may exist that your system has no record of. Return
2xxwith the fields you have rather than a 404 — a non-2xx discards the entire snapshot, including fields you could have supplied. - Keep keys identifier-shaped so the path syntax can reach them.
- Do not gate on the customer ID alone. It travels in the URL and is not a secret. Use
BEARERorAPI_KEY.
