Send to agents · 02

Signed webhooks.

Let another system start a job without an Access Key. Stripe, Shopify, or your own service signs each request with a secret, and Olbrain checks the signature instead of a key.

POST /api/agents/webhook/{agent_id}/signed

When to use this

Signed webhooks start jobs only. The job must have a signed sender connected: Stripe, Shopify, or a shared secret. Set it up when you build the job with Alchemist; its hand-over shows the exact URL and steps.

Stripe and Shopify

Add the URL above as a webhook endpoint in Stripe or Shopify, with the signing secret connected to the job. Olbrain checks Stripe-Signature (Stripe's t= and v1= scheme, 5-minute tolerance) or X-Shopify-Hmac-SHA256. Use Send test webhook in Stripe, or Send test notification in Shopify, to try it — it starts a real, billed run.

Your own service

Sign {timestamp}.{raw body} with HMAC-SHA256 and the shared secret, and send the hex digest:

HeaderValue
X-Olbrain-TimestampUnix time in seconds. Must be within 5 minutes of Olbrain's clock.
X-Olbrain-SignatureHex HMAC-SHA256 of the timestamp, a dot, and the exact body bytes.
Content-Typeapplication/json
Signed requestshell
BODY='{"order_id":"4421"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$OLBRAIN_WEBHOOK_SECRET" | sed 's/^.*= //')
curl -X POST https://webhook.olbrain.com/api/agents/webhook/agt_01HAKZ.../signed \
  -H "Content-Type: application/json" \
  -H "X-Olbrain-Timestamp: $TS" \
  -H "X-Olbrain-Signature: $SIG" \
  -d "$BODY"

Sign the bytes you send, not a re-serialised copy. The body must be a JSON object up to 1 MiB, shaped like a job trigger. Keep the secret on your server.

Each delivery runs once

Olbrain remembers each signed delivery for 24 hours. Sending the same signed request again returns {"status": "duplicate"} and starts nothing. A delivery that fails is forgotten, so the sender's retry runs it. Expect a rare duplicate if a run started but its response never reached the sender.

Errors

StatusWhen
401 invalid_signatureMissing or wrong signature, a timestamp outside 5 minutes, or the agent has no signed sender. All look the same on purpose.
400 invalid_bodyThe body isn't a JSON object.
409 delivery_in_progressThe same delivery is still running. Retry shortly.
413 body_too_largeThe body is over 1 MiB.
503secret_unavailable, delivery_store_unavailable, or signed_senders_disabled. Retry with backoff.

After admission, the same checks as any trigger apply — billing, the job's daily run limit, and publishing. See Errors.