PaymentsHandling webhooks
Handling webhooks
How to register, verify, and process webhook deliveries from conomy_hq.
Webhooks are the platform’s primary mechanism to push state changes to your integration. Payment transaction updates are delivered as a signed POST to the URL you register for the environment.
For the catalog of events and payload shapes, see Webhooks API reference.
Register your endpoint
Section titled “Register your endpoint”Configure a webhook URL per environment with PUT /clients/webhook. The platform will POST every event to that URL.
PUT /clients/webhook HTTP/1.1Authorization: Bearer <access_token>x-api-key: <api_key>Content-Type: application/json
{ "webhookUrl": "https://yourapp.example/webhooks/conomy", "secretKey": "<shared-secret>"}Use GET /clients/webhook to read the registered URL. For split CVU handling, pass flavor: "cvu.static" when the client provides the fixed CVU and flavor: "cvu.dynamic" when Conomy creates the CVU.
When you register the endpoint, also configure a secretKey. Conomy uses it to sign every delivery with HMAC-SHA256, so your handler can verify the request came from Conomy and not from a third party.
Verify the signature
Section titled “Verify the signature”Every signed delivery includes an X-Webhook-Signature header. The signature is a 64-character hexadecimal HMAC-SHA256 digest of the raw request body, computed with your secretKey.
Pseudocode:
received = request.headers["X-Webhook-Signature"]rawBody = request.raw_bodyexpected = hmac_sha256(rawBody, secretKey).hex()if not constant_time_equals(expected, received): return 401Always compare in constant time. Always verify before trusting the transaction data.
Respond fast
Section titled “Respond fast”The platform expects a 2xx response within 10 seconds. Your handler should:
- Verify the
X-Webhook-Signatureheader. - Enqueue the payload for asynchronous processing.
- Return
2xx.
Heavy work — database writes, external API calls, settlement reconciliation — belongs on a worker behind a queue, not inline in the webhook handler.
Be idempotent
Section titled “Be idempotent”Webhook deliveries are at-least-once. The same (eventType, transaction.id) tuple may arrive twice — most often when your handler took too long on the first delivery and the platform retried.
Use that tuple as your idempotency key. Skip processing if you have already handled it.
key = eventType + ":" + transaction.idif already_processed(key): return 200mark_processing(key)process(payload)mark_processed(key)Retry behaviour
Section titled “Retry behaviour”When your endpoint returns a non-2xx response or times out, the platform retries with exponential backoff for up to 24 hours. After that, the event is dropped and surfaces in your delivery log.
Specifically:
- First retry after 30 seconds.
- Each subsequent retry doubles the delay, capped at 1 hour.
- After 24 hours total, the delivery is marked as failed.
If you discover a backlog of failed deliveries, fix the root cause first, then contact Conomy support to coordinate replay.
Forward compatibility
Section titled “Forward compatibility”Treat the webhook contract as additive:
- New
eventTypevalues may appear at any time. Unknown event types should be logged and ignored, never errored. - New fields may appear on existing payloads. Unknown fields should be ignored, never errored.
Local testing
Section titled “Local testing”In sandbox, call POST /simulate/payment to advance a payment from CREATED or AUTHORIZED through RECEIVED to SETTLED. Conomy fires the same signed events to your registered webhook URL, so you can validate signatures and idempotency end-to-end without a real provider. For handler code, see Validate webhook signatures.
Related
Section titled “Related”- Webhooks API reference — full event catalog.
- Going live — production readiness checklist.
- Errors — error response format and retry guidance.