Skip to main content

Webhooks

Webhooks let your backend update orders when an on-chain payment changes state. Manatee sends the same signed event envelope for BTC, BCH, and XMR to the webhook_url provided at payment creation.

Event types​

Event typeMeaningTypical action
payment.detectedA matching transaction was seen, but confirmations are below the required threshold.Show "payment seen" or "waiting for confirmations".
payment.confirmedThe transaction reached required_confirmations.Mark the order as paid or ready for fulfillment.
payment.expiredA still-pending payment reached expires_at without a qualifying transaction.Stop accepting payment instructions and let the customer create a new payment.

Treat payment.detected as an early signal. Use payment.confirmed as the fulfillment trigger for most production flows.

Payload example​

{
"version": "1",
"type": "payment.confirmed",
"data": {
"payment_id": "pay_abc123",
"txid": "a1b2c3d4...",
"asset": "bch",
"network": "testnet",
"address": "bchtest:qr95sy3j9xwd2ap32xkykttr4cvcu7as4ytjg7p7mc",
"amount_sats": 10000,
"received_sats": 10000,
"amount_atomic": "10000",
"received_atomic": "10000",
"atomic_unit": "satoshi",
"confirmations": 1,
"required_confirmations": 1,
"webhook_url": "https://yourapp.example/webhooks/bch"
}
}
Data fieldMeaning
payment_idManatee payment ID stored next to your order ID
assetbtc, bch, or xmr
networkmainnet, testnet, stagenet, or regtest (depending on the asset)
txidMatching on-chain transaction ID; empty for an unpaid payment.expired event
addressCanonical address for the asset and network; BCH uses prefixed CashAddr
amount_satsExpected amount in the asset's satoshis
received_satsMatching native-asset amount observed so far
amount_atomic / received_atomicExact decimal-string amounts in the unit named by atomic_unit; present for every asset
atomic_unitsatoshi for BTC/BCH or piconero for XMR
confirmationsConfirmation count at event creation
required_confirmationsConfirmation threshold configured for the payment
webhook_urlDelivery URL stored with the payment

Store the payment ID returned during payment creation next to your own order ID. The webhook intentionally does not include your reference; use the stored mapping or retrieve the payment when that field is needed.

For XMR, use the decimal strings exactly as received: 1000000000000 piconero is 1.000000000000 XMR. XMR events use the same timestamped HMAC headers and verification procedure as BTC/BCH. The XMR Stagenet quickstart includes an end-to-end synthetic webhook check before a real Stagenet payment.

Required headers​

HeaderPurpose
X-Manatee-Event-IdUnique event delivery ID for replay protection and idempotency.
X-Manatee-Event-TypeEvent type, such as payment.detected, payment.confirmed, or payment.expired.
X-Manatee-TimestampUnix timestamp in seconds used in signature verification.
X-Manatee-SignatureHMAC-SHA256 signature over timestamp + "." + raw request body.

Always verify X-Manatee-Signature before updating an order, and reject timestamps outside your allowed clock-skew window. See Security for implementation details.

For backwards compatibility, Manatee currently also sends the legacy X-Event-ID, X-Event-Type, and X-Signature headers. New integrations should use the X-Manatee-* headers.

Send a test webhook​

Before creating a payment, you can send a synthetic payment.confirmed event to your webhook endpoint:

curl -X POST "$MANATEE_API_URL/v1/webhooks/test" \
-H "Authorization: Bearer $MANATEE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://yourapp.example/webhooks/bch",
"asset": "bch"
}'

This checks endpoint reachability, payload parsing, signature handling, and response behavior without sending an on-chain transaction. Use btc, bch, or xmr; omitting asset keeps the backwards-compatible BTC default. The payload network is inherited from the authenticated API key. The request does not create a payment and is not stored in payment history.

Webhook failed​

If webhook delivery fails:

  • Confirm the URL is publicly reachable by server-to-server HTTP requests.
  • Return a 2xx response only after your app accepts the event.
  • Bypass browser challenges, captchas, or login redirects only for the webhook route.
  • Verify the raw request body, not parsed JSON, when checking signatures.
  • Store X-Manatee-Event-Id values so repeated delivery is safe.

For retry behavior and more details, see Webhook Delivery in a Crypto Payment API.