POST to that URL whenever the event occurs.
Subscribe to an event
1
Discover available events
Call
GET /events to list the event
types you can subscribe to.2
Create a subscription
Call
POST /events/subscription
with the event_name and your callback_url. The response includes a
secret — store it to verify future deliveries.3
Acknowledge deliveries
Respond with a
2xx status so Karat knows the event was received.Secret generation
Karat generates a unique signing secret when you create a subscription. The secret is returned only once in the create subscription response — store it securely so you can verify deliveries.Handshake verification
When creating a subscription, the API verifies ownership of the callback URL by performing a challenge-response handshake. Your server must handle this before the subscription is accepted. The API sends aPOST request to your callback_url with a JSON body:
200 and a JSON
body echoing the challenge:
400 error with one of these messages:
Event types
Payload
Every delivery shares the same envelope —id, event, created_at,
subscription_id, and an event-specific data object.
payout.updated
tax_form.created
recipient.updated
Sent as a recipient moves through onboarding. The status field carries the
milestone:
Each milestone is sent at most once per onboarding invitation — repeating a
step (for example, re-signing a tax form) does not produce another event. The
tax_info_collected event is never sent for recipients you configured with
tax collection disabled; those recipients go straight from
onboarding_started to onboarding_completed.
first_name, last_name, and nickname are nullable. date is the ISO-8601
timestamp of when the milestone occurred.
business_type reports whether the recipient registered as an individual or
an entity. It is null until the recipient’s tax information has been
collected and shared with you — expect null on onboarding_started and a
value from tax_info_collected onward. It matches
profile.businessType on the recipients endpoints; sandbox
recipients always report individual.
Transaction events
Transaction subscriptions cover eligible open, unlocked operational checking accounts belonging to your API key’s organization. They are not limited to payouts created through the API. Usedata.transaction.accountId to identify the account; there is no account filter when creating a subscription. Create a separate subscription for each transaction event type you need:
relatedTransactionId is a provider association when known, not a guaranteed match; do not match by amount or description.
transaction.pending
transaction.updated
transaction.posted
transaction.pending_completed
transaction.updated can contain either a pending or posted record; the example shows a pending amount update. transaction.posted can arrive without a preceding pending event.
transaction.pending_completed means the hold is no longer active, not that it settled. Remove it from your pending set. Its status: "complete" is only delivered by this event and never appears in the active-pending endpoint results. A completion event may be your first notification for a pending entry created before your subscription. A released hold need not produce a posting; returns are separate movements.
Ordering, retries, and recovery
data.occurredAtis when Karat captured the change, not its provider booking time.data.revisionis a positive decimal string that increases independently per transaction ID. Compare it as an integer, not lexicographically, and never compare revisions between different transactions.- Delivery is at least once and may arrive out of order. Deduplicate using the envelope
id; retries retain the original payload and ID. Only apply a revision newer than the last one stored for that transaction. - Keep the completion revision after removing a pending entry, so a delayed pending update cannot restore it.
- Only subscriptions that existed when the change was captured receive that change. New subscriptions do not receive a historical backfill. Deleted subscriptions and accounts that are no longer eligible receive no new dispatch.
- Delivery may fail permanently after retries. Use the transactions endpoint to backfill posted records, refresh the complete active-pending set, and periodically reconcile after downtime or delivery failures.
Verify webhook signatures
Every delivery is signed so you can confirm it came from Karat. Verify the signature before processing the payload. Each request includes these headers:
The signature is an HMAC-SHA256 of
timestamp + "." + raw_body, keyed with
your subscription secret, then base64-encoded:
1
Look up the secret
Use
X-Karat-Subscription-Id to find the secret you stored when creating
the subscription.2
Check the timestamp
Reject deliveries where
X-Karat-Webhook-Timestamp is outside a ±300 second
window to protect against replays.3
Recompute and compare
Recompute the signature from the raw request body and compare it to the
value in
X-Karat-Signature using a constant-time comparison.4
Deduplicate
Use
X-Karat-Webhook-Id (and the id in the body) to ignore duplicate
deliveries.Delivery
- Deliveries are sent asynchronously and retried on failure.
- Always return a
2xxresponse quickly; do heavy processing out of band.
Manage subscriptions
- List your subscriptions with
GET /events/subscription. - Remove one with
DELETE /events/subscription/{subscription_id}.