Reference
Headers & status codes
The headers Queuey reads on ingress and sends on delivery, and the HTTP status codes you can get back when you POST an event.
Headers Queuey reads (ingress)
| Header | Meaning |
|---|---|
| Content-Type | application/json for JSON event bodies. |
| X-Api-Key | API-key authentication. Format: qak_<keyId>.<secret> (when the queue's ingress auth is API key). |
| Idempotency-Key | Producer-asserted idempotency key. A duplicate within the dedup window short-circuits to the already-accepted event. |
| X-Queuey-Event-Type | The event's type, such as order.created: what the console shows and filters on, and what integrators of a stream see. Every queue reads it, unless the queue's or the workspace's ingress takes the event type from somewhere else (a query parameter or a body field). |
| X-Queuey-Key-Id | Signed-request: the HMAC signing key id. |
| X-Queuey-Timestamp | Signed-request: Unix seconds, checked for skew (replay protection). |
| X-Queuey-Nonce | Signed-request: a unique value, single-use (replay protection). |
| X-Queuey-Content-SHA256 | Signed-request: lowercase hex SHA-256 of the raw body. |
| X-Queuey-Signature | Signed-request: lowercase hex HMAC-SHA256 of the canonical string. |
| X-Queuey-Path | Loop-prevention chain. Refused past the configured hop budget or on a cycle. |
Setting the event type
From the .NET SDK, set EventType on PublishOptions, or pass it to PushEventAsync; the client sends it as X-Queuey-Event-Type (see .NET producer: Queuey.Client). Over plain HTTP, send the header yourself:
curl -X POST "https://ingress.queuey.ai/events/ten_yourTenant/orders" \
-H "Content-Type: application/json" \
-H "X-Queuey-Event-Type: order.created" \
-d '{ "orderId": "10042" }'
# …plus the queue's credential: the X-Queuey signature headers, or X-Api-KeyEvery queue reads this header, with nothing to set up. The type can come from a query parameter or a top-level body field instead, such as Stripe's type: set "ingress": { "eventType": { "from": "body", "name": "type" } } on the workspace or the queue in queuey.deploy.json, or event typing on the queue's Events tab in the console. Then no producer has to send the header, and a queue with such a source reads the type from there instead.
Headers Queuey sends (delivery)
| Header | Meaning |
|---|---|
| Authorization | Bearer / Basic — set per the target's auth mode (incl. OAuth2). |
| Idempotency-Key | Threaded from the event so an idempotent receiver can dedupe across retries. The v2 signature covers it. |
| X-Queuey-Event-Id | The event's public id, the same on every retry and redelivery: what a receiver deduplicates on. The v2 signature covers it. |
| X-Queuey-Path | Queuey appends its segment, so a downstream Queuey can detect loops. |
| X-Queuey-Signature (+ Key-Id / Timestamp / Nonce / Content-SHA256) | Present when the queue signs outbound deliveries with Queuey HMAC: the v1 signature, as hex, over method, path, query, timestamp, nonce and body hash. |
| X-Queuey-Signatures | Beside v1: the signatures by version, as v2=<hex>. v2 adds the event id and the Idempotency-Key to v1's lines. See Verify deliveries. |
| Stripe-Signature | Present instead, when the queue recalculates the Stripe signature: t=<Unix seconds of this attempt>,v1=<lowercase hex HMAC-SHA256 of {t}.{raw body}>. Signed afresh on every attempt with the secret the queue's Stripe ingress verifies with, and only over the unchanged bytes of events that arrived through that ingress after recalculation started. Verify it with Stripe's libraries — see Stripe webhooks, step 5. |
| Your GroupKey header | Opt-in: the event's GroupKey under a name you choose (see Customer context). |
| Your mapped headers | Opt-in: values lifted off the inbound request at accept — a header, a query parameter, or a top-level body field — sent under names you choose. Snapshotted per event, identical on every retry. See Customer context → Forward more than the GroupKey. |
| Your static headers | Fixed name/value pairs configured on the target. Always win a name collision. X-Queuey-Event-Id and Idempotency-Key can't be static headers: Queuey sets them per event, and signs them. |
Precedence on a name collision, lowest to highest: mapped headers, Queuey's own headers, then static headers / auth / signing. The console refuses a collision at save; the order is the backstop. With Stripe signature recalculation on, Stripe-Signature is written by the signing step alone: a static header, a mapped header or a GroupKey header with that name is refused at save.
Signing does not cover mapped or GroupKey headers. The HMAC canonical string is built from method, path, query, body and the signature headers themselves — a forwarded header travels unsigned. Treat it as context, not as a verified claim. A recalculated Stripe signature covers less still: the timestamp and the body, as Stripe's own scheme does.
Names that can never be forwarded
| Header | Why |
|---|---|
| X-Queuey-* | Queuey's own vocabulary — the whole prefix, including the HMAC headers. |
| Idempotency-Key, X-Idempotency-Key, X-Delivery-Key | Dedup identity; forwarding one would let a producer forge it. |
| Authorization, Proxy-Authorization, Cookie, Set-Cookie, X-Api-Key | Credentials. Forwarding one hands the producer's secret to every receiver of the queue. |
| Host, Content-Type, Content-Length, Connection, Transfer-Encoding, Expect, Upgrade, TE | Transport — the outbound request owns these. |
Ingress status codes
Errors return a consistent envelope so clients can branch on the code: { "error": { "code": "ingress_closed", "message": "…" } }.
| Status | Meaning |
|---|---|
| 202 Accepted | The event was accepted and persisted. The body returns the eventId; delivery is asynchronous. A duplicate Idempotency-Key returns 202 with replayed:true. |
| 400 Bad Request | Validation error — context_group_key_required (the queue requires a GroupKey and none was found); context_group_key_invalid, context_partition_key_invalid or context_event_type_key_invalid (the key contains control characters); context_group_key_too_long, context_partition_key_too_long or context_event_type_key_too_long (the key is over the length limit); outbound_header_required (a mapped header marked required found no value); sandbox_query_not_allowed (sandbox query parameters on the production URL). |
| 401 Unauthorized | Missing or invalid credentials — missing_api_key, invalid_api_key, invalid_signature, timestamp_out_of_range, replayed_request. |
| 403 Forbidden | Valid but denied — ip_not_allowed, client_scope_denied, missing_permission. |
| 404 Not Found | Unknown workspace or queue — not_found. |
| 409 Conflict | The queue's ingress is closed — ingress_closed; events already accepted keep delivering. The queue or its workspace is archived — queue_archived; it takes no events until someone restores it in the console. A queue with no valid mode is refused too — queue_paused. |
| 422 Unprocessable Entity | The X-Queuey-Path chain exceeded the hop budget or formed a cycle — loop_detected / max_hops_exceeded. |
Related
- Signed requests (HMAC) — how the X-Queuey signature headers are built.
- Stripe webhooks — when a delivery carries Stripe-Signature, and what Queuey checks before it signs.
- Customer context — forward the GroupKey and other request values as headers.
- Quickstart — send your first event.