Skip to content
Last updated

Webhooks

Apiera webhooks deliver real-time HTTP notifications when events occur in your organization. Instead of polling for changes, your application receives a POST request for each event, enabling responsive integrations that react to changes as they happen.

Design philosophy

Apiera uses a granular, signal-based webhook architecture. Every operation across the API surface fires a corresponding event. Not just top-level resource changes, but sub-resource operations too (e.g. product.attribute.linked, product.input_value.updated).

Granular events let integrators know what kind of change occurred, not just that something changed. A coarse product.updated event forces consumers to either fetch-and-diff or maintain complex routing logic. Granular events allow selective subscriptions and clear intent.

Thin payloads contain only navigational properties: the UUIDs needed to construct the exact REST API call to fetch current state. Delta payloads (before/after values) are deliberately avoided. While the infrastructure can provide near-ordered delivery in many cases, delta payloads require guaranteed ordering to be safe. Out-of-order delivery of before/after values can corrupt consumer state. Consumers always fetch current state from the API, which is architecturally sound regardless of delivery order.

How it works

  1. Subscribe - Create a webhook subscription with a target URL and select which event types to receive.
  2. Receive - When an event occurs, Apiera sends an HTTP POST to your endpoint with a signed JSON payload.
  3. Verify - Validate the HMAC-SHA256 signature to confirm the request is authentic.
  4. Fetch - Use the UUIDs in the payload to call the corresponding REST endpoint for current state.

Setting up a subscription

1. Create a subscription

curl -X POST https://api.apiera.io/v1/webhook-subscriptions \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "My Integration",
    "targetUrl": "https://example.com/webhooks"
  }'

The response includes a secret field (format: whsec_<base64>). Store this secret securely. It is only returned on creation and when explicitly rotated. You need it to verify incoming webhook signatures.

{
  "uuid": "a1b2c3d4-...",
  "status": "active",
  "displayName": "My Integration",
  "targetUrl": "https://example.com/webhooks",
  "requestTimeoutMs": 10000,
  "secret": "whsec_dGhpcyBpcyBhIHNlY3JldA==",
  "createdAt": "2026-03-10T12:00:00Z",
  "updatedAt": "2026-03-10T12:00:00Z"
}

2. Subscribe to event types

List available event types, then subscribe to the ones you need:

# List all available event types
curl https://api.apiera.io/v1/webhook-event-types \
  -H "Authorization: Bearer {token}"

# Subscribe to an event type
curl -X POST https://api.apiera.io/v1/webhook-subscriptions/{subscriptionUuid}/event-types \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookEventTypeUuid": "event-type-uuid-here"
  }'

You only receive events for event types you have explicitly subscribed to.

3. Manage your subscription

ActionMethodEndpoint
List subscriptionsGET/v1/webhook-subscriptions
Get subscriptionGET/v1/webhook-subscriptions/{uuid}
Update subscriptionPATCH/v1/webhook-subscriptions/{uuid}
Delete subscriptionDELETE/v1/webhook-subscriptions/{uuid}
Activate / DeactivatePATCH/v1/webhook-subscriptions/{uuid}/actions/lifecycle
Rotate secretPATCH/v1/webhook-subscriptions/{uuid}/actions/rotate-secret
List subscribed event typesGET/v1/webhook-subscriptions/{uuid}/event-types
Subscribe to event typePOST/v1/webhook-subscriptions/{uuid}/event-types
Unsubscribe from event typeDELETE/v1/webhook-subscriptions/{uuid}/event-types/{eventTypeUuid}

Subscription lifecycle

Subscriptions have three states:

StatusDescription
activeReceives and delivers events normally.
inactivePaused. No events are created or delivered.
suspendedTemporarily disabled by the system (e.g. persistent delivery failures).

Transition between states using the lifecycle endpoint:

curl -X PATCH https://api.apiera.io/v1/webhook-subscriptions/{uuid}/actions/lifecycle \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{ "transition": "deactivate" }'

Security

Signature verification

Every webhook delivery is signed with your subscription's HMAC secret. Always verify the signature before processing the payload.

Each request includes three headers:

HeaderDescription
webhook-idUnique delivery identifier (UUID).
webhook-timestampUnix timestamp (seconds) when the webhook was sent.
webhook-signatureHMAC-SHA256 signature in the format v1,<base64>.

The signature is computed over the string:

{webhook-id}.{webhook-timestamp}.{payload}

Where {payload} is the raw JSON request body.

Verification steps:

  1. Extract the webhook-id, webhook-timestamp, and webhook-signature headers.
  2. Construct the signed content: {webhook-id}.{webhook-timestamp}.{payload}.
  3. Compute HMAC-SHA256 using your secret (Base64-decode the secret after removing the whsec_ prefix).
  4. Compare the computed signature with the webhook-signature header value.
  5. Optionally, reject requests where the timestamp is older than 5 minutes to prevent replay attacks.

See Examples for complete verification code in multiple languages.

Rotating secrets

If your secret is compromised, rotate it immediately:

curl -X PATCH https://api.apiera.io/v1/webhook-subscriptions/{uuid}/actions/rotate-secret \
  -H "Authorization: Bearer {token}"

The response contains the new secret. Update your verification code before the next delivery.

Delivery headers

Every webhook POST request includes these headers:

HeaderDescription
Content-TypeAlways application/json; charset=utf-8.
webhook-idUnique delivery UUID.
webhook-timestampUnix timestamp (seconds).
webhook-signatureHMAC-SHA256 signature (v1,<base64>).
X-Webhook-Event-TypeThe event type string (e.g. product.created).
Deprecation(Optional) RFC 7234 date if the event type is deprecated.
Sunset(Optional) RFC 7234 date when the event type will be removed.

Payload structure

All payloads are thin. They contain only the UUIDs needed to fetch current state via the REST API.

{
  "productUuid": "550e8400-e29b-41d4-a716-446655440000"
}

The payload structure varies by event type but always maps directly to REST API path parameters. See Events for details on event types and their payloads.

Monitoring deliveries

Track delivery status and debug failures using the delivery endpoints:

# List deliveries for a subscription
curl https://api.apiera.io/v1/webhook-subscriptions/{uuid}/deliveries \
  -H "Authorization: Bearer {token}"

# Get a specific delivery
curl https://api.apiera.io/v1/webhook-subscriptions/{uuid}/deliveries/{deliveryUuid} \
  -H "Authorization: Bearer {token}"

# List delivery attempts
curl https://api.apiera.io/v1/webhook-subscriptions/{uuid}/deliveries/{deliveryUuid}/attempts \
  -H "Authorization: Bearer {token}"

Each delivery tracks:

FieldDescription
statuspending, delivered, or failed.
attemptsNumber of delivery attempts made.
lastStatusCodeHTTP status code from the most recent attempt.
scheduledAtWhen the next retry is scheduled (if pending).

Each attempt records the HTTP status code, response body (truncated to 2048 characters), and response time in milliseconds.