Webhooks

Design a safe Cobru webhook handler and understand the current callback limitations.

Cobru sends a POST request to the callback URL you include when creating a payment. This is currently the main way to react to payment updates from your own backend.

Start here

  1. Treat the callback as a notification, not a source of truth.
  2. Persist the raw event immediately.
  3. Return HTTP 200 fast.
  4. Deduplicate by Cobru identifiers or your own payment reference.
  5. Reconcile before unlocking irreversible value.

Current trust model

Cobru webhooks are not signed today. There is no public HMAC header or JWT verification contract. Treat the webhook as a notification, not as definitive proof.

Typical payload

{
  "orderId": "123",
  "state": 3,
  "payment_method": "Bre-B",
  "amount": "50000.00",
  "url": "3gofdf6f"
}

Payment states

StateMeaningNotes
0Created / pendingpayment object exists
1Processinguser has started or Cobru is awaiting final confirmation
2Unpaid / rejectedoutcome depends on payment method
3Paid / approvedthe state most teams treat as successful settlement
4Refundedrefund applied
5Expiredappears in older Cobru materials; confirm before depending on it

What a safe webhook integration must do

Accept the callback, parse JSON, and persist the raw payload immediately.

Return HTTP 200 quickly so Cobru does not depend on your downstream processing time.

Deduplicate by orderId, url, or your own internal payment reference.

Reconcile the payment before shipping goods, unlocking value, or marking irreversible business success.

  1. Parse the payload.
  2. Persist the event immediately.
  3. Return HTTP 200 as fast as possible.
  4. Process reconciliation and side effects asynchronously.
  5. Protect downstream actions with idempotency on orderId or your own reference.
export async function POST(request: Request) {
  const payload = await request.json();

  await saveWebhookEvent(payload);

  return new Response('ok', { status: 200 });
}

Store at least:

  • raw payload
  • received timestamp
  • your internal order ID
  • Cobru url slug
  • Cobru orderId when present
  • processing result
  • replay count or deduplication marker

Hardening options available today

RiskWorkaround today
Anyone can hit your callback URLinclude your own secret in the callback query string
Duplicate deliveriesstore orderId and skip already-processed events
Callback spoofingre-check payment details with Cobru before shipping goods or unlocking value
Operational blind spotslog every callback and expose an internal replay tool

What not to do

  • do not mark an order as permanently successful before reconciliation
  • do not perform heavy downstream work before returning 200
  • do not trust source IP alone as your only security control
  • do not assume callbacks are delivered exactly once

Local testing

ngrok http 3000

Then use the public HTTPS URL as your Cobru callback value in sandbox.

ControlWhy it matters
callback URL secret or unguessable tokenreduces trivial spoofing risk
persistent event loglets you debug support incidents and replay failures
idempotent processorprotects against duplicates
reconciliation stepprevents false positives when callbacks are spoofed or incomplete
alerting on failed processingreduces silent payment-handling failures
  • /docs/testing
  • /docs/production-readiness
  • /docs/troubleshooting
  • /docs/api/cobrus/create

On this page