Skip to main content
Every WalletSuite webhook delivery is a single HTTP POST with a JSON body in a stable envelope. The envelope carries delivery and routing metadata; the data object carries the event itself.

The envelope

The envelope is shared by every event type; each event’s data schema and example payloads live in the catalog below.

Fields

FieldTypeDescription
schema_versionstringPayload schema version. See Payload versioning.
event_idstring (UUID)Unique identifier for this event - equals the Webhook-Id header, your idempotency key.
event_typestring (open enum)What happened, e.g. "transfer.received".
subscription_idstring (UUID)The subscription that matched and produced this delivery. Use it to route the event back to the address/chain you registered.
occurred_atstring | null (ISO-8601)When the event happened on-chain, or null when that time isn’t available. Always UTC, ends in Z, with exactly 3 fractional digits (milliseconds).
dataobjectThe event payload. Its shape depends on event_type - see the event catalog.

Example

Example delivery (transfer.received)
{
  "schema_version": "1.0",
  "event_id": "5b8e3c1a-9d27-4f60-b4e8-6a1c0d9f3b52",
  "event_type": "transfer.received",
  "subscription_id": "9b7c1e2a-4f6d-4c3b-8a1e-2d5f7a9c0b13",
  "occurred_at": "2026-05-26T14:22:48.123Z",
  "data": { ... }
}

Payload versioning

schema_version is pinned per subscription: a subscription is pinned to the version current at creation and keeps receiving that version’s payloads for its lifetime.
  • Within a version, evolution is additive. New fields may be added to the envelope or the data object. Existing fields keep their names, types, and meaning. Your parser must tolerate unknown fields rather than reject them.
  • Breaking changes ship as a new version. If a field is ever renamed, removed, or has its type changed, that arrives as a new schema_version. Existing subscriptions stay on their pinned version until you explicitly opt in.

Event catalog

One entry per event type: what fires it, the data schema, and example payloads.

transfer.received

Fired once per incoming transfer to a watched address, when WalletSuite first observes it on-chain. The data object:
FieldTypeDescription
chainstring (open enum)The chain the transfer happened on, e.g. "ethereum", "tron".
directionstringTransfer direction relative to the watched address, e.g. "incoming".
tx_hashstringThe transaction hash on the source chain.
block_numbernumberBlock height in which the transfer was included.
fromstringSender address, in the chain’s canonical encoding - see Address encodings.
tostringRecipient address - the watched address that matched your subscription. Same encoding as from.
amountstringTransfer amount in token units, as a decimal string - see the warning below.
asset_typestring (open enum)The asset standard of the transfer, e.g. "native", "erc20", "trc20". Branch on this field to decide how to interpret the asset - never infer from asset_contract nullability.
asset_contractstring | nullThe token contract address, in the chain’s canonical encoding. null for native transfers, and may also be null for a token transfer when the contract address isn’t available.
amount is a decimal string in token units, already adjusted for the asset’s decimals. "1.5" means 1.5 tokens, not 1.5 wei. It is never in scientific notation and has arbitrary precision.Parse it with a decimal/big-number type (decimal.Decimal, BigNumber, BigDecimal), never a native float - IEEE-754 floats silently lose precision on values like USDC amounts and large token balances.

Example payloads

Four complete transfer.received payloads - one per asset shape.
ETH native transfer
{
  "schema_version": "1.0",
  "event_id": "5b8e3c1a-9d27-4f60-b4e8-6a1c0d9f3b52",
  "event_type": "transfer.received",
  "subscription_id": "9b7c1e2a-4f6d-4c3b-8a1e-2d5f7a9c0b13",
  "occurred_at": "2026-05-26T14:22:48.123Z",
  "data": {
    "chain": "ethereum",
    "direction": "incoming",
    "tx_hash": "0x9f3c1d8e7a2b4f6c0d9e8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d",
    "block_number": 18573245,
    "from": "0x1234567890abcdef1234567890abcdef12345678",
    "to": "0xabcdef1234567890abcdef1234567890abcdef12",
    "amount": "1.5",
    "asset_type": "native",
    "asset_contract": null
  }
}

Address encodings

from, to, and asset_contract use each chain’s canonical address encoding, consistent with the rest of the WalletSuite API. On input - for example, when you register a subscription - common representations of an address are accepted and normalized to that canonical form.

Event kinds vs event types

Two different concepts share similar names:
ConceptWhere it livesWhat it is
eventKindsOn the subscription (you set it when you POST /api/notifications/subscriptions)Asset-scope filters that decide which transfers you get notified about. Values: "INCOMING_NATIVE", "INCOMING_FUNGIBLE".
event_typeOn the delivered payload (the envelope)The type of event that actually arrived on the wire, e.g. "transfer.received".
eventKinds is a subscribe-time filter, not a delivered field. Subscribing with ["INCOMING_NATIVE"] means you only receive native-coin transfers; ["INCOMING_FUNGIBLE"] means only token transfers; both means both. Either way, you distinguish native from token deliveries by reading asset_type on the payload, not by inspecting eventKinds (which is never sent). See Quickstart for creating subscriptions.

Quickstart

Create a subscription, provision a signing secret, and receive your first event.

Verify Signatures

Validate the Standard Webhooks signature against the raw request body.

Delivery & Retries

Acknowledgement window, retry schedule, ordering, and at-least-once semantics.

Troubleshooting

When a payload fails to verify or never arrives - resolution checklists and FAQ.

Best Practices

Idempotency, async processing, and hardening your endpoint for production.