Webhooks
Use webhooks to receive Infuse platform events in your own systems. A webhook endpoint belongs to an organisation and can subscribe to one or more event types.
Webhooks are configured from Admin Center > Webhooks.
When to Use Webhooks
Use webhooks when your backend needs to react to Infuse activity without polling APIs.
Common examples:
- update an internal entitlement or licensing system after a marketplace purchase,
- notify an operations workflow when a purchase state changes,
- mirror Infuse events into your own audit or analytics pipeline.
Webhooks are platform-level integrations. Infuse-Marketplace is currently the first event source, but webhook endpoints are managed at the organisation level.
Available Events
The initial Infuse-Marketplace event types are:
| Event type | Description |
|---|---|
marketplace.purchase.completed | A marketplace purchase was completed and activated. |
marketplace.purchase.refunded | A marketplace purchase was refunded. |
marketplace.purchase.revoked | A marketplace purchase was revoked. |
Only marketplace.purchase.completed is emitted today.
Create an Endpoint
- Open Admin Center > Webhooks.
- Select Create endpoint.
- Enter your receiver URL.
- Optionally add a description.
- Leave the endpoint enabled, unless you want to create it without receiving events yet.
- Select at least one event type.
- Save the endpoint.
- Copy the signing secret immediately and store it in your backend secret manager.
The signing secret is only shown once after creation. It cannot be retrieved again later.
Endpoint URL Requirements
Production webhook endpoints must use HTTPS.
Your endpoint should:
- accept
POSTrequests, - read a JSON request body,
- return a
2xxstatus quickly after accepting the event, - verify the Infuse signature before processing the event,
- be idempotent, because a delivery can be retried or replayed.
If your processing is slow, acknowledge the webhook first and queue the work internally.
Request Headers
Infuse sends these headers with each webhook delivery:
| Header | Description |
|---|---|
Infuse-Webhook-Id | Unique webhook event ID. |
Infuse-Webhook-Event-Type | Event type, such as marketplace.purchase.completed. |
Infuse-Webhook-Timestamp | Unix timestamp in seconds used in the signature payload. |
Infuse-Webhook-Signature | Lowercase hex HMAC-SHA256 signature. |
Use Infuse-Webhook-Id as an idempotency key when recording processed events.
Verify Signatures
Each endpoint has a signing secret that starts with whsec_. Store the raw secret securely.
To verify a delivery:
- Read the raw request body exactly as received.
- Read
Infuse-Webhook-Timestamp. - Read
Infuse-Webhook-Signature. - Hash the raw
whsec_...secret with SHA-256 and hex-encode it. - Build the signed payload as
{timestamp}.{rawBody}. - Compute
HMACSHA256(secretHash, signedPayload). - Compare the computed lowercase hex signature with
Infuse-Webhook-Signatureusing a constant-time comparison.
Example in Node.js:
import crypto from 'node:crypto';
export function verifyInfuseWebhook({
rawBody,
timestamp,
signature,
signingSecret,
}: {
rawBody: string;
timestamp: string;
signature: string;
signingSecret: string;
}) {
const secretHash = crypto
.createHash('sha256')
.update(signingSecret, 'utf8')
.digest('hex');
const expected = crypto
.createHmac('sha256', secretHash)
.update(`${timestamp}.${rawBody}`, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected, 'utf8'),
Buffer.from(signature.toLowerCase(), 'utf8'),
);
}
Do not parse and re-stringify the JSON before verifying. Use the raw request body.
Example Payload
marketplace.purchase.completed sends purchase, buyer, device, payment, and marketplace item information.
{
"id": "5051eeeb-acf1-4793-80cf-5559b97cd976",
"purchaseId": "5051eeeb-acf1-4793-80cf-5559b97cd976",
"subject": "marketplace_purchase/local-test-20260603040716",
"status": "active",
"livemode": false,
"buyer": {
"organisationId": "22222222-2222-2222-2222-222222222222",
"userId": "0560272b-98b7-49e7-821c-0eba9f0a4b8b",
"email": "user@example.com"
},
"device": {
"id": "device-001",
"serialNumber": "DEVICE-001"
},
"marketplace": {
"name": "Example Infuse-Marketplace Item",
"itemId": "fad3247d-edc1-4cf8-952d-d4c12406d7d5",
"listingId": "40c5016c-390b-4b3a-b1e2-a881788d5014",
"offeringId": "30162bd0-7683-444c-8208-cf8eee8729b5"
},
"payment": {
"currency": "USD",
"provider": "stripe",
"totalAmountPaid": 12.34,
"providerListingMarkup": 1.23,
"providerPaymentReference": "payment-reference",
"providerCustomerReference": "customer-reference"
},
"occurredAtUtc": "2026-06-03T04:07:16.711787+00:00",
"activatedAtUtc": "2026-06-03T04:07:16.711787+00:00"
}
Treat payload fields as event data for your integration. Use Infuse APIs as the source of truth if you need to fetch the latest purchase or device state.
Edit an Endpoint
From Admin Center > Webhooks > Endpoints, you can:
- update the endpoint URL or description,
- enable or disable deliveries,
- change subscribed events,
- rotate the signing secret,
- delete the endpoint.
Rotating the signing secret shows the new secret once. Update your receiver before or immediately after rotating so deliveries continue to verify.
Disabling an endpoint stops new deliveries to that endpoint. It does not delete delivery history.
Delivery History
Open the Deliveries tab to review webhook delivery attempts.
The table shows:
- event type,
- subject,
- endpoint URL,
- delivery status,
- attempt count,
- last attempt time,
- next retry time,
- response code.
Delivery statuses are:
| Status | Meaning |
|---|---|
Pending | The delivery is queued or waiting for its next attempt. |
Succeeded | The endpoint returned a 2xx response. |
Failed | The last attempt failed and another retry may be scheduled. |
Exhausted | Infuse will not retry automatically. |
Failed and exhausted deliveries can be replayed from the delivery table.
Retry Behavior
Infuse treats 2xx responses as successful.
The following failures are retryable:
- timeout or network failure,
408,409,429,5xx.
Non-retryable responses, such as 400, are marked failed without normal automatic retry.
Your receiver should return:
2xxonly after it has accepted the event,4xxwhen the request should not be retried,5xxwhen the problem is temporary and Infuse should retry.
Security Recommendations
- Keep signing secrets in a server-side secret manager.
- Never expose signing secrets in browser code.
- Verify every delivery before processing it.
- Use a constant-time comparison for signatures.
- Record processed
Infuse-Webhook-Idvalues to avoid duplicate processing. - Rotate signing secrets if they are exposed or no longer trusted.
- Restrict webhook receiver logs so secrets and sensitive payloads are not leaked.