tailthemesbuy this theme · $39
Skip to content
halyard
Sections menu
API reference menu

Reference

Halyard HTTP API

Nine endpoints, JSON in and JSON out, over one base URL.

https://api.halyard.dev/v1API v2.4.1Updated 13 August 2026

Authentication

Every request carries a bearer token. Tokens are scoped to one environment and one set of permissions, and Halyard never accepts a key in a query string.

Authorization header

curl "$API/queues" \
  -H "Authorization: Bearer hk_live_2f9c…"

# 401 without it
# {"error":"unauthorized","message":"Provide a bearer token."}
Scopes
queues:adminscopeCreate and delete queues. Nothing else needs it.
queues:writescopePublish, lease, extend, ack, nack and replay. This is what a consumer runs with.
queues:readscopeList queues and read dead letters. Never moves a message.

Create a queue

POST/queues201

Queues are created by name and are ready to accept messages when the call returns.

Body parameters
namestringrequiredLowercase letters, digits and hyphens, up to 64 characters. Unique inside the environment.
visibility_timeoutduration · default 30sHow long a lease hides a message. Accepts 1s to 12h; a consumer can shorten it per lease.
max_deliveriesinteger · default 5Attempts before a message moves to the dead-letter queue. Set 1 to disable retries.
regionstring · default the caller’s regionOne of eu-west, us-east, us-west, ap-south. Fixed after creation.
201 Created

{
  "name": "orders",
  "region": "eu-west",
  "visibility_timeout": "30s",
  "max_deliveries": 5,
  "depth": 0,
  "created_at": "2026-08-13T09:14:22Z"
}

Delete a queue

DELETE/queues/{queue}204

Removes the queue, its messages and its dead letters. There is no undo and no soft delete.

204 No Content

HTTP/1.1 204 No Content
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1786612560

Careful

A queue with a lease open still deletes. In-flight consumers get 404 on their next ack, so drain the queue before you delete it.

Publish messages

POST/queues/{queue}/messages202

Returns 202 once the write is durable in three availability zones.

Body and headers
bodyobject | stringrequiredStored verbatim, up to 256 KB. Objects come back as objects.
ordering_keystringMessages sharing a key are delivered in publish order. Different keys run in parallel.
delayduration · default 0sHold the message invisible before its first delivery. Maximum 7 days.
Idempotency-KeyheaderRemembered for 24 hours. A repeat returns the original message instead of a duplicate.

Fill the parameters and copy the command. It runs in your terminal; this page assembles it and never sends it.

Build the request

the name in the path

JSON or a string, up to 256 KB

one key, publish order

1s to 7d, empty sends now

remembered for 24 hours

POST/queues/orders/messages202

curl "$API/queues/orders/messages" \
  -H "Authorization: Bearer $HALYARD_KEY" \
  -H "Idempotency-Key: 8f14e45f" \
  -d '{"body": {"order_id":"ord_10427","total_cents":4990}, "ordering_key": "ord_10427"}'
202 Accepted

{
  "id": "msg_01HQ8Z3F",
  "queue": "orders",
  "state": "queued",
  "ordering_key": "ord_10427",
  "delivery_count": 0,
  "published_at": "2026-08-13T09:15:01Z"
}

Lease messages

POST/queues/{queue}/leases200

Claims up to 25 messages and hides them from other consumers until the lease expires.

Body parameters
maxinteger · default 1Messages to lease in one call, up to 25.
waitduration · default 0sHold the connection open until a message arrives, up to 20s. Long polling costs nothing extra.
visibility_timeoutduration · default the queue’s valueOverride the hide window for this lease only.
200 OK

{
  "lease": "lse_01HQ8Z",
  "expires_at": "2026-08-13T09:15:31Z",
  "messages": [
    {
      "id": "msg_01HQ8Z3F",
      "body": {"order_id": "ord_10427", "total_cents": 4990},
      "delivery_count": 1,
      "published_at": "2026-08-13T09:15:01Z"
    }
  ]
}

