Webhooks

Receive signed Signals events at an organisation-owned public HTTPS endpoint.

Store the secret once
The signing secret is displayed only when the destination is created or rotated. Keep it in a server-side secret store and never log it.

Event types

Event typeWhen it is sent
signals.monitor.deliveryWhen a configured monitor has new paid resources to deliver.
integration.testWhen an owner or admin sends a test delivery.

Envelope

Every body is canonical JSON using schema version 1.

FieldTypeRequired
schema_version1Yes
event_idUUIDv7Yes
delivery_idUUIDv7Yes
event_typeevent typeYes
occurred_atRFC 3339 timestampYes
dataevent payloadYes

Delivery headers

HeaderPurpose
X-Luranta-Delivery-IdUnique delivery attempt identity. Use it when investigating delivery state.
X-Luranta-Event-IdStable event identity. Use it as the primary idempotency key.
X-Luranta-Event-TypeThe event discriminator for routing and payload handling.
X-Luranta-SignatureThe v0 HMAC-SHA256 signature.
X-Luranta-TimestampUnix time in seconds included in the signed input.

Verify before processing

Read the request body as raw bytes. Reject timestamps more than 5 minutes from your clock. Compute HMAC-SHA256 over v0.<timestamp>.<raw_body> using the destination secret, encode it as lowercase hexadecimal, prefix it with v0=, then compare in constant time.

Only parse or enqueue the body after verification succeeds. Deduplicate business processing by event_id; retain delivery_id for per-attempt diagnostics.

Receive and verify

body='{"data":{"action_url":"https://luranta.com/signals/monitors","resource_ids":[],"schema_version":1,"summary":"A monitored hiring signal changed.","title":"Hiring signal update"},"delivery_id":"019c0000-0000-7000-8000-000000000201","event_id":"019c0000-0000-7000-8000-000000000202","event_type":"integration.test","occurred_at":"2026-08-02T12:00:00.000Z","schema_version":1}'
timestamp=$(date +%s)
signature=$(printf '%s' "v0.$timestamp.$body" \
  | openssl dgst -sha256 -hmac "$LURANTA_WEBHOOK_SECRET" -hex \
  | awk '{print $NF}')

curl --request POST "http://localhost:8787/luranta-webhook" \
  --header "Content-Type: application/json" \
  --header "X-Luranta-Event-Id: 019c0000-0000-7000-8000-000000000202" \
  --header "X-Luranta-Delivery-Id: 019c0000-0000-7000-8000-000000000201" \
  --header "X-Luranta-Event-Type: integration.test" \
  --header "X-Luranta-Timestamp: $timestamp" \
  --header "X-Luranta-Signature: v0=$signature" \
  --data-binary "$body"

Acknowledgement and retries

Receiver resultLuranta behaviour
Any 2xxMarks that destination delivery as complete.
408, 409, 425, 429 or 5xxRetries with bounded backoff, up to 12 attempts.
Other non-2xxTreats the delivery as terminal.
Repeated terminal deliveriesPauses the destination after 5 consecutive failures.
RedirectDoes not follow it; the delivery fails.

Endpoint requirements

  • Use a public HTTPS hostname on port 443.
  • Do not use credentials in the URL.
  • Luranta rejects loopback, private, link-local, metadata and non-public DNS answers before every attempt.
  • The maximum body size is 64 KiB and the request timeout is 10 seconds.
  • Return a 2xx as soon as the verified event is durably queued; process it asynchronously.

Rotate or troubleshoot

Create a new secret from Signals → Destinations, update your receiver, then send a test event before resuming production delivery. Delivery receipts show the destination, event, attempt count and terminal failure code without exposing the secret or payload. A paused destination must be explicitly resumed after the cause is fixed.