On this page
One system. Composable layers.

Hosted webhooks deliver journey, payment, approval, and program events to your HTTPS receiver. Events and pending deliveries are persisted before transmission. Each endpoint has its own Ed25519 signing key, and retries preserve the event identifier and exact body bytes so your application can safely recognize repeats.

Register an endpoint

Use an active developer session with Authorization: Bearer, or the __Host-layerx-session cookie. Cookie-authenticated POST and DELETE requests also carry x-layerx-csrf matching the session CSRF token. Registration requires an Idempotency-Key.

POST /v1/webhooks/endpoints
Authorization: Bearer <developer-session>
Idempotency-Key: <stable-registration-key>
Content-Type: application/json

{
  "url": "https://merchant.example.com/events/paxeer",
  "kinds": ["payment", "approval"],
  "minimum_verification": "unverified"
}

The URL uses a canonical DNS name and resolves exclusively to public addresses. Literal IP destinations are refused. Each developer principal can register up to 32 endpoints. Registration returns the endpoint identifier, signing key identifier, public key, and receiver obligation. Preserve the returned key in your receiver's trusted key configuration.

Event families and evidence

KindResource and factsEvidence
journeyJourney identity, kind, state, updated time.Source facts with optional activity receipt binding.
paymentActivity identity, amount, asset, settled state.Successful verified receipt for settlement; source amount and asset retain their own evidence labels.
approvalApproval identity, agent, state, creation time.Source facts with optional activity receipt binding.
programProgram identity, lifecycle, version, code hash, receipt digest.Source facts with optional activity receipt binding.

Webhook verification levels are unverified, receipt-verified, checkpoint-finalised, and paxeer-finalised. Each fact retains its own level; the event header uses the weakest fact. A payment event can therefore have an unverified header while its settled-state fact carries receipt evidence. A minimum-verification filter applies to that aggregate header. Inspect and verify the facts your decision uses.

Verify the raw delivery

layerx-webhook-id: <event-id>
layerx-webhook-timestamp: <unix-seconds>
layerx-webhook-key-id: <endpoint-key-id>
layerx-webhook-signature: v1=<padded-base64-ed25519-signature>

signed_message = UTF8(event_id + "." + timestamp + ".") || raw_body
  1. Validate bounded identifiers and canonical integer timestamp syntax.
  2. Reject signatures older than the accepted age or too far in the future. Defaults are 300 seconds of age and 30 seconds of future skew.
  3. Verify Ed25519 against the trusted public key named by the key identifier, over the exact incoming body bytes.
  4. Claim the event identifier and payload digest in a durable replay store before applying business effects.
  5. For economic effects, resolve and verify the referenced receipt and compare its digest to the event evidence.

Read the body as raw bytes before JSON parsing. Re-serializing parsed JSON changes the signed message. Operational headers for delivery, attempt, kind, subject, sequence, and endpoint are outside the signature; use authenticated body fields for business decisions. GET /v1/webhooks/scheme publishes the receiver contract.

Commit once, accept repeats

Delivery is at least once. Store the event identifier with its payload digest and business outcome in the same transactional database as your application effects. A completed repeat returns success without repeating fulfilment; an in-progress claim waits or retries; the same identifier with a different digest is a conflict. Release an unsuccessful processing lease so a legitimate retry can proceed.

The framework integrations provide verified webhook consumers and replay-store interfaces. An in-memory single-process store is useful for local execution; a durable shared store preserves deduplication across workers and restarts.

Ordering, retries, and dead letters

Events are ordered per subject, rather than globally across every resource. Publish rejects a non-advancing subject sequence. Delivery progresses through pending, in-flight, retrying, delivered, and dead-lettered. Only an accepting 2xx status from your endpoint marks a delivery delivered.

Default controlValue
Maximum attempts8
Initial retry delay10 seconds
Maximum retry delay3,600 seconds
Deterministic backoff spread20%
In-flight lease120 seconds
Automatic suspension20 consecutive dead letters

Backoff doubles up to its bound. Redirects are refused; HTTP 410 is a permanent failure. A permanent failure or exhausted attempts creates a dead letter. A suspended endpoint receives no dispatch until resumed. A lost worker's in-flight lease permits recovery without losing the persisted event.

Manage delivery and replay

Method and pathPurpose
GET /v1/webhooks/endpointsList endpoint registrations.
GET /v1/webhooks/endpoints/{id}/eventsRead endpoint event history and continuation cursor.
GET /v1/webhooks/endpoints/{id}/keysRead current and overlapping verification keys.
POST /v1/webhooks/endpoints/{id}/keysRotate the signing key with an idempotency key.
POST /v1/webhooks/endpoints/{id}/redeliveriesEnqueue replay from a signed cursor with an idempotency key.
POST /v1/webhooks/endpoints/{id}/suspensionsSuspend an endpoint with a reason.
POST /v1/webhooks/endpoints/{id}/resumptionsResume delivery and clear consecutive dead-letter accounting.
GET /v1/webhooks/events, /deliveries, /dead-lettersInspect events and operational outcomes.
POST /v1/webhooks/dead-letters/{id}/replayRetry a dead letter with an idempotency key.

Pagination defaults to 50 items with a maximum of 200. Preserve cursors as opaque signed values. Expired retention returns 410 cursor_expired; repair continuity using retained event and receipt history rather than silently assuming all events were delivered. Replay keeps the original event identifier and body digest.

Rotate keys and monitor receivers

Key rotation announces a pending public key before activation; the default overlap is 86,400 seconds. Configure the new public key during the overlap while retaining the old key for eligible deliveries. Signing private keys stay with the signing service.

Monitor delivery latency, retry age, dead letters, suspension, and receiver signature failures. Return 2xx after durable acceptance. For long processing jobs, commit an inbox record and process it asynchronously. Use agent subscriptions for tenant-scoped streams with explicit acknowledgement and gap recovery.

Reference: platform/hosted/webhooks/src/main.rs, hosted.rs, scheme.rs, events.rs, endpoints.rs; platform/docs/content/guide/webhooks.md; docs/site/docs/platform/webhooks.md.
Paxeer X · System documentationBack to top ↑

Ask Paxeer X Docs

Answers from the documentation.

What would you like to know?

Ask a question, find a guide, or get help with your next step.

Enter to send · Shift+Enter for a new line