Note

An empty queue answers 200 with an empty array, not 404. Treat the empty array as normal and keep polling.

Extend a lease

PATCH/queues/{queue}/leases/{lease}200

Buys more time on work already in hand. One call per half-timeout is the pattern the SDKs use.

Body parameters
extend_bydurationrequiredAdded to the current expiry, not to now. Accepts 1s to 12h; the total lease life is capped at 12h.
200 OK

{
  "lease": "lse_01HQ8Z",
  "expires_at": "2026-08-13T09:16:01Z",
  "extended_by": "30s",
  "extensions": 1
}

Note

Extending an expired lease answers 409, not 200. The message is already back in the queue; let the redelivery run.

Acknowledge a lease

POST/queues/{queue}/leases/{lease}/ack204

Deletes every message in the lease. Acks are idempotent, so a retry after a timeout is safe.

204 No Content

HTTP/1.1 204 No Content
X-RateLimit-Remaining: 4991
X-RateLimit-Reset: 1786612560

Return work early

POST/queues/{queue}/leases/{lease}/nack204

Hands the messages back before the timeout, so a known failure does not wait out the lease.

Body parameters
retry_afterduration · default the backoff scheduleHold the message invisible for this long before redelivering. Overrides the doubling backoff once.
reasonstringStored on the delivery attempt and returned as last_error if the message dead-letters. Up to 200 characters.
terminal

curl "$API/queues/orders/leases/lse_01HQ8Z/nack" \
  -X POST -H "Authorization: Bearer $HALYARD_KEY" \
  -d '{"retry_after": "60s", "reason": "payment_provider_timeout"}'

# 204 No Content

Dead letters

GET/queues/{queue}/dead-letters200

Lists messages that exhausted max_deliveries, with the delivery history that got them there.

200 OK

{
  "messages": [
    {
      "id": "msg_01HQ7Y2B",
      "body": {"order_id": "ord_10391"},
      "delivery_count": 5,
      "last_error": "payment_provider_timeout",
      "dead_lettered_at": "2026-08-13T08:02:44Z"
    }
  ],
  "has_more": false
}

Replay a dead letter

POST/queues/{queue}/dead-letters/replay202

Moves dead letters back to the queue. Replay resets delivery_count and preserves the ordering key.

Body parameters
idsstring[] · default every dead letterMessage ids to replay. Omit to replay the whole dead-letter queue, oldest first.
maxinteger · default 100Messages to replay in one call, up to 1,000.
202 Accepted

{
  "replayed": 1,
  "ids": ["msg_01HQ7Y2B"],
  "remaining": 0
}

Errors

Errors carry a stable code, a human message, and nothing else. Retrying helps on 429 and 503; it does not on the rest.

Error codes
invalid_request400The body failed validation. The response names the field. Retrying will not help.
unauthorized401Missing or expired key. Rotate it in the dashboard, then retry.
queue_not_found404No queue by that name in this environment. Check the environment before the name.
lease_expired409The lease timed out before the ack arrived. The message is already back in the queue; do not republish it.
rate_limited429Over the ceiling. Retry-After carries the seconds to wait.
region_unavailable503A region is failing over. Retry with backoff; writes are accepted again within seconds.

Rate limits

Limits apply per queue unless the row says otherwise. Ask support before you need a raise, not during the incident.

Ceilings
Publishper queue1,000 messages a second sustained, 5,000 in a burst of up to ten seconds.
Leaseper queue500 calls a second. Batching with max raises throughput without raising this number.
Acknowledgeper queue5,000 calls a second, matched to the publish burst so an ack never becomes the bottleneck. Extend and nack share this ceiling.
Managementper token60 calls a minute across queue creation and deletion.
Headersevery responseX-RateLimit-Remaining and X-RateLimit-Reset are always present, including on a 200. Reset is a Unix epoch in seconds.