End-to-end integrations
Integrate webhooks with signature checks
A copy-paste prompt that builds a Lumx webhook endpoint correctly — raw body, HMAC over the signed content, secret rotation, replay and retries.
// PROMPT
{ "type": "INDIVIDUAL", "name": "William Default", "taxId": "100.100.100-01", "birthDate": "1990-01-01" }
You are a senior backend engineer building the Lumx webhook receiver for an existing service.
Ground truth. Read both before writing any code and follow them over any prior knowledge:
1. https://docs.lumx.io/developer/webhooks — the signature scheme, the event catalog and the retry schedule. Also read https://docs.lumx.io/llms.txt for the rest of the documentation.
2. https://lumx-docs-public-prod.s3.us-east-1.amazonaws.com/api-production.yaml — the OpenAPI 3.1 spec, for the resource shapes that arrive inside the event payload.
1. Capture the raw request body before any JSON middleware parses it. Signature verification runs over bytes; a re-serialized body fails and the failure looks like a wrong secret.
2. Read the three headers: webhook-id, webhook-timestamp, webhook-signature.
3. Build the signed content as "{webhook-id}.{webhook-timestamp}.{body}", compute HMAC-SHA256 with the signing secret, and base64-encode the result. The secret arrives prefixed with whsec_ — strip the prefix and base64-decode the remainder before using it as the key.
4. Accept any valid signature in the header, not the first one. The header holds a space-delimited list of version-prefixed signatures, and during a secret rotation Lumx signs with the old and the new secret for 24 hours. Compare in constant time.
5. Reject anything older than your replay window using webhook-timestamp, and deduplicate on webhook-id — Lumx delivers up to eight times with increasing backoff, so the same event will arrive twice.
6. Return 2xx immediately, then process asynchronously. Route by eventType over the documented families: onramp.*, offramp.*, transfer.*, customer.*, customer.limit_request.*, account.* and destinations.*.
7. Treat the payload as a notification, not as state. Before you credit, release or settle anything, confirm with GET /transactions/{id} or GET /customers/{id}.
Constraints:
- Do not trust an event whose signature did not verify, including in sandbox.
- Do not enumerate event types from memory. Take the list from the docs page and flag any type your code receives that is not on it.
- The envelope is eventId, eventType and data. Anything else you need is inside data and its shape follows the resource.
- Do not state a rate limit for the confirmation calls. None is published. Handle 429 TOO_MANY_REQUESTS with exponential backoff.
Deliverables:
- A verification function with unit tests covering a good signature, a tampered body, an expired timestamp and a rotation header with two signatures.
- An idempotent dispatcher keyed on webhook-id.
- A replay script that posts a stored event to the local endpoint so the handler can be tested without waiting for a transaction.
Register the endpoint in the Dashboard under Developers → Webhooks and copy the signing secret into your own secret store before running the agent.
If your infrastructure filters inbound IPs, take the published list from the webhooks page and add it yourself.
Run the rotation test after the agent finishes: rotate the secret in the Dashboard and confirm nothing drops during the 24-hour overlap.
Discover how our infrastructure can seamlessly integrate stablecoins into your financial operations quickly, securely, and efficiently.

