Skip to main content

Webhooks

After a payment or payout status changes, Cobrex sends an HTTP request to the URL configured for the merchant or the callback provided when the operation was created.

Request body​

OperationBody
PaymentJSON payment object (see model).
PayoutJSON payout object (see model).

Confirm HTTP method and headers with the latest spec; use the checks below for security.

Your server response​

When the webhook is accepted and processed (or safely queued internally so processing is guaranteed), your endpoint must return HTTP 200. Cobrex treats this as successful delivery.

Any other outcome (5xx, 4xx, timeouts, connection drops) is treated as failure — retries follow the schedule below.

Retries after failure​

On unsuccessful delivery, Cobrex schedules another attempt with increasing delay:

  • The attempt counter increments while it stays below 9.
  • At 9 or more attempts in this cycle, no further retries are scheduled (next_attempt_at is cleared).
  • The delay until the next attempt depends on the current attempts value when the next run is scheduled.

Delay until the next attempt:

attempts when schedulingDelay until next delivery
110 seconds
230 seconds
31 minute
45 minutes
515 minutes
61 hour
74 hours
816 hours
Other handled values (implementation fallback)15 minutes

You may therefore receive up to nine unsuccessful rounds before retries stop under this scheme; confirm production behaviour with Cobrex support if retry policy changes.

Check 1 — IP address​

Allow only trusted IPs. At documentation time:

46.166.162.83

Lists can change after infra moves — confirm the production list with support.

Check 2 — x-signature header​

  1. Keep the raw body as string/buffer before JSON.parse.
  2. HMAC-SHA256 with your secret (same as API, or a dedicated webhook secret — confirm with Cobrex).

Expected pattern (integration panel):

signature_hex = HMAC-SHA256( key = api_secret, message = JSON.stringify(data) ).toString('hex')

where data is the parsed object. In practice, verifying HMAC over the raw body string is often more stable:

const crypto = require('crypto');

function verifyWebhookSignature(rawBodyString, receivedHex, apiSecret) {
const expected = crypto.createHmac('sha256', apiSecret).update(rawBodyString).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(receivedHex, 'hex'));
}

Confirm with Cobrex whether production matches JSON.stringify(data) exactly or raw bytes — use the confirmed variant.

Recommendations​

  • Return HTTP 200 quickly after validation and enqueueing; run heavy work asynchronously.
  • Make handlers idempotent by payment_id / payout_id.
  • Log headers and bodies in debug (never log secrets).

See also: Authentication & signing.