Skip to main content

Webhook Payloads

What Are Webhooks

A webhook is how Nimbbl proactively tells your server about a status change — a payment succeeding, a refund completing, a payment link being opened — instead of you having to keep asking. As soon as something happens on the Nimbbl side, we send an HTTP POST with the event details to a URL you've configured, in real time.

Configuration

Webhooks are set up per sub-merchant. Event selection, URL requirements, and versioning are all configured with Nimbbl's help — webhook setup is not currently self-serve from Command Center:

  • Events — tell [email protected] which events (payment success, refund failed, payment link opened, and so on) should trigger a call to your URL. See Subscribing to Webhook Events below for where to find the full, current event list for each category.
  • URL requirements — the URL must be HTTPS, accept POST requests, be publicly reachable, and return a 200 response once you've validated the signature.
  • One URL per event type — a single URL can handle multiple event types, but each event type maps to only one URL at a time. Route different events to different URLs by configuring them separately.
  • Test vs. live — test-mode webhooks only fire for test transactions; live-mode webhooks only fire for live transactions. Confirm with Nimbbl whether your test and live traffic sit on one sub-merchant or two separate ones — the migration guide describes test and live as separate sub-merchants configured independently, and it matters for whether a test-mode webhook_version flip affects live traffic.
  • Payload version — v3 or v4, set per sub-merchant via the webhook_version field. v3 sends the full payload as-is; v4 encodes and signs the payload before sending it.

To get your webhook URL(s) configured or changed, send them to [email protected].

Deploy and Verify Before Requesting a Version Change

Moving webhook_version to v4 doesn't run both versions side by side — the flip is instant and total for that sub-merchant, and failed deliveries during an unprepared cutover expire after roughly 16 hours with no recovery. Deploy and verify your v4 parsing and signature logic, and prove it in test mode, before requesting the live flip. See Migrating Webhooks from v3 to v4 for the full sequence.

Delivery and Retries

Nimbbl delivers a webhook as an HTTP POST with a JSON body. Your endpoint must respond within 15 seconds; anything else — a non-2xx status, a timeout, or no response — is treated as a failed delivery and queued for retry.

If a delivery fails, Nimbbl retries up to 5 more times (6 attempts total, including the first), on this schedule:

AttemptTime since the previous attemptTime since the first attempt
1 (initial)0s
225 seconds25 seconds
310 minutes10 minutes 25 seconds
41 hour1 hour 10 minutes 25 seconds
56 hours7 hours 10 minutes 25 seconds
616 hours23 hours 10 minutes 25 seconds

After the sixth attempt fails, Nimbbl does not retry again — there is no manual replay today, so an endpoint that's down for the full ~23-hour window loses that event permanently.

Best Practice

Return HTTP 200 immediately after validating the signature. Process the webhook payload (database updates, fulfillment, notifications) after sending the response. This ensures Nimbbl receives your acknowledgement well within the 15-second window and avoids unnecessary retries.

Idempotency and Ordering

Build your handler assuming both of the following:

  • No ordering guarantee. Events can arrive out of the order they occurred in, including across retries. Don't assume a capture_success will always arrive after its payment_authorized, for example — check the current state of the underlying transaction rather than inferring it from delivery order.
  • No delivery-count guarantee. The same event can be delivered more than once (a retry can succeed on Nimbbl's side after your 200 was lost in transit, for instance). Dedupe on the event type plus the relevant transaction IDtransaction_id alone isn't sufficient to dedupe, since several event types can share it (see Pre-auth and Capture for a concrete case).

Signature Validation

Every webhook is signed. v1–v3 signs a concatenation of specific fields; v4 signs the entire compact JSON payload with a single HMAC-SHA256, using your access_secret — never trust a webhook body before validating it. See Validating Payment Response with Signature for the algorithm and code samples in Java, C#, PHP, and Python.

Encryption

If payload encryption is enabled for your sub-merchant, the webhook body is AES-256-GCM encrypted instead of (or alongside) being signed. See Using Encrypted Payloads for key derivation, the IV handling, and decryption code — encrypted delivery is not enabled by default, so contact [email protected] to turn it on.

Subscribing to Webhook Events

Which events exist, and their exact v3/v4 payload shapes, are documented on the three payload-reference pages below. Each page also covers how its events are wrapped and signed in v4.

Payment Webhooks covers the payment lifecycle — authorization, capture, and void. Refund Webhooks covers the three refund states. Payment Link Webhooks covers the payment-link lifecycle and the hold placed when a link is used for pre-authorization. If you're moving a sub-merchant from v3 to v4, see Migrating Webhooks from v3 to v4 for what changes and how to cut over safely.