Admin Center

Webhooks

Send organisation-level Infuse events to your own HTTPS endpoint.

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 typeDescription
marketplace.purchase.completedA marketplace purchase was completed and activated.
marketplace.purchase.refundedA marketplace purchase was refunded.
marketplace.purchase.revokedA marketplace purchase was revoked.

Only marketplace.purchase.completed is emitted today.

Create an Endpoint

  1. Open Admin Center > Webhooks.
  2. Select Create endpoint.
  3. Enter your receiver URL.
  4. Optionally add a description.
  5. Leave the endpoint enabled, unless you want to create it without receiving events yet.
  6. Select at least one event type.
  7. Save the endpoint.
  8. 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 POST requests,
  • read a JSON request body,
  • return a 2xx status 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:

HeaderDescription
Infuse-Webhook-IdUnique webhook event ID.
Infuse-Webhook-Event-TypeEvent type, such as marketplace.purchase.completed.
Infuse-Webhook-TimestampUnix timestamp in seconds used in the signature payload.
Infuse-Webhook-SignatureLowercase 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:

  1. Read the raw request body exactly as received.
  2. Read Infuse-Webhook-Timestamp.
  3. Read Infuse-Webhook-Signature.
  4. Hash the raw whsec_... secret with SHA-256 and hex-encode it.
  5. Build the signed payload as {timestamp}.{rawBody}.
  6. Compute HMACSHA256(secretHash, signedPayload).
  7. Compare the computed lowercase hex signature with Infuse-Webhook-Signature using 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:

StatusMeaning
PendingThe delivery is queued or waiting for its next attempt.
SucceededThe endpoint returned a 2xx response.
FailedThe last attempt failed and another retry may be scheduled.
ExhaustedInfuse 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:

  • 2xx only after it has accepted the event,
  • 4xx when the request should not be retried,
  • 5xx when 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-Id values 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.