General
All Tesser webhook events share a common envelope structure. The envelope wraps event-specific data in a consistent format so your handler can route and process events uniformly.
Envelope Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique event identifier |
type | string | Event type in scope.action format (e.g. payment.quote_created) |
created_at | string | ISO 8601 timestamp of when the event was created |
data | object | Contains the event-specific payload under data.object |
Event Type Format
Event types follow the pattern scope.action. Current scopes are payment, deposit, withdrawal, rebalance, and step. See Payment Updates and Treasury Updates for event details.
Example Payloads
The data.object carries the full resource for top-level events (payment.*, deposit.*, withdrawal.*, rebalance.*) and the individual step resource for step.* events. The top-level examples below use the terminal-state *.updated event, which carries the fullest payload — desired, estimated, and actual overlays all populated, and each step in a terminal status with its timestamps and actual.* filled in. The step example uses step.completed.
The compliance arrays on the Payment example — risk_status_reasons[], participants[], and provider_metadata[] — are shown empty to keep the envelope readable. For populated examples of each, see Outcome Examples and Participants Examples.
Example terminal-state payment.updated webhook (USDC payout on Ethereum, complete):
Code
Inbound variant. The example above is an outbound payout. Inbound payments use the same envelope and the same Payment resource, with these differences:
| Field | Outbound | Inbound |
|---|---|---|
direction | outbound | inbound |
funding_account_id | the account funding the payout | the originator's generic account when Travel Rule data sent an account number, otherwise null |
desired.* | echoes what you requested | all null — you never requested the payment |
estimated.* | populated at planning (payment.quote_created) | populated when Tesser records the on-chain transaction (payment.created) |
expires_at | end of the quote and funding window | null |
steps[] | one entry per planned leg | exactly one, created in confirmed status |
steps[].provider_key | circle_mint, openfx, or turnkey | null — the external sender signed and broadcast the transaction |
Travel Rule data can arrive after payment.created: when the funds land first, Tesser creates the payment from the on-chain transfer, and the originator's participants[] and funding_account_id arrive later in a payment.updated. When that data names the originator VASP, wallet screening runs again and its payment.risk_updated delivers them instead, unless a risk review decision is already recorded, in which case payment.updated delivers them. See The Originator's Funding Account.
For full inbound payloads at each stage, see Receive an Inbound Payment to a Wallet.