Webhook events

Real-time notifications for deposits, withdrawals, and checkout.

Cheddar delivers webhooks via Svix. Each delivery is HMAC-signed — verify the signature before trusting the payload.

Configure your endpoint URL and view your signing secret in the dashboard — see Webhooks.

Signature verification

Use the Svix libraries (or verify the svix-signature header manually) with your endpoint’s signing secret:

import { Webhook } from "svix";
const wh = new Webhook(SIGNING_SECRET);
const payload = wh.verify(rawBody, {
"svix-id": req.headers["svix-id"],
"svix-timestamp": req.headers["svix-timestamp"],
"svix-signature": req.headers["svix-signature"],
});

Event catalog

Customer payments

EventWhen
CUSTOMER_DEPOSITA customer deposit is confirmed on-chain.
CUSTOMER_DEPOSIT_APPROVEDA flagged deposit was approved and credited.
CUSTOMER_DEPOSIT_REJECTEDA flagged deposit was returned to the sending address.
CUSTOMER_DEPOSIT_REDIRECTEDA flagged deposit was sent to a different address.
CUSTOMER_WITHDRAWA customer withdrawal is broadcast.
CUSTOMER_WITHDRAW_AWAITING_APPROVALA withdrawal needs manual approval (threshold / low liquidity).
CUSTOMER_FAILED_TO_WITHDRAWA withdrawal failed.

CUSTOMER_DEPOSIT payload:

{
"eventType": "CUSTOMER_DEPOSIT",
"id": "",
"mint": { "id": 1, "symbol": "USDC", "chain": "ETHEREUM" },
"amount": "1000000",
"uiAmount": "1.00",
"usdAmount": "1.00",
"txHash": "0x…",
"createdAt": "2026-01-01T00:00:00.000Z",
"customerId": "your-customer-id",
"scannerUrl": "https://etherscan.io/tx/0x…",
"riskOfFunds": "VERY_LOW_RISK",
"isFlagged": false
}

Flagged deposit resolution

A deposit that trips your organization’s risk thresholds arrives as CUSTOMER_DEPOSIT with isFlagged: true and is held — Cheddar does not credit it to the customer’s balance. It stays held until someone resolves it, and the resolution emits exactly one of three terminal events.

These are the events to act on if you credited a player from the original CUSTOMER_DEPOSIT. A rejected or redirected deposit means the funds are gone — reverse the credit on your side.

EventOutcomeEmitted
CUSTOMER_DEPOSIT_APPROVEDFunds are credited and swept as normal.At the moment of the decision — nothing moves on-chain.
CUSTOMER_DEPOSIT_REJECTEDFunds are returned to the address they came from.After the return transaction confirms on-chain.
CUSTOMER_DEPOSIT_REDIRECTEDFunds are sent to a different address, chosen by Cheddar operations.After the transfer confirms on-chain.

Reject and redirect are only emitted once the chain confirms, so expect a delay between the operator’s decision and the event. If the transfer never confirms, no terminal event is sent and the deposit stays unresolved.

CUSTOMER_DEPOSIT_REJECTED and CUSTOMER_DEPOSIT_REDIRECTED payload:

{
"eventType": "CUSTOMER_DEPOSIT_REJECTED",
"id": 12345,
"mint": { "id": 1, "symbol": "USDC", "chain": "ETHEREUM" },
"amount": "1000000",
"uiAmount": "1.00",
"usdAmount": "1.00",
"createdAt": "2026-01-01T00:00:00.000Z",
"customerId": "your-customer-id",
"flagReason": {
"score": 12,
"severity": "HIGH_RISK",
"entityType": "MIXER",
"entityName": "Example Mixer"
},
"destinationAddress": "0x…",
"txHash": "0x…"
}

CUSTOMER_DEPOSIT_APPROVED carries the same fields without destinationAddress and txHash — approving moves no funds, so there is no transfer to reference.

flagReason reports why the deposit was held, from an analysis of the sending wallet. Every field is nullable: a deposit flagged before this data was recorded, or one where the provider returned no entity, will have nulls. id is the deposit id, matching the id on the original CUSTOMER_DEPOSIT.

Checkout lifecycle

Checkout events use an envelope: { id, type, created_at, data }. The type is one of checkout.session.created, checkout.payment.detected, checkout.payment.confirming, checkout.payment.partial, checkout.payment.completed, checkout.payment.overpaid, checkout.wrong_token_received, checkout.expired, checkout.session.expired, checkout.refund.*, checkout.flagged.*, checkout.canceled, and checkout.risk_scan_pending.

Operational

EventWhen
gas_wallet.low_balanceA gas wallet dropped below its configured threshold.

Idempotency

Event IDs are deterministic per source (e.g. evt_deposit_{id}). De-duplicate on the event ID — you may receive the same event more than once.

Each flagged-deposit resolution uses its own ID — evt_deposit_approved_{id}, evt_deposit_rejected_{id}, evt_deposit_redirected_{id} — distinct from the evt_deposit_{id} of the original deposit, so a resolution never de-duplicates against it.