Skip to content

Acknowledge a message and send another

Last updated 

POST /spools/{spool}/ack-and-send

Atomically completes the delivery the lease names and appends the request body to the queue Spooler-Queue names — a pipeline step handing its result to the next stage, with no window where the input is acked and the output is missing, or the reverse. The two queues may differ or be the same. Send's headers apply: Spooler-Delay-Seconds postpones the new message, a dedup key deduplicates it. Retries need no dedup key, whatever the status or a lost response: a retry of a committed call fails with 410 and appends nothing. On synchronous copies a redelivery after a lost lease means the first call never committed; with none, a primary change can lose a committed call, input and output alike (see the replication docs). A dedup hit refuses the whole call (409 kind dedup_claimed, the original id in details.id) and acks nothing — ack explicitly if folding into the existing message was the intent. The destination refuses the call the way it refuses a send: a draining queue, the lease's own included, answers 409 queue_deleting and nothing is acked. The spool's message cap does not apply (the call is net zero); the byte cap refuses only growth past the limit.

Sample ​

sh
curl -si -X POST "$SPOOLER_API/spools/<spool>/ack-and-send" \
  -H "Authorization: Bearer $SPOOLER_KEY" \
  -H "Spooler-Queue: <queue>" \
  -H "Spooler-Lease: <lease>" \
  --data-binary '<payload>'

Parameters ​

NameInTypeRequiredDescription
spoolpathIdentName, 1–63 chars, ^[A-Za-z0-9_:-]+$yesThe spool name.
handlequerybooleannoWhen true, the response carries a handle to the fresh message in Spooler-Handle. Its one use is to take the message back before anyone receives it: present it to discard to cancel a delayed send whose condition was met in the meantime, or to withdraw a send whose surrounding work failed to commit — a cancel window, not a transaction: a producer that crashes before cancelling leaves a deliverable message. Off by default, since the handle is a bearer credential.
Spooler-QueueheaderIdentName, 1–63 chars, ^[A-Za-z0-9_:-]+$yesThe queue the new message is sent to; the lease names the one acked from. The two may be the same.
Spooler-LeaseheaderLease, 16–256 chars, ^[A-Za-z0-9_-]+$yesThe lease from a receive, presented back.
Spooler-Delay-Secondsheaderinteger, 0–604,800noSeconds until the new message becomes visible, at most a week. Omitted or 0 means immediately visible.
Spooler-Dedup-Stringheaderstring, 1–128 chars, ^[\x21-\x7E]+$noThe new message's dedup key, as on send. A hit inside the queue's dedup window refuses the whole call with 409.
Spooler-Dedup-Hashheaderstring, 32 chars, ^[0-9a-fA-F]{32}$noThe new message's 16-byte dedup fingerprint, hex-encoded, as on send.

Request body ​

Required; application/octet-stream.

Responses ​

StatusDescription
201Acknowledged and appended durably; no body.
400The request is malformed; the kind names the problem.
401The API key is missing or not recognized; the kind is unauthenticated.
402The account is suspended; the kind is account_suspended.
403The operation is refused; the kind names why: a plan limit (queue_limit, retention_limit), or account_blocked on any operation when the account is on an abuse hold.
404The spool or queue does not exist; the kind says which.
409Concurrent state refuses the operation; the kind names it.
410The lease no longer settles anything: expired, already settled, or predates a primary change.
413The message exceeds the plan's message size limit. The connection is closed, since the body is left unread.
429The per-account request rate cap is exceeded. The body names the kind (rate_limited); the wait is the Retry-After header and is not repeated in the body. Headers are as structured as the body, and this one is the header HTTP defines for a wait.
500The server failed; kind operation_unconfirmed means the write was accepted but its durability is unknown.
503The spool is momentarily unavailable.
507The new message would grow the spool's payload bytes past its plan's maximum (kind spool_full). An equal or smaller message always passes, so a full spool can still drain.

201 headers ​

HeaderDescription
Spooler-Message-IdThe appended message's id.
Spooler-HandleThe handle to the fresh message; present only when the request asked for it via handle=true.

429 headers ​

HeaderDescription
Retry-AfterSeconds until the next request is admitted, whole and at least 1; always the delay-seconds form, never an HTTP-date.