Webhook Setup

Receive webhooks from CueAPI, handle payloads, and respond correctly.

Overview

When a cue fires with webhook transport, CueAPI sends a signed HTTP POST to your callback URL with the cue's payload.

What CueAPI sends

POST https://your-endpoint.com/webhook
Content-Type: application/json
X-CueAPI-Signature: v1=a1b2c3d4...
X-CueAPI-Timestamp: 1710340800
X-CueAPI-Cue-Id: cue_abc123def456
X-CueAPI-Execution-Id: 550e8400-e29b-41d4-a716-446655440000
X-CueAPI-Scheduled-For: 2026-03-13T09:00:00Z
X-CueAPI-Attempt: 1

The body is your cue's payload as JSON.

Headers

HeaderDescription
X-CueAPI-SignatureHMAC-SHA256 signature (v1={hex} format)
X-CueAPI-TimestampUnix timestamp of when the signature was created
X-CueAPI-Cue-IdThe cue ID that triggered this execution
X-CueAPI-Execution-IdUnique execution ID for this specific fire
X-CueAPI-Scheduled-ForThe scheduled time for this execution
X-CueAPI-AttemptAttempt number (1 = first attempt, 2+ = retries)

Responding correctly

Your endpoint must:

  1. Return 2xx (200, 201, 202, etc.) to indicate success
  2. Respond within 30 seconds — requests that take longer are treated as failures
  3. Be idempotent — CueAPI uses at-least-once delivery, so you may receive the same payload twice
python
# Flask example
@app.route("/webhook", methods=["POST"])
def handle_webhook():
    payload = request.json
    execution_id = request.headers.get("X-CueAPI-Execution-Id")
 
    # Check idempotency (recommended)
    if already_processed(execution_id):
        return {"status": "already processed"}, 200
 
    # Do the work
    process_task(payload)
 
    return {"status": "ok"}, 200

What triggers retries

CueAPI retries when:

  • Your endpoint returns 4xx or 5xx
  • Your endpoint times out (no response within 30s)
  • Connection fails (DNS resolution failure, connection refused, etc.)

CueAPI does not retry when:

  • Your endpoint returns 2xx (even if the body indicates an error)

Testing locally

For local development, use a tunneling service to expose your local server:

bash
# Using ngrok
ngrok http 8000
 
# Create a cue pointing to the ngrok URL
curl -X POST https://api.cueapi.ai/v1/cues \
  -H "Authorization: Bearer cue_sk_..." \
  -d '{
    "name": "test-webhook",
    "schedule": {"type": "once", "at": "2026-03-14T10:00:00Z"},
    "callback": {"url": "https://abc123.ngrok.io/webhook"}
  }'

Or use worker transport to avoid needing a public URL entirely.

Next steps

Verify webhook signatures

Verify that webhooks are actually from CueAPI, not a malicious third party.