Channel Webhooks

Subscribe to channel payment events — detection, screening, holds, confirmation, and rejection — as customer deposits land on your channels.


BEEM sends webhooks for every channel payment, keeping you informed as customer deposits land on your channel addresses.

Channel webhooks are separate from Payment Link webhooks — they use the channel source and a distinct event namespace. Your single webhook listener receives both; you branch on the source and event fields. If you also use Payment Links, see Payment Link Webhooks for those events.

Webhook structure

A channel webhook has three sections:

{
  "event": "layer1:payment:channel:transaction-detected",
  "source": "channel",
  "data": {}
}
FieldDescription
sourceThe product source. For a channel payment, this is always channel.
eventThe event type — what happened. See below.
dataThe full channel payment object.

Event types

A channel deposit can produce up to five events. Whether each event fires — and the order they come in — depends on the outcome of compliance screening.

EventWhen it fires
layer1:payment:channel:transaction-detectedA deposit has been seen on-chain at a channel address but has not yet reached the required confirmations. The payment status is DETECTED.
layer1:payment:channel:transaction-screening-requestedThe deposit has been submitted to compliance screening. Always fires after transaction-detected. The next event is either transaction-held (if screening flags it) or the deposit continues to its next status.
layer1:payment:channel:transaction-heldThe deposit was held by compliance screening. Funds are not credited until the hold clears. Fires for both KYT (Chainalysis) flags and Travel Rule RFIs — call GET /platform/v1/travel-rule-rfis to determine which. See Building a Travel Rule Integration.
layer1:payment:channel:transaction-confirmedThe deposit reached the required confirmations and funds have been credited to the linked wallet. The payment status is COMPLETE.
layer1:payment:channel:transaction-rejectedThe deposit was rejected. Terminal. Funds are typically returned to the sender, though the exact outcome is compliance-dependent.

Key data fields

The channel webhook data object is flatter than the Payment Link payload — amounts and currencies are separate top-level fields rather than nested objects.

FieldDescription
uuidThe channel payment's unique identifier. Constant across both webhooks for the same deposit.
channelIdThe UUID of the channel that received the deposit.
referenceThe channel's reference — your internal label.
statusDETECTED on the first webhook, COMPLETE on the second.
hashThe on-chain transaction hash. Use it to verify the deposit on a block explorer.
addressThe channel deposit address the customer paid to.
paidCurrency / paidAmountThe asset and amount the customer actually sent on-chain.
displayCurrency / displayAmountThe asset and amount in the channel's Display Currency.
walletCurrency / walletAmountThe asset and amount credited to the linked wallet.
feeCurrency / feeAmountBEEM's processing fee for the deposit.
networkFeeThe network fee object — paidCurrency, paidAmount, displayCurrency, displayAmount.
riskThe compliance screening result — level, resourceName, resourceCategory, and any alerts.
sourcesThe array of sender addresses the funds came from.
exchangeRate / displayRateThe conversion rates applied — each an object of base, counter, rate.
📘

Amounts are zero on transaction-detected

On the first webhook the amount fields are 0 — the transaction has been seen but not yet confirmed, so the final figures are not settled. The transaction-confirmed webhook carries the actual paidAmount, displayAmount, walletAmount, and the conversion rates.

Webhook sequences

The events you receive depend on the outcome of compliance screening. Three primary paths:

Cleared deposit (the happy path):

  1. transaction-detected — the deposit appears on-chain. status is DETECTED.
  2. transaction-screening-requested — the deposit is submitted to compliance screening.
  3. transaction-confirmed — the deposit reaches the required confirmations and funds are credited. status is COMPLETE.

Held deposit (cleared after resolution):

  1. transaction-detected
  2. transaction-screening-requested
  3. transaction-held — the deposit is flagged. The hold may be driven by KYT (Chainalysis) screening or a Travel Rule RFI. Call GET /platform/v1/travel-rule-rfis to determine which, then resolve via the appropriate path. See Building a Travel Rule Integration.
  4. Once the hold clears, transaction-confirmed — funds credited.

Rejected deposit (terminal):

  1. transaction-detected
  2. transaction-screening-requested
  3. transaction-held (in most cases — depends on the screening rule)
  4. transaction-rejected — terminal. Funds are typically returned to the sender, though the exact outcome is compliance-dependent.

There is no expiry, underpayment, or "late" concept for channels — a channel address simply accepts whatever is sent, whenever it is sent.

Example payloads

{
  "event": "layer1:payment:channel:transaction-detected",
  "source": "channel",
  "data": {
    "channelId": "326bf4e4-866e-4ec5-80e8-5233b7d29af5",
    "merchantId": "a7eddadd-fd9b-45fb-82a1-dc12eaa14cba",
    "merchantDisplayName": "ETH Merchant",
    "reference": "Channel Test",
    "dateCreated": 1709556819750,
    "lastUpdated": 1709556819750,
    "status": "DETECTED",
    "uuid": "2d04095f-29b0-4434-89af-573759f8f248",
    "hash": "0x8ad672efcb337fb5a2025149e5e6f22e8af17f71b5270e904de28cee44de00e6",
    "address": "0xf210435eb347b9c79361b97fae333abf7cba1d9b",
    "tag": null,
    "paidCurrency": "ETH",
    "displayCurrency": "USD",
    "walletCurrency": "ETH",
    "feeCurrency": "ETH",
    "paidAmount": 0,
    "displayAmount": 0,
    "walletAmount": 0,
    "feeAmount": 0,
    "exchangeRate": null,
    "displayRate": null,
    "risk": {
      "level": "UNKNOWN",
      "resourceName": "UNKNOWN",
      "resourceCategory": "UNKNOWN",
      "alerts": []
    },
    "sources": null,
    "networkFee": {
      "paidCurrency": null,
      "paidAmount": 0,
      "displayCurrency": null,
      "displayAmount": 0
    }
  }
}
{
  "event": "layer1:payment:channel:transaction-confirmed",
  "source": "channel",
  "data": {
    "channelId": "326bf4e4-866e-4ec5-80e8-5233b7d29af5",
    "merchantId": "a7eddadd-fd9b-45fb-82a1-dc12eaa14cba",
    "merchantDisplayName": "ETH Merchant",
    "reference": "Channel Test",
    "dateCreated": 1709556820000,
    "lastUpdated": 1709556909163,
    "status": "COMPLETE",
    "uuid": "2d04095f-29b0-4434-89af-573759f8f248",
    "hash": "0x8ad672efcb337fb5a2025149e5e6f22e8af17f71b5270e904de28cee44de00e6",
    "address": "0xf210435eb347b9c79361b97fae333abf7cba1d9b",
    "tag": null,
    "paidCurrency": "ETH",
    "displayCurrency": "USD",
    "walletCurrency": "ETH",
    "feeCurrency": "ETH",
    "paidAmount": 0.01234,
    "displayAmount": 43.28,
    "walletAmount": 0.01234,
    "feeAmount": 0.0001234,
    "exchangeRate": {
      "base": "ETH",
      "counter": "ETH",
      "rate": 1
    },
    "displayRate": {
      "base": "ETH",
      "counter": "USD",
      "rate": 3507.29
    },
    "risk": {
      "level": "UNKNOWN",
      "resourceName": "UNKNOWN",
      "resourceCategory": "UNKNOWN",
      "alerts": []
    },
    "sources": [
      "0x84a4a239805d06c685219801b82bea7c76702214"
    ],
    "networkFee": {
      "paidCurrency": "ETH",
      "paidAmount": 0.000033576139821,
      "displayCurrency": "USD",
      "displayAmount": 0.11
    }
  }
}

What's next