Skip to documentation
Beacon Docs
Agent API and webhooks

Publication webhooks

Receive signed publication lifecycle events and process delivery retries safely.

Open Markdown

Beacon webhooks send publication lifecycle changes to your HTTPS endpoint.

Create an endpoint in Settings > Developer > Webhooks. Select only the events that your application needs. Beacon shows the signing secret one time. Store it in a secret manager.

Supported events

EventDestination statusMeaning
post.scheduledscheduledBeacon scheduled or safely requeued the destination.
post.publishedpublishedBeacon confirmed publication.
post.partialpartially_publishedBeacon published at least one part, but work remains.
post.failedfailedBeacon has a safe failed result.
post.delayeddelayedBeacon delayed a safe retry.
post.reconnect_requiredreconnect_requiredThe channel owner must reconnect the provider.
post.recovery_requiredcheckingBeacon cannot prove the provider result. Do not retry the post.
post.cancelledcancelledBeacon cancelled the destination before dispatch.
post.expiredexpiredBeacon stopped unfinished work after its allowed time.

The event name post.recovery_required maps to the customer status checking.

Event body

Beacon sends one JSON envelope for one post destination.

{
  "createdAt": "2026-08-28T10:00:00.000Z",
  "data": {
    "destination": {
      "channelId": "c40a49a6-2f5b-4b03-8ca8-ddf3972d38b8",
      "provider": "linkedin",
      "publishAt": "2026-08-28T10:00:00.000Z",
      "releaseUrl": "https://www.linkedin.com/feed/update/example",
      "status": "published"
    },
    "post": {
      "postId": "8420cf47-6086-43f9-b37b-c6b26ef81a2d"
    }
  },
  "id": "647ef738-7bfc-467a-a7a5-3738f36f6dad",
  "type": "post.published"
}

A delayed event can include checkAgainAt. A failed or blocked event can include a safe error with code, message, provider, and retryable.

Beacon does not include internal target IDs, publication-unit IDs, provider external IDs, provider request IDs, raw provider responses, or credentials.

Verify the signature

Verify the exact raw request body before you parse JSON. Do not reformat or reserialize the body first.

Beacon sends these headers:

X-Beacon-Event-Id
X-Beacon-Event-Type
X-Beacon-Timestamp
X-Beacon-Signature: t=UNIX_SECONDS,v1=HEX_HMAC

Beacon calculates HMAC-SHA256 over this text:

<timestamp>.<rawBody>

The TypeScript SDK verifies the signature and rejects old timestamps:

import {
  verifyBeaconWebhookSignature,
  type BeaconWebhookEvent,
} from "@beacon/sdk";

const rawBody = await request.text();
const verified = await verifyBeaconWebhookSignature({
  rawBody,
  secret: process.env.BEACON_WEBHOOK_SECRET!,
  signatureHeader: request.headers.get("x-beacon-signature"),
});

if (!verified) {
  return new Response("Invalid signature", { status: 401 });
}

const event = JSON.parse(rawBody) as BeaconWebhookEvent;

The default timestamp tolerance is five minutes. Keep the server clock accurate. Compare signatures in constant time. Never log the secret, signature, or full body.

Acknowledge an event

Return an HTTP status from 200 through 299 after you store or process the event. Keep the handler fast. Move long work to your own queue.

Beacon does not follow redirects. Use a stable credential-free HTTPS address.

Retry behavior

Beacon keeps the same event ID and exact body across automatic delivery attempts. It creates a new timestamp and signature for each attempt.

Beacon retries network errors, 408, 425, 429, and 500 through 599. Other 400 responses fail permanently.

Beacon makes at most five automatic attempts. The nominal waits after attempts are 1, 2, 4, and 8 seconds, plus worker scheduling time. Beacon honors Retry-After for a retryable response and limits that wait to 60 seconds.

Ordering and duplicate handling

Beacon does not guarantee global event order. Separate workers or endpoints can observe events in different orders.

Store the event id with a unique constraint. If you receive the same ID again, return a successful response and do not repeat your side effect.

Use createdAt to understand when Beacon recorded the change. When event order affects a decision, read the current post through GET /agent/v1/posts/{postId} before you act.