Browse documentation DocumentationLet’s talk
Documentation / Build with Rokn

Sending invoices and quotes

Sending is asynchronous: the send routes answer 202, a send moves from queued to sent or failed, and a failed send tells you why.

Sending an invoice or a quote is asynchronous. POST …/invoices/{id}/send and POST …/quotes/{id}/send queue the document and answer 202 Accepted at once with the send; they no longer answer 200 once the document has been sent. Read the outcome with the send, or with the document's sendState. Every path below is under /api/v1/workspaces/{slug}.

The flow

  • POST …/invoices/{id}/send (invoices:write, tool send_invoice) and POST …/quotes/{id}/send (quotes:write, tool send_quote) answer 202 with the send: id, documentId, documentType, state, failureReason, emailOutcome, attempts, createdAt and finishedAt.
  • GET …/invoices/{id}/sends/{sendId} (invoices:read, tool get_invoice_send) and GET …/quotes/{id}/sends/{sendId} (quotes:read, tool get_quote_send) return that send as it stands now. A send id that belongs to another document is 404.
  • state is queued or working while the worker runs, then sent or failed. While a send is open, the invoice or quote carries sendState of queued or working; otherwise it is null.
  • The document stays a draft until the send commits. Then it is sent and locked, an invoice with its pay link and a quote with the client's approval link, and the client is emailed the PDF.

The outcome

  • A sent send has an emailOutcome: sent, skipped (the client has no email address) or failed (the document is sent but the email could not be delivered).
  • A failed send has a failureReason: gateway_unavailable, pdf_unavailable or conflict (a transient failure, retried three times, no sooner than 15 seconds, 1 minute and 5 minutes after each failure, before the send fails); gateway_rejected (the payment gateway refused its credentials) or gateway_test_mode (a test-mode key in production), which fail it at once; and quote_expired, not_sendable, feature_locked, billing_read_only, interrupted, requester_not_allowed and unexpected.
  • Nothing is sent when a send fails, and the document stays a draft. Fix the cause and POST again.

Refusals and retries

  • A second POST while a send is open is 409 send_in_progress. A document that is no longer a draft is 409 invalid_status_transition. A quote whose validity has passed is 409 quote_expired.
  • Both routes honour Idempotency-Key: a replay returns the same send.
  • The worker picks up queued sends every minute.

Finding out that a send failed

When a person asked for a send and it fails for good, Rokn publishes invoice.send_failed or quote.send_failed to that person and they are notified. A send queued by an API key or by automation has no requester and publishes nothing: poll the send, or the document's sendState, instead.

HTTP · send an invoice and read the outcome
POST /api/v1/workspaces/acme/invoices/inv_123/send
Authorization: Bearer <token>
Idempotency-Key: 6f1c2e0a-…

# 202 → { "id": "snd_1", "documentType": "invoice", "state": "queued", … }

GET /api/v1/workspaces/acme/invoices/inv_123/sends/snd_1
Authorization: Bearer <token>

# 200 → { "state": "sent", "emailOutcome": "sent", "failureReason": null, … }