Stripe and webhook catchers
Updated
Kalman can take in events from platforms that send webhooks. Stripe has its own built-in connection. For anything else, use a webhook catcher: a Kalman URL that accepts a platform's payload as it already sends it.
Connect Stripe
- Open Integrations. Under Payments, find Stripe and click Connect.
- Copy the Webhook URL.
- In Stripe, go to Developers → Webhooks, add the URL, and subscribe to these events:
checkout.session.completedandpayment_intent.succeededbecomepurchase.invoice.paidbecomesrefill_purchased, but only for subscription renewals.charge.refundedbecomesrefund_issued.customer.subscription.deletedbecomessubscription_canceled.
- Paste the endpoint's signing secret (it starts with
whsec_) into Stripe signing secret and click Save. Kalman rejects deliveries until a secret is saved. After saving, the secret can't be viewed again.
Where to put kl_id and the product SKU
Kalman reads kl_id (the visitor's _kl_id cookie) and kalman_product_sku only from the metadata of the object in each event. It doesn't look them up on related objects. Set them on every object whose events you send:
| Stripe event | Object Kalman reads | Where to set kl_id and kalman_product_sku |
|---|---|---|
checkout.session.completed |
Checkout Session | client_reference_id (for kl_id) or the session's metadata |
payment_intent.succeeded |
PaymentIntent | payment_intent_data.metadata when you create the Checkout Session, or the PaymentIntent's metadata |
invoice.paid (renewals) |
Invoice | the invoice's metadata. Stripe doesn't copy subscription metadata onto renewal invoices, so set it on each invoice, for example from an invoice.created handler |
charge.refunded |
Charge | the charge's metadata. Check in Stripe that it carries kl_id; if it doesn't, the refund isn't joined to the visit |
customer.subscription.deleted |
Subscription | subscription_data.metadata at checkout, or the subscription's metadata |
To match products without a SKU, add Stripe price IDs to a product (Products and aliases). Kalman finds the price on invoice lines and subscription items, or in metadata.price_id. A Checkout Session event doesn't include its line items unless your endpoint expands them, so use kalman_product_sku there.
Format, test mode and duplicates
- Payload: Stripe's standard event JSON (
{"id": "evt_…", "type": …, "data": {"object": …}}), verified with theStripe-Signatureheader and yourwhsec_secret. Deliveries more than 5 minutes old are rejected. - API version: Kalman doesn't pin one. It reads both the older and the newer invoice-line shapes. If you upgrade your Stripe API version, send a test event and check the Events log.
- Test and live: each Kalman Stripe source has one signing secret, and Kalman doesn't check Stripe's
livemodeflag. Use a separate Kalman Stripe source, with its own URL and secret, for your test-mode endpoint, so test purchases never mix with real ones. - Duplicates: a purchase, refill, refund or cancellation is counted once per order, so a retried or duplicated delivery doesn't double-count. Other events are de-duplicated by Stripe's event id.
- Order: deliveries are recorded at the time Stripe says the event happened. Kalman doesn't reorder them: a refund that arrives before its purchase is still recorded as a refund.
Create a webhook catcher
Click Connect on Webhook catcher under Custom, or click Connect with a webhook catcher on any platform card. A bar at the top of the catcher's page tracks the steps: Choose platform, Copy URL and token, Send test events, Map fields, Event types, Test mapping, Go live.
The Endpoint panel gives two URLs:
- Webhook URL (includes token): paste this into the sending platform.
- Webhook URL (token in header): use this if the platform can set headers. Send the token as
Authorization: Bearer <token>or inX-Kalman-Token. This keeps the token out of server logs.
If the sender can sign requests the way Kalman does, change How the sender proves itself to Kalman HMAC signature.
Catch a sample
- A new catcher listens for 15 minutes. After that, click Listen for 15 minutes to listen again.
- In the sending platform, trigger each event you care about, such as a test order or a workflow run on a test contact.
- Click Refresh. Each delivery is kept as an encrypted sample. Samples are not recorded as events yet.
Map fields
- Fields seen lists each field path, its kind and how often it appears. Kalman never shows the values.
- Choose a Kalman field in each row's dropdown (email, phone,
order_ref,value,product_sku,kl_idand so on). - If one payload holds several events, set Events array path. Tick Values are in cents if the amounts are in cents.
- Click Save.
Name the events
- From a field: map a field to
event. Event types seen lists its values, and you translate each one, for exampleorder.paid→purchase. Kalman doesn't record a name that looks sensitive. - From the URL: add
&event=purchase(orlead,provider_approved…) to the end of a workflow's URL. If a mapped event field is present, it takes priority.
Test, then go live
- Click Test mapping on a sample. Kalman shows what it would record. Identity fields show only as hashed, and nothing is recorded.
- Click Process samples to record the caught samples. Mapped events then go to your connected ad platforms.
- A new catcher records only until you start it: deliveries are kept as samples, even after listening ends, and nothing becomes an event. When the mapping is right, click Start processing. From then on, new deliveries become events. Samples already caught wait for Process samples. Switch to recording only goes back.
Catchers created before November 9, 2026 keep processing as they did.
Monitor
- Recent deliveries shows the time, status and detail for each delivery. It never shows payloads.
- If a mapped field goes missing from deliveries, a warning appears: "The sender's payload may have changed." Catch a fresh sample and check the mapping. Saving the mapping resets the warning.
Raw bodies are stored encrypted and deleted after 30 days. Emails and phones are hashed on arrival.
What Kalman never sends: ad platforms get only allowlisted fields. They never receive product names or SKUs, raw payload fields, or plain-text contact details.
Related articles
- Connect Sylaris OSSend payments, provider decisions, shipments and refills from Sylaris OS to Kalman over a signed webhook, then check that they arrived.
- Products and aliasesAdd your programs with a SKU, price and projected LTV, and link unmatched SKUs or Stripe prices so revenue and LTV land on the right product.
- The Event log, deliveries and the data-flow recordSee every event Kalman received, exactly what it sent to Meta and why anything was held back, and download a data-flow record.
- Troubleshooting: no data or nothing sentWhy the tag isn't recording, a tracking domain is stuck, or events aren't reaching an ad platform, and how to fix each case.
Support
Still stuck? Log in and open a request.
We answer in writing within one business day.
Open a request