Payment Updates
Event Types
| Event | Fired when |
|---|---|
payment.created | A payment has been created in Tesser's system |
payment.quote_created | Route planning is complete; execution steps are created with exchange rate info |
payment.balance_updated | Balance check result is available (reserved or awaiting_funds) |
payment.risk_updated | Risk status has changed. See Risk Statuses and Webhooks for the six risk_status values and what each one means |
payment.updated | General notification that a field on the payment has been updated. |
payment.expired | The payment reached its expiration date-time and is no longer actively processing |
For a detailed breakdown of what each event means in the context of a payout, see Funds Movement Lifecycle and Data Model.
Step Events
Once steps are created (payment.quote_created), individual step lifecycle events fire as each step progresses:
| Event | Fired when |
|---|---|
step.signature_requested | Tesser has prepared an unsigned transaction and is waiting for your signature. The payload carries it as unsigned_transaction |
step.signed | Step has been cryptographically signed |
step.submitted | Step has been submitted for execution |
step.confirmed | Step execution is confirmed on-chain or by the partner |
step.completed | Step finished successfully |
step.failed | Step encountered an error and could not complete |
step.updated | General notification that a field on the step has been updated |
The data.object for Payment step events is a PaymentStep resource.
step.signature_requested and step.signed fire only for steps your organization signs — on-chain steps out of a self-custodial wallet, where provider_key is turnkey. Steps executed by a custodian or liquidity provider go straight to step.submitted. To sign, see Sign a Wallet Step and Payout Step Signing.
Expiration
When a payment reaches expires_at before completing, its unfinished steps are resolved and two kinds of event fire:
step.failed, one per step still increatedorsignature_requested— the only two statuses expiration fails. Each carriesfailed_atand astatus_reasonsentry witherror_codetransfers-9204("The transfer expired before it could be executed"). A step that has reachedsigned,submitted, orconfirmedis in flight on-chain, so expiration leaves it to resolve on its own outcome instead of failing it.payment.expired, carrying the final state of the payment.
No payment.updated follows payment.expired — the expiration event itself carries the final top-level values, including whatever the actual overlay settled to. Steps never emit an event of their own for expiration; it is a property of the payment, and a failed step's outcome surfaces as step.failed.
For how the payment's fields look at expiration, see Expiration.
Inbound Payments
The events above describe an outbound payout. Inbound Payments use different event sequences depending on whether funds arrive at a managed wallet or an OpenFX ledger.
Managed Wallet Inbound Payments
Funds arriving at one of your managed wallets from an external sender use the same event types, with these differences:
- No planning events. There is no quote and no
PATCH, sopayment.quote_creatednever fires.payment.createdarrives with theestimatedoverlay already populated from the observed on-chain transaction. - No signing events. The external sender signed and broadcast the transaction, so
step.signature_requestedandstep.signednever fire. - One step. The payment has exactly one
transferstep, created inconfirmedstatus, which moves tocompletedwhen the block finalizes. - Risk screening targets the sender and does not gate the credit.
payment.risk_updatedreports the screening outcome for the sending wallet. It runs in parallel with on-chain finalization, so it can arrive before or afterstep.completed, and the receiving wallet's available balance updates on finalization regardless of the outcome.
For the full inbound event sequence and payloads at each stage, see Receive an Inbound Payment to a Wallet.
OpenFX Ledger Inbound Payments
When OpenFX reports an on-chain deposit that does not match a submitted withdrawal or rebalance, Tesser creates a completed inbound Payment for the receipt and adds the amount reported by OpenFX to the ledger's available_balance.
- One terminal event.
payment.createdis the only lifecycle webhook. Its Payment contains one completedtransferstep, withestimated.*andactual.*populated andprovider_key: "openfx". Because the Payment is already complete when Tesser creates it, no planning, signing, step-status, orpayment.updatedevents follow. - No balance check.
balance_statusisnull, and the received amount is available whenpayment.createdarrives. - No wallet-risk screening.
risk_statusisunchecked; nopayment.risk_updatedevent is emitted for this provider-ledger receipt.
If an OpenFX deposit could match more than one submitted flow, Tesser does not create an inbound Payment or update the ledger's tracked balance. The submitted flows remain pending and require support to resolve.
Payload
The data.object for each top-level Payment event contains the full payment resource, including its steps. See General for the envelope shape and an example payload, and the Payment schema for the full field reference.
For payments that undergo compliance screening, three arrays carry its output. They are populated by the time payment.risk_updated fires and are repeated on every later payment event:
| Field | Carries | Reference |
|---|---|---|
risk_status_reasons[] | The findings behind the current risk_status, each marked decisive or not | Reading risk_status_reasons[] |
participants[] | The parties Tesser identified in the flow of funds, each with the record it was reconciled to and the reconciliation outcome | Payment Participants |
provider_metadata[] | Provider-defined wallet screening and Travel Rule responses for analytics and audit; screening data can reference networks other than the payment network | Raw Screening Data |
Key Status Fields
For details on how risk_status and balance_status evolve through a payout, see Risk Statuses and Balance Statuses.