Skip to content

Webhook Events Reference ​

All event payloads share the same flat data structure built from the payment record. Fields that do not apply to the current state are null. Decimal values are JSON strings.

Common data fields (all payment.* events):

FieldTypeDescription
payment_idstring (UUID)Payment identifier
statusstringCurrent payment status (lowercase snake_case)
amount_usdstringPayment amount
received_cryptostringTotal crypto received so far
crypto_symbolstring | nulle.g. "ETH"
crypto_namestring | nulle.g. "Ethereum"
chainstring | nullChain short name, e.g. "eth"
locked_rate_usdstring | nullLocked rate
fee_payerstring"user" or "payer"
feesobject | null{ "service_fee_usd": "...", "conversion_fee_usd": "..." } — present once fees are computed
net_amount_usdstring | nullNet settlement (present at completion)
selection_expires_atstring | nullSelection window deadline
created_atstringCreation timestamp
completed_atstring | nullCompletion timestamp
redirect_urlstring | nullMerchant redirect URL

Payment events ​

payment.created ​

Fired when a merchant creates a payment request.

json
{
  "event": "payment.created",
  "timestamp": "2026-05-16T12:00:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "awaiting_selection",
    "amount_usd": "150.00",
    "received_crypto": "0",
    "crypto_symbol": null,
    "crypto_name": null,
    "chain": null,
    "locked_rate_usd": null,
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": null,
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.awaiting ​

Fired when the payer confirms their token selection and the rate is locked. The payment is now waiting for an on-chain transaction. A selection_expires_at countdown starts.

json
{
  "event": "payment.awaiting",
  "timestamp": "2026-05-16T12:01:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "awaiting_payment",
    "amount_usd": "150.00",
    "received_crypto": "0",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2000.00",
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": "2026-05-16T12:31:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

The wallet address the payer should send to is available via GET /v1/pay/{payment_id} (or the API-key-authenticated payment detail endpoint).

payment.partial ​

Fired when a transaction is detected at the payment wallet but the received amount is less than required (status: "partially_paid").

json
{
  "event": "payment.partial",
  "timestamp": "2026-05-16T12:03:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "partially_paid",
    "amount_usd": "150.00",
    "received_crypto": "0.030000000000000000",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2000.00",
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": "2026-05-16T12:31:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.confirming ​

Fired when the required amount has been received and the payment is waiting for block confirmations.

json
{
  "event": "payment.confirming",
  "timestamp": "2026-05-16T12:04:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "confirming",
    "amount_usd": "150.00",
    "received_crypto": "0.075000000000000000",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2000.00",
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": "2026-05-16T12:31:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.completed ​

Fired when the payment is fully confirmed, swept, and settled. This is the primary event to trigger order fulfilment. Fees and net_amount_usd are populated.

json
{
  "event": "payment.completed",
  "timestamp": "2026-05-16T12:05:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "completed",
    "amount_usd": "150.00",
    "received_crypto": "0.075000000000000000",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2000.00",
    "fee_payer": "user",
    "fees": {
      "service_fee_usd": "0.75",
      "conversion_fee_usd": "1.50"
    },
    "net_amount_usd": "147.75",
    "selection_expires_at": "2026-05-16T12:31:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": "2026-05-16T12:05:00.123456+00:00",
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.expired_selection ​

Fired when the chain selection window expires. The payer can return to the payment page and reselect a token. No funds are lost — any partial payments already received are preserved (and shown via received_crypto).

json
{
  "event": "payment.expired_selection",
  "timestamp": "2026-05-16T12:31:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "expired_selection",
    "amount_usd": "150.00",
    "received_crypto": "0.030000000000000000",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2000.00",
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": "2026-05-16T12:31:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.reselected ​

Fired when the payer reselects a token after expired_selection. A new rate is locked and a new selection window starts (status returns to awaiting_payment).

json
{
  "event": "payment.reselected",
  "timestamp": "2026-05-16T12:45:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "awaiting_payment",
    "amount_usd": "150.00",
    "received_crypto": "0.030000000000000000",
    "crypto_symbol": "ETH",
    "crypto_name": "Ethereum",
    "chain": "eth",
    "locked_rate_usd": "2100.00",
    "fee_payer": "user",
    "fees": null,
    "net_amount_usd": null,
    "selection_expires_at": "2026-05-16T13:15:00.123456+00:00",
    "created_at": "2026-05-16T12:00:00.123456+00:00",
    "completed_at": null,
    "redirect_url": "https://yourstore.com/thank-you"
  }
}

payment.blacklisted ​

Fired when a transaction is detected from an address on the platform blacklist. The payment cannot proceed.

json
{
  "event": "payment.blacklisted",
  "timestamp": "2026-05-16T12:03:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "blacklisted",
    "amount_usd": "150.00",
    "received_crypto": "0",
    ...
  }
}

No sender address or reason is included for security reasons.

payment.failed ​

Fired when a system error occurs during payment processing that requires investigation (including sweep failures).

json
{
  "event": "payment.failed",
  "timestamp": "2026-05-16T12:03:00.123456+00:00",
  "data": {
    "payment_id": "9f1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "sweep_failed",
    ...
  }
}

Check GET /v1/payments/{payment_id} for details; contact support if a payment enters this state.

Withdrawal events ​

Status note (2026-08-31): withdrawal events are not yet emitted by the live platform — they are valid, subscribable, and documented here as the contract for their emission, but subscribing to them today yields no notifications. Track withdrawal status via GET /v1/withdrawals until emission is wired. This note will be removed when the events go live. (Internal tracking: spec 008 drift register, entry 1.)

withdrawal.completed ​

Fired when a withdrawal transaction has been confirmed on-chain and the funds have arrived at your wallet.

json
{
  "event": "withdrawal.completed",
  "timestamp": "2026-05-16T14:00:00.123456+00:00",
  "data": {
    "withdrawal_id": "w1x2y3z4-...",
    "status": "completed",
    "amount_usd": "147.75",
    "fee_usd": "1.00",
    "net_amount_usd": "146.75",
    "chain": "eth",
    "destination_address": "0xyourwallet...",
    "tx_hash": "0xwithdrawal...",
    "failure_reason": null,
    "completed_at": "2026-05-16T14:00:00.123456+00:00"
  }
}

withdrawal.failed ​

Fired when a withdrawal transaction fails and cannot be automatically retried. failure_reason describes the cause where available.

json
{
  "event": "withdrawal.failed",
  "timestamp": "2026-05-16T14:00:00.123456+00:00",
  "data": {
    "withdrawal_id": "w1x2y3z4-...",
    "status": "failed",
    "amount_usd": "147.75",
    "fee_usd": "1.00",
    "net_amount_usd": "146.75",
    "chain": "eth",
    "destination_address": "0xyourwallet...",
    "tx_hash": null,
    "failure_reason": "Transaction broadcast failed: insufficient gas",
    "completed_at": null
  }
}

Event subscription ​

You can subscribe to specific event types in the Client Portal → Dashboard → Webhooks, or via PUT /v1/webhooks:

json
{
  "events": [
    "payment.completed",
    "payment.expired_selection",
    "payment.reselected",
    "withdrawal.completed",
    "withdrawal.failed"
  ]
}

Use ["*"] to receive all events. Invalid event names are rejected with a validation error.

TokenCashFlow Documentation