Webhooks
How stores send orders to Preset Bridge and how Preset Bridge sends delivery results back.
Webhook endpoint
All store webhooks are sent to a single endpoint pattern:
POST /api/webhooks/<provider>/<integrationId>
Where:
<provider>is one of:shopify,woocommerce, orgeneric<integrationId>is the unique ID of your store integration
Signature verification
Preset Bridge verifies the authenticity of incoming webhooks using HMAC signatures. The signature header differs by provider:
| Provider | Signature header | Algorithm |
|---|---|---|
| Shopify | X-Shopify-Hmac-Sha256 |
HMAC-SHA256 (Base64) |
| WooCommerce | X-WC-Webhook-Signature |
HMAC-SHA256 (Base64) |
| Generic | X-Webhook-Signature or X-NDSP-Signature |
HMAC-SHA256 (Hex, prefixed with sha256=) |
Shopify payload
Shopify sends the full order object. Preset Bridge extracts line items and the customer's NDSP username from the order note or note attributes.
{
"id": 5678901234,
"order_number": 1042,
"email": "customer@example.com",
"note": "NDSP username: cortex_user_42",
"note_attributes": [
{ "name": "ndsp_username", "value": "cortex_user_42" }
],
"line_items": [
{
"sku": "STORM-LEAD-V2",
"product_id": 7891234567890,
"variant_id": 43210987654321,
"title": "Storm Drive Lead Preset",
"quantity": 1
}
]
}
note_attributes for a field named ndsp_username, cortex_username, or neural_dsp_username. If not found, it falls back to parsing the note field.
WooCommerce payload
WooCommerce sends the full order object. Preset Bridge extracts line items and looks for the NDSP username in order meta fields.
{
"id": 1234,
"order_key": "wc_order_abc123",
"billing": {
"email": "customer@example.com"
},
"meta_data": [
{ "key": "ndsp_username", "value": "cortex_user_42" }
],
"line_items": [
{
"sku": "STORM-LEAD-V2",
"product_id": 567,
"variation_id": 890,
"name": "Storm Drive Lead Preset",
"quantity": 1
}
]
}
Generic payload
The generic provider accepts a simplified JSON structure. Use this when integrating a custom store or platform.
{
"orderId": "order-1234",
"customerEmail": "fan@music.com",
"targetUsername": "cortex_user_42",
"items": [
{
"sku": "STORM-LEAD-V2",
"productId": "prod_123",
"title": "Storm Drive Lead Preset",
"quantity": 1
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
orderId |
string | Yes | Unique order identifier (used for deduplication) |
customerEmail |
string | No | Customer's email for reference |
targetUsername |
string | Yes | Customer's Cortex Cloud username |
items |
array | Yes | List of purchased items to match against item mappings |
items[].sku |
string | No* | Product SKU |
items[].productId |
string | No* | Product ID |
items[].title |
string | No* | Product title |
items[].quantity |
number | No | Quantity purchased (default: 1) |
* At least one identifier (sku, productId, or title) must be present to match an item mapping.
Webhook responses
Preset Bridge responds to webhooks synchronously:
| Status | Meaning |
|---|---|
202 |
Webhook accepted and delivery queued |
400 |
Invalid payload or missing required fields |
401 |
Invalid or missing webhook signature |
404 |
Integration not found |
500 |
Internal processing error |
Delivery result webhooks
Outbound webhook subscriptions send delivery state changes from Preset Bridge to your store or another HTTPS endpoint. Create them under Integrations → Outbound webhooks.
Each request includes these headers:
| Header | Value |
|---|---|
Content-Type |
application/json |
X-NDSP-Event |
The delivery event name, such as delivery.completed |
X-NDSP-Signature |
sha256=<hmac-hex>, calculated over the exact request body |
{
"id": "f5ee5dc4-76fd-4d41-8ad7-19e132e9f5aa",
"type": "delivery.completed",
"createdAt": "2026-08-11T02:20:00.000Z",
"integrationId": "store-integration-id",
"deliveryId": "delivery-record-id",
"delivery": {
"orderId": "511",
"eventId": "wc-511-stable-event-id",
"status": "completed",
"message": "Preset shared successfully"
}
}
Subscriptions can be limited to one or more integration IDs. Use that restriction when one account operates several stores.
delivery.invalidated stops store-side completion and includes the merchant’s reason. delivery.reopened returns the order to review without starting another attempt.
Delivery result retries
Preset Bridge retries connection failures, timeouts, HTTP 408, HTTP 429 and HTTP 5xx responses after 1 minute, 5 minutes, 15 minutes, 1 hour, 6 hours and 24 hours. Other HTTP 4xx responses are permanent because they normally require a URL, secret or receiver change.
Open the subscription under Outbound webhooks to see its recent response codes and attempt status.
Retry behaviour
Deliveries that fail due to transient errors or wait for Cortex Cloud friendship are automatically retried. The delivery queue processes up to 5 jobs per minute.
You can also manually retry a failed delivery from the Integrations page in your dashboard. For deliveries that failed due to a missing or incorrect username, update the customer's NDSP username before retrying.