Payment Webhooks

Payment webhooks let your backend receive real-time callbacks whenever a payment’s status changes. Instead of polling the Status endpoint, you can react immediately when a transaction is completed, underpaid, expired, or any other terminal state.

Why use webhooks?

Benefit
Detail

Real-time

Instant status updates—no polling loops

Lower complexity

Fewer API calls, simpler state machine

Automation-ready

Trigger order fulfilment, accounting entries, customer comms, etc. as soon as events occur

Two ways to receive events

Method
Scope
When to choose

Terminal webhook (configured once)

All payments created by the terminal

Normal production flow

webhookUrls array (sent in POST /payments/crypto)

The single payment being created

A/B testing, dual systems, or tenant-specific routing

Fan-out delivery When you include webhookUrls, Bead sends every event to all of these destinations:

  1. The terminal’s default webhook and

  2. Each URL in the webhookUrls array. No change is required on the terminal if you just want extras.

1 – Configure the terminal webhook

PUT /Terminals/{terminalId}/webhook
Host: api.beadpay.io
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "webhookUrl": "https://yourserver.com/webhooks/payment-notifications"
}

Successful response

{
  "terminalId": "{terminalId}",
  "webhookUrl": "https://yourserver.com/webhooks/payment-notifications",
  "updated": "2025-07-09T14:21:00Z"
}

2 – (Optional) Add per-payment endpoints

Include the webhookUrls array when you create the hosted-payment URL:

{
  "...": "... other create-payment fields ...",
  "webhookUrls": [
    "https://hooks.yourapp.dev/store-42",
    "https://hooks.yourapp.dev/analytics"
  ]
}

Receiving a webhook

Bead POSTs a JSON body to each registered URL whenever statusCode changes.

{
  "trackingId":   "4f181348293946cfa39b5846078c9bbc",
  "paymentCode":  "bAKbqtcuP5",
  "statusCode":   "completed",
  "amounts": {
    "requested": {
      "inPaymentCurrency":   { "amount": 1.02, "currency": { "code": "USDC", "name": "USDC Ethereum" } },
      "inRequestedCurrency": { "amount": 1.00, "currency": { "code": "USD",  "name": "USD"          } }
    },
    "paid": {
      "inPaymentCurrency":   { "amount": 1.02, "currency": { "code": "USDC", "name": "USDC Ethereum" } }
    }
  },
  "reference":    "ORDER123",
  "description":  "Transaction description",
  "receivedTime": "2025-07-09T14:22:18Z",
  "terminalId":   "{terminalId}",
  "merchantId":   "{merchantId}"
}

NotestatusCode is now the enum word (e.g. "completed") rather than a numeric value.

Status values

Status
Meaning

created

Payment record created; awaiting funds

underpaid

Funds received < requested

overpaid

Funds received > requested

completed

Full amount confirmed (or overpaid auto-accepted)

expired

Payment window elapsed, no settlement

invalid

On-chain tx can’t be matched

cancelled

Shopper cancelled checkout

For underpaid, overpaid, expired, invalid, or cancelled outcomes, Bead prompts the shopper for an email (if not already supplied) and emails instructions for any reclaimable funds.

Securing your webhook endpoint

  1. Signature – inspect the x-webhook-signature header (HMAC-SHA256).

  2. Auth header – enforce a pre-shared bearer or basic token.

  3. IP-allowlist – optionally restrict to Bead’s published subnet list.

  4. HTTPS – plain HTTP is rejected by the API.

Best-practice handler flow

  1. Verify origin (signature / auth / IP).

  2. Validate payload (trackingId, statusCode, required sub-objects).

  3. Apply business logic (update DB, fulfil order, issue refund).

  4. Acknowledge quickly with HTTP 200. Any non-2xx triggers automatic retries with exponential back-off for 24 h.

Testing in sandbox

  • Base URL https://api.test.devs.beadpay.io

  • Point sandbox terminals at your dev webhook endpoint.

  • Generate test payments and force each status to ensure downstream code handles every callback.

Next steps

  • Combine webhooks with occasional polling (/payments/tracking/{trackingId}) for redundancy.

  • Questions? Email [email protected].

Last updated