Skip to main content
Pre-release — contact your Fortary account team for access.
Every delivery’s request body is an event envelope: a fixed outer shape plus a data payload specific to the event kind. Your webhook only receives the kinds it subscribed to.

The event envelope

{
  "id": "evt_01hz8x2k9qv7m3ntf5rw6ye8ka",
  "kind": "transaction.confirmed",
  "schemaVersion": 1,
  "date": "2026-06-10T14:23:05Z",
  "entityId": "entity_7c1e4a0c2f",
  "vaultIds": ["vault_3f8a2c1d9b"],
  "data": { }
}
FieldDescription
idUnique event id (evt_…). Stable across retries and redeliveries — deduplicate on it
kindThe event kind, resource.action (e.g. transaction.confirmed)
schemaVersionInteger version of this kind’s data schema
dateWhen the event occurred (not when it was delivered) — order on it
entityIdThe entity the event belongs to
vaultIdsVaults involved; empty for non-vault-scoped kinds; can contain several vaults for UTXO transactions
dataKind-specific payload, documented below
Asset amounts are strings in atomic units; amountUsd valuations are indicative JSON numbers. Timestamps are ISO-8601 UTC (Z), absent values are explicit null, and IDs are opaque prefixed strings — pass back exactly what you received.

Event kinds

KindFires when
transaction.requestedA transaction request is submitted and enters approval
transaction.approvedThe request passes its approval policy
transaction.rejectedThe request is rejected by an approver
transaction.expiredThe request expires before collecting the required approvals
transaction.broadcastedThe transaction is submitted to the network and receives its on-chain hash
transaction.confirmedThe transaction reaches the required confirmation depth
transaction.failedThe transaction’s on-chain execution fails
address.createdA deposit address is issued for a vault

Transaction lifecycle

A custody transaction is correlated by txRequestId until broadcast and by txHash after it — transaction.broadcasted carries both:
transaction.requested ──► transaction.approved ──► transaction.broadcasted ──► transaction.confirmed
          │                                                            └─────► transaction.failed
          ├──► transaction.rejected
          └──► transaction.expired
Incoming deposits have no request phase — the first event you receive for a deposit is transaction.confirmed.
Credit funds only on transaction.confirmed. Every earlier event is a pre-settlement observation.

transaction.requested, transaction.approved, transaction.rejected, transaction.expired

The approval-phase events share one payload — the request’s identity and network. Authoritative amounts arrive with transaction.confirmed.
{
  "id": "evt_01hz8vq4t2m9k7xw3nrf5ye8c2",
  "kind": "transaction.requested",
  "schemaVersion": 1,
  "date": "2026-06-10T14:02:11Z",
  "entityId": "entity_7c1e4a0c2f",
  "vaultIds": ["vault_3f8a2c1d9b"],
  "data": {
    "txRequestId": "9f4e6a2b-3c1d-4e8f-a501-2b7c9d0e1f23",
    "networkId": "eip155:43114"
  }
}
  • txRequestId — the transaction request’s identifier; also present on transaction.broadcasted for correlation.
  • networkId — the network, as a CAIP-2 id (e.g. eip155:43114 for Avalanche C-Chain).

transaction.broadcasted

Fires when the transaction is submitted to the network, joining the request-phase identity (txRequestId) to the on-chain identity (txHash). No amounts yet — nothing is decoded at broadcast time.
{
  "id": "evt_01hz8wr7p5n2j9ky4mtg6ze1d8",
  "kind": "transaction.broadcasted",
  "schemaVersion": 1,
  "date": "2026-06-10T14:08:42Z",
  "entityId": "entity_7c1e4a0c2f",
  "vaultIds": ["vault_3f8a2c1d9b"],
  "data": {
    "txRequestId": "9f4e6a2b-3c1d-4e8f-a501-2b7c9d0e1f23",
    "networkId": "eip155:43114",
    "txHash": "0x9c4f2ea1b83d5f7c6a01e9d24b8f3a5c7e610d92f48ab35c17ed09b64a2f8e31"
  }
}

transaction.confirmed and transaction.failed

Both carry a full snapshot of the transaction as observed on-chain — the same shape, distinguished by status. Example: an incoming AVAX deposit —
{
  "id": "evt_01hz8x2k9qv7m3ntf5rw6ye8ka",
  "kind": "transaction.confirmed",
  "schemaVersion": 1,
  "date": "2026-06-10T14:23:05Z",
  "entityId": "entity_7c1e4a0c2f",
  "vaultIds": ["vault_3f8a2c1d9b"],
  "data": {
    "txHash": "0x2b7e91c04a6f8d3e5c19b0a7f42d68e3a5c901f7d84b26ea30fc59d18b47a6e2",
    "networkId": "eip155:43114",
    "blockNumber": 41234567,
    "timestamp": "2026-06-10T14:22:58Z",
    "status": "CONFIRMED",
    "amounts": [
      {
        "direction": "CREDIT",
        "asset": {
          "kind": "native",
          "assetId": "eip155:43114",
          "decimals": 18,
          "symbol": "AVAX",
          "name": "Avalanche",
          "logoUri": null
        },
        "amount": "1250000000000000000",
        "amountUsd": 31.25,
        "fromAddresses": ["0x1f0ec8b90a37f6d2f0e5b3a49c7d81f2e6a04b53"],
        "toAddresses": ["0x8ab34c1d9e2f5a706b8c3d4e5f6a7b8c9d0e1f2a"]
      }
    ],
    "fee": null,
    "flow": "incoming"
  }
}
  • statusCONFIRMED or FAILED. transaction.failed is only delivered for outgoing transactions — a deposit that fails on-chain produces no event.
  • amounts — one entry per asset movement touching your vaults. direction is CREDIT or DEBIT; amount is a string in the asset’s atomic unit; amountUsd may be null when no price is available.
  • assetkind: "native" (assetId is the bare CAIP-2 network id) or kind: "token", which adds namespace (erc20 or spl) and contractAddress.
  • fee — the network fee, or null when it wasn’t paid by you (typical for deposits).
  • flow — the transaction’s direction relative to your vaults: incoming, outgoing, internal, or trade.
  • blockNumber — may be null on networks without block-height semantics.

address.created

Fires when a deposit address is issued. The vault is in the envelope’s vaultIds.
{
  "id": "evt_01hz8y6m3wp8n4kv7qsx2ze9fb",
  "kind": "address.created",
  "schemaVersion": 1,
  "date": "2026-06-10T15:01:33Z",
  "entityId": "entity_7c1e4a0c2f",
  "vaultIds": ["vault_3f8a2c1d9b"],
  "data": {
    "networkId": "bip122:000000000019d6689c085ae165831e93",
    "address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
  }
}

Schema versioning

Each kind’s data payload is versioned via schemaVersion. Additive changes ship under the same version — treat unknown fields as forward-compatible. Breaking changes increment the version and are announced in the changelog.