Skip to main content
CHIP Send delivers three webhook events. Each delivery is a JSON snapshot of the object after the change, with the event name in the Event-Type header and an X-Signature you must verify before parsing — see Validating Webhooks. Subscribe a webhook to any of them through the event_hooks field on Create a Webhook.

Delivery headers

Verify X-Signature before trusting a body — see Validating Webhooks. Failed deliveries are retried; see Delivery Protocol.
Read the raw request body. Framework middleware that parses JSON before your handler runs breaks verification, because re-serialising the parsed object produces different bytes than the ones that were signed. Take the raw buffer, verify, then parse.

bank_account_status

status is the status the account just moved into. A webhook is queued when the account record is created, so the first delivery you receive after adding a bank account can already be pending or verified if verification finished first. Verified:
Rejected:
Pending verification:

send_instruction_status

state is the state the instruction just moved into. Completed:
Accepted by the bank (not yet completed):
Rejected:

budget_allocation_status

This event is only delivered for allocations — rows with transaction_type: in. A row is created when you request a budget allocation, and its status moves pending → approved, or pending → expired.
Deductions are not delivered here. The ledger also holds transaction_type: out rows (the deduction behind a completed send, status: success) and you can read them from GET /send/send_limits, but they never produce a budget_allocation_status webhook. Reconcile completed payouts from send_instruction_status instead of waiting for a success event here.
Each approvals_details entry: Pending approval:
Approved allocation:
Expired allocation:

Reading the payloads

  • status and state always describe the object after the change, so an event is a snapshot rather than a diff. Do not infer the previous state from it.
  • Intermediate states can be superseded: when an object moves on before an earlier delivery is complete, CHIP suppresses the stale one so you always end at the latest state. Never assume you will receive every step — drive your logic off state / status in the body.
  • Deliveries are retried until your server answers 2xx, so the same state can arrive more than once, and after a retry it can arrive later than a newer state. Treat each body idempotently on the object id plus state / status.
  • Treat the body as the record of that moment. Fetch the object through the API if you need the current state.
  • Live bodies are compact JSON — one line, no whitespace between fields. The samples on this page are pretty-printed for reading. Verify and parse the raw bytes you received, never a re-serialised copy.
  • rejection_reason is the human-readable reason; it is null for successful states.
  • Amounts are not interchangeable across events: send instruction amount is a decimal string ("1500.00"), budget amount, fee and net_amount are numbers.
  • Timestamps are UTC in ISO-8601 with milliseconds. from_settlement is a plain date.
  • The ids, names, account numbers and amounts in these examples are illustrative.