Payload envelope
Every webhook event shares the same outer envelope structure, regardless of event type:| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for this event delivery |
event_type | string | The event type name (see tables below) |
created_at | string (ISO 8601) | Timestamp when the event was generated |
data | object | Event-specific payload — fields vary by event_type |
All event types
| Domain | Event | When it fires |
|---|---|---|
| Account | account.kyc_approved | KYC review passed; account is now ACTIVE |
| Account | account.kyc_rejected | KYC review failed; account is now ACTION_REQUIRED |
| Account | account.closed | Account has been successfully closed |
| Funding | funding.ach_relationship_created | An ACH relationship has been created and approved |
| Funding | funding.ach_relationship_removed | An ACH relationship has been cancelled |
| Funding | funding.deposit_completed | An ACH deposit has fully settled |
| Funding | funding.deposit_returned | An ACH deposit was returned by the bank |
| Funding | funding.withdrawal_completed | An ACH withdrawal has fully settled |
| Funding | funding.withdrawal_returned | An ACH withdrawal was returned by the bank |
| Trading | order.submitted | An order was accepted and submitted to the market |
| Trading | order.filled | An order was fully executed |
| Trading | order.rejected | An order was rejected before or during execution |
| Trading | order.cancelled | An order was cancelled (user-initiated or system) |
Account events
account.kyc_approved
Fires when a new account completes KYC review and transitions to ACTIVE status. This is typically the signal your application should act on to enable trading and funding features for a user.
account.kyc_rejected
Fires when KYC review fails. The account transitions to ACTION_REQUIRED. Your application should prompt the user to provide additional documentation or contact support.
account.closed
Fires when an account closure completes. The account status transitions to CLOSED.
Funding events
funding.ach_relationship_created
Fires when a new ACH relationship is successfully created and passes verification, entering APPROVED status.
funding.ach_relationship_removed
Fires when an ACH relationship is cancelled via DELETE /v1/accounts/{accountId}/ach-relationships/{achId}.
funding.deposit_completed
Fires when an ACH deposit fully settles and funds are available in the account.
funding.deposit_returned
Fires when an ACH deposit is returned by the bank. The return_code identifies the reason.
funding.withdrawal_completed
Fires when an ACH withdrawal fully settles at the destination bank.
funding.withdrawal_returned
Fires when an ACH withdrawal is returned by the bank.
Trading events
order.submitted
Fires when an order has been accepted by Buildmarkets and submitted to the market. The order is now in pending_new or new status.
order.filled
Fires when an order is fully executed. Includes the average fill price and total filled quantity.
order.rejected
Fires when an order is rejected — either by Buildmarkets validation or by the downstream execution venue. The rejection_reason explains why.
order.cancelled
Fires when an order is cancelled — either by the user (DELETE /v1/accounts/{id}/orders/{orderId}) or by the system (e.g., day order not filled by market close).
Handling duplicate events
In rare cases (network issues, retries), your endpoint may receive the same event more than once. Use theid field on each event payload as an idempotency key — store processed event IDs and skip processing if the ID has already been handled.
Next steps
- Webhooks Overview → — Register and manage webhook endpoints
- Webhook Security & Delivery → — Verify signatures and understand retry behavior
Webhook Security & Delivery
Every webhook payload Buildmarkets sends is cryptographically signed. Verifying this signature before processing an event is critical — it ensures the payload genuinely came from Buildmarkets and has not been tampered with. This page explains how to verify signatures, what delivery guarantees Buildmarkets provides, how to inspect delivery history, and best practices for building a reliable webhook handler.Signature verification
When you register a webhook, Buildmarkets returns asecret that begins with whsec_. Buildmarkets uses this secret to compute an HMAC-SHA256 signature of the raw request body and attaches it to every delivery via the X-BMKT-Signature header.
Your endpoint must verify this signature before acting on any payload.
Verification steps
- Read the raw request body as bytes (do not parse JSON first)
- Read the
X-BMKT-Signatureheader - Compute
HMAC-SHA256(raw_body, secret) - Compare your computed signature to the value in the header
- If they match — process the event. If not — return
400and ignore the payload
Important: Always use a constant-time comparison function when comparing signatures to prevent timing attacks. Do not use simple string equality (===).
Example — Node.js (Express)
Example — Python (Flask)
Delivery mechanics
Endpoint requirements
Your webhook URL must:- Be publicly accessible via HTTPS (TLS 1.2 or higher)
- Return a
2xxHTTP status code within 10 seconds - Accept POST requests with
Content-Type: application/json
2xx response (including 3xx redirects) as a delivery failure and will retry.
Retry schedule
If your endpoint does not return a2xx within 10 seconds, Buildmarkets retries delivery with exponential backoff:
| Attempt | Delay after previous attempt |
|---|---|
| 1st retry | 5 minutes |
| 2nd retry | 30 minutes |
| 3rd retry | 2 hours |
| 4th retry | 5 hours |
| 5th retry | 10 hours |
Your endpoint should return2xxquickly, then process asynchronously. If your handler takes more than a few seconds, return200immediately and offload processing to a background queue. This prevents timeout-induced retries for events you have already received.
At-least-once delivery
Buildmarkets guarantees at-least-once delivery — every event will be delivered at least once, but rare network conditions can result in duplicate deliveries. Use theid field from the payload envelope as an idempotency key to detect and safely ignore duplicates.
Delivery history
The deliveries endpoint provides a log of every delivery attempt made for a specific webhook — including the HTTP status code your server returned, the response time, and whether the attempt succeeded.GET /v1/webhooks/{webhookId}/deliveries
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
webhookId | string (UUID) | ✅ | The webhook to retrieve delivery history for |
Response fields
Each delivery attempt object contains:| Field | Type | Description |
|---|---|---|
id | string | Unique delivery attempt ID |
event_id | string | ID of the event this delivery corresponds to |
event_type | string | The event type that was delivered |
status | string | succeeded or failed |
http_status | integer | null | HTTP status code returned by your endpoint |
response_time_ms | integer | null | Time in milliseconds for your endpoint to respond |
attempt_number | integer | Which delivery attempt this was (1 = first, 2 = first retry, etc.) |
attempted_at | string (ISO 8601) | Timestamp of the delivery attempt |
next_retry_at | string (ISO 8601) | null | When the next retry will be attempted; null if succeeded or max retries reached |
Example request
Example response
Disabling a webhook
If your endpoint is temporarily unavailable (e.g., during a deployment), you can pause delivery by setting the webhookstatus to disabled via PATCH /v1/webhooks/{webhookId}. Buildmarkets will not attempt delivery while the webhook is disabled.
Note: Buildmarkets does not queue events that occur while a webhook is disabled. Events that fire during a disabled window will not be retroactively delivered. Use the relevant Buildmarkets API endpoints to reconcile missed state changes if needed.
Security best practices
- Verify every signature before processing any payload — do not skip this step even in development
- Use
HTTPSonly — never register a webhook pointing to a plain HTTP URL - Store the secret securely — treat it like a password; use environment variables or a secrets manager, never hardcode it
- Return
2xxfast, process async — offload event handling to a queue to avoid timeout-induced retries - Implement idempotency — use the event
idto detect and discard duplicate deliveries - Monitor delivery history — set up alerts for sustained delivery failures so you can detect endpoint outages quickly
Next steps
- Webhooks Overview → — Register and manage webhook endpoints
- Webhook Events Reference → — Full payload schemas for every event type