Skip to content
Documentation

Dispatch API

Publish an event once; HookSift fans it out to every subscribed endpoint with per-subscription ordering, endpoint-level exactly-once, and configurable retries.

The Dispatch API is available to design partners. Keys are provisioned after onboarding. Apply for a tenant →

Introduction

All requests go to the edge base URL below. Every request is authenticated and signed. Unauthenticated requests to the root return 403 Forbidden from hooksift-edge — this is expected; the API never serves an open root.

base url
https://events.hooksift.com

The API is versioned in the path (/v1 is implied by the current edge; unversioned routes resolve to v1). All request and response bodies are JSON.

Authentication

Authenticate with a per-tenant bearer key in the Authorization header. Keys are scoped to a single tenant and are issued during design-partner onboarding.

header
Authorization: Bearer hs_live_m8r2k4_5a1f…
No key? Keys are provisioned to design partners. Apply →

The dispatch endpoint

Publish an event to a tenant channel. HookSift resolves every subscription on that channel and fans the event out.

POST /dispatch/tenant/{tenant_id}/channel/{channel}

Request headers

HeaderRequiredDescription
AuthorizationYesBearer key for the tenant.
Hooksift-Idempotency-KeyRecommendedCollapses redeliveries of the same logical event. See Idempotency.
Content-TypeYesapplication/json

Example request

dispatch.sh
curl -X POST https://events.hooksift.com/dispatch/tenant/m8r2k4/channel/orders \
  -H "Authorization: Bearer $HOOKSIFT_KEY" \
  -H "Hooksift-Idempotency-Key: evt_9Fh2kQ" \
  -H "Content-Type: application/json" \
  -d '{
        "type": "orders.paid",
        "data": { "order_id": "o_5521", "amount": 4900, "currency": "usd" }
      }'

Request body

FieldTypeDescription
typestringEvent type, e.g. orders.paid. Subscriptions filter on this.
dataobjectArbitrary JSON payload delivered verbatim to endpoints.
dedupe_keystring?Optional explicit dedupe key; overrides the idempotency header.
order_keystring?Optional ordering key. Events sharing a key deliver in publish order per endpoint. Defaults to the channel.

Response · 202 Accepted

{
  "dispatch_id": "dsp_7yQ2fD",
  "channel": "orders",
  "endpoints": 4,
  "status": "queued"
}

A 202 means the event was accepted and queued for fan-out — not that every endpoint has received it. Track per-endpoint outcomes in the delivery log.

Idempotency

Send Hooksift-Idempotency-Key on every publish. Two requests with the same key inside the dedupe window collapse to a single logical event, so a client retry after a network blip never fans out twice. The default window is 24 hours.

Deduplication also applies at the endpoint: if a delivery is retried, the receiver sees the same Hooksift-Event-Id and can safely no-op. Exactly-once at the endpoint is the combination of sender-side dedup and this stable event id.

Retry policies

Each subscription carries its own retry policy. Set it when you create the endpoint, or update it later. Endpoints that exhaust their attempts are moved to the dead-letter queue and stop receiving new deliveries until re-enabled.

policy.json
{
  "max_attempts": 8,
  "backoff": "exponential",
  "base_ms": 500,
  "timeout_ms": 5000,
  "dead_letter": true
}
BackoffDelay between attempts
exponentialbase_ms · 2^(n-1), capped at 1 h, ±10% jitter
linearbase_ms · n
constantbase_ms every attempt

Delivery log & replay

Every attempt is recorded: endpoint, attempt number, status, latency, and the response code. Query the log to debug failures, then replay a single delivery or a time range — without republishing from your source.

GET /dispatch/tenant/{tenant_id}/deliveries?status=failed
{
  "deliveries": [
    {
      "id": "dlv_3kP…",
      "endpoint": "https://hooks.dev-app.com/ep",
      "attempt": 2,
      "status": "retrying",
      "response_code": 503,
      "latency_ms": 4812
    }
  ]
}
POST /dispatch/tenant/{tenant_id}/deliveries/{id}/replay

Log retention depends on plan: 7 days (Signal), 30 days (Fan-out), 90 days (Dispatch).

Verifying signatures

Every delivery includes a Hooksift-Signature header. Recompute the HMAC over t + "." + body with your endpoint secret and compare in constant time. Reject deliveries whose timestamp is more than 5 minutes old to defeat replays.

verify.py
# header: Hooksift-Signature: t=1720051200,v1=4f9a…
import hmac, hashlib, time

def verify(secret, header, body):
    parts = dict(p.split("=") for p in header.split(","))
    ts, sig = parts["t"], parts["v1"]
    if abs(time.time() - int(ts)) > 300: return False  # stale
    mac = hmac.new(secret, f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, sig)

Response codes

CodeMeaning
202Accepted — event queued for fan-out.
401Missing or invalid bearer key.
403Unauthenticated root, or tenant disabled. The API root always returns 403.
409Idempotency conflict — key reused with a different body.
422Malformed payload (missing type, invalid JSON).
429Rate limited — back off per the Retry-After header.
503Edge draining — retry with backoff; publishes are never dropped.
Ready to integrate?

Tenant keys are provisioned to design partners after onboarding.

Apply for a tenant →