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": {}
}| Field | Description |
|---|---|
source | The product source. For a channel payment, this is always channel. |
event | The event type — what happened. See below. |
data | The 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.
| Event | When it fires |
|---|---|
layer1:payment:channel:transaction-detected | A 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-requested | The 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-held | The 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-confirmed | The deposit reached the required confirmations and funds have been credited to the linked wallet. The payment status is COMPLETE. |
layer1:payment:channel:transaction-rejected | The 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.
| Field | Description |
|---|---|
uuid | The channel payment's unique identifier. Constant across both webhooks for the same deposit. |
channelId | The UUID of the channel that received the deposit. |
reference | The channel's reference — your internal label. |
status | DETECTED on the first webhook, COMPLETE on the second. |
hash | The on-chain transaction hash. Use it to verify the deposit on a block explorer. |
address | The channel deposit address the customer paid to. |
paidCurrency / paidAmount | The asset and amount the customer actually sent on-chain. |
displayCurrency / displayAmount | The asset and amount in the channel's Display Currency. |
walletCurrency / walletAmount | The asset and amount credited to the linked wallet. |
feeCurrency / feeAmount | BEEM's processing fee for the deposit. |
networkFee | The network fee object — paidCurrency, paidAmount, displayCurrency, displayAmount. |
risk | The compliance screening result — level, resourceName, resourceCategory, and any alerts. |
sources | The array of sender addresses the funds came from. |
exchangeRate / displayRate | The conversion rates applied — each an object of base, counter, rate. |
Amounts are zero ontransaction-detectedOn the first webhook the amount fields are
0— the transaction has been seen but not yet confirmed, so the final figures are not settled. Thetransaction-confirmedwebhook carries the actualpaidAmount,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):
transaction-detected— the deposit appears on-chain.statusisDETECTED.transaction-screening-requested— the deposit is submitted to compliance screening.transaction-confirmed— the deposit reaches the required confirmations and funds are credited.statusisCOMPLETE.
Held deposit (cleared after resolution):
transaction-detectedtransaction-screening-requestedtransaction-held— the deposit is flagged. The hold may be driven by KYT (Chainalysis) screening or a Travel Rule RFI. CallGET /platform/v1/travel-rule-rfisto determine which, then resolve via the appropriate path. See Building a Travel Rule Integration.- Once the hold clears,
transaction-confirmed— funds credited.
Rejected deposit (terminal):
transaction-detectedtransaction-screening-requestedtransaction-held(in most cases — depends on the screening rule)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
}
}
}
