Skip to content

HTTP Client

Queen from anything that speaks HTTP: push, pop, acknowledge and long-poll, each one a runnable curl.

Updated View as Markdown

Queen has no binary protocol and no wire framing. Every SDK is a wrapper over JSON on HTTP, so anything that can make an HTTP request is a first-class client, curl included. The base URL is http://host:6632, and one header authenticates: Authorization: Bearer <token>.

Push

Two messages, one call. The queue and the partition are created by it: there is no declaration step.

curl -s -X POST http://localhost:6632/api/v1/push -H 'Content-Type: application/json' -d '{"items":[{"queue":"demo","partition":"acct-42","transactionId":"evt-1","payload":{"n":1}},{"queue":"demo","partition":"acct-42","transactionId":"evt-2","payload":{"n":2}}]}'

queue and payload are required per item, partition defaults to Default. A missing transactionId is minted as a UUIDv7, which makes the push non-idempotent: send a deterministic one and a retry inside the dedup window comes back as a duplicate instead of writing twice.

The answer is 201 and one entry per item, in request order, each carrying a status: queued, duplicate (nothing was written, and message_id is the original message’s), buffered (the database write failed and the message is on the broker’s disk spool awaiting replay) or failed (the spool write failed too, and the message is gone). A 201 does not by itself mean “stored in PostgreSQL”: read every item’s status.

Pop

Lease a batch for a consumer group. batch caps how many messages come back.

curl -s 'http://localhost:6632/api/v1/pop/queue/demo?consumerGroup=billing&batch=10'

Add /partition/:partition to the path to pin one lane, or call /api/v1/pop with a namespace or a task to lease across every matching queue. The response, abridged, carries the lease and the messages. Keep the leaseId and each message’s partitionId: the acknowledgement needs both.

{
  "success": true,
  "queue": "demo",
  "partitionId": "0197f2b0-...",
  "leaseId": "0197f2b2-...",
  "consumerGroup": "billing",
  "messages": [
    {
      "id": "0197f2b1-...",
      "transactionId": "evt-1",
      "data": { "n": 1 },
      "partitionId": "0197f2b0-..."
    }
  ]
}

Acknowledge

Both messages, in one call.

curl -s -X POST http://localhost:6632/api/v1/ack/batch -H 'Content-Type: application/json' -d '{"consumerGroup":"billing","acknowledgments":[{"transactionId":"evt-1","partitionId":"<partitionId>","leaseId":"<leaseId>","status":"completed"},{"transactionId":"evt-2","partitionId":"<partitionId>","leaseId":"<leaseId>","status":"completed"}]}'

partitionId is required, because a transactionId is not unique across partitions. An ack is an offset commit: there is one cursor per partition and consumer group, so acking evt-2 alone completes evt-1 too, and a negative ack clamps the cursor at the failed message, which means everything after it in that batch is coming back.

status is normalised server-side. completed, success, acked, ok and absent all mean completed; retry and dlq mean themselves; anything else at all means failed. A typo does not error, it nacks.

The route answers 200 with an array in request order whatever the outcome, so a rejected ack is a 200 with success: false on its item. The status code tells you nothing here: check each entry, and the array length against what you sent.

Long-poll

Do not spin on an empty queue. wait=true parks the request until a message arrives or timeout milliseconds pass.

curl -si 'http://localhost:6632/api/v1/pop/queue/demo?consumerGroup=billing&batch=10&wait=true&timeout=5000'

The group’s cursor is past both messages now, so this one comes back 204 No Content with no body at all, which -i makes visible. Treat a 204 as “no messages” and never parse it. Give your own HTTP client more time than the broker: the SDKs set their timeout to timeout plus 5,000 ms, so the server’s window closes first and the socket stays reusable.

Conventions, access levels and error codes are in the HTTP API reference; every method and path the broker registers, with the role that satisfies it, is in the route table.

Next: Hello world, the first of four tutorials that put these routes in a runnable script and check their own outcome.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close