Skip to main content

Handle Deliveries

This document describes how webhook events are delivered, acknowledged, retried, and how consumers should process and order them.

Overview​

Webhook events are delivered using an at-least-once delivery model.

This means:

Each event is guaranteed to be delivered one or more times. Duplicate deliveries are possible and expected.

Webhook consumers must implement idempotent processing.

Delivery Model​

  • Delivery guarantee: At least once
  • Duplicates: Possible
  • Ordering: Not guaranteed at delivery time

Delivery Method​

  • Protocol: HTTPS only
  • HTTP Method: POST
  • Content-Type: application/json
  • Encoding: UTF-8

Delivery Headers​

Each delivery includes the following headers:

HeaderDescription
X-Agc-VersionWebhook payload version
X-Agc-Tenant-IdID of the tenant that triggered the event
X-Agc-Webhook-IdID of the configured webhook
X-Agc-Attempt-IdUnique identifier for this delivery attempt
X-Agc-Event-IdUnique event identifier (stable across retries, use for idempotency)
X-Agc-Event-TypeName of the event type (e.g. pid.completed)
X-Agc-TimestampISO-8601 timestamp indicating when this delivery attempt was sent
X-Agc-SignatureHMAC signature used to verify authenticity (only present if a secret is configured

Delivery Payload​

The webhook request body uses the following structure:

{
"version": "1.0",
"tenant_id": "tenant_abc",
"event_id": "evt_123456789",
"event_type": "pid.completed",
"event_timestamp": "2026-01-22T06:40:00.000Z",
"data": {}
}

Payload Field Semantics​

FieldDescription
versionWebhook payload version
tenant_idID of the tenant that triggered the event
event_idUnique event identifier (stable across retries)
event_typeEvent type name
event_timestampWhen the event occurred in the platform
dataEvent-specific payload

Success & Failure Criteria​

Successful Delivery​

Any HTTP response with a status code in the range:

200–399

is considered a successful delivery, and no further retries will be made.

Retryable Failures​

The following status codes will trigger retries:

  • 408 – Request Timeout
  • 429 – Too Many Requests
  • 500–599 – Server errors

Retries are also triggered for:

  • Network errors
  • TLS failures
  • DNS failures
  • Connection timeouts

Non-Retryable Failures​

The following status codes will NOT be retried:

  • 400 – Bad Request
  • 401 – Unauthorized
  • 403 – Forbidden
  • 404 – Not Found
  • 410 – Gone

When these responses are received, the delivery is considered final.


Retry Behavior​

Retry Strategy​

  • Retries use exponential backoff
  • Retries continue for up to 24 hours
  • Retry intervals are not guaranteed and may vary

Retry Characteristics​

  • event_id remains constant across all retries
  • attempt_id is unique for every delivery attempt
  • The same payload is resent for each retry

Idempotency (Required)​

Due to at-least-once delivery semantics, webhook consumers must implement idempotent processing.

Idempotency Key​

Use:

event_id
if event_id already processed:
return success
else:
process event
store event_id

Failing to implement idempotency may result in duplicate side effects.


Timeout Expectations​

Webhook endpoints should:

  • Respond within a few seconds
  • Avoid long-running synchronous processing
  • Offload heavy work to background jobs or queues

Slow responses increase retry likelihood.


Security Considerations​

  • Use HTTPS
  • Validate HMAC signatures when present
  • Validate timestamps (X-Agc-Timestamp) to prevent replay attacks
  • Reject malformed payloads

See Validating Deliveries for details.


Logging & Observability​

Strongly recommended logging fields:

  • event_id
  • event_type
  • attempt_id
  • event_timestamp
  • X-Agc-Timestamp
  • HTTP response codes
  • Signature verification failures