Developers

Issuance and auto-send

Explicit issuance vs the auto-send cron; booked-but-send-failed.

Issuing an invoice is the act of freezing it, booking it into Dinero, and (optionally) sending it to the customer. Invoia supports two patterns.

Explicit issuance

Drive it from your integration when your workflow says "this project is done":

# One-time invoice.
curl -X POST https://invoia.io/api/v1/invoices/ext:proj_ACME_migration/issue \
  -H "Authorization: Bearer $INVOIA_API_KEY"

# A series occurrence.
curl -X POST https://invoia.io/api/v1/recurring-series/ext:acme-retainer/occurrences/2026-07-01/issue \
  -H "Authorization: Bearer $INVOIA_API_KEY"

Issuance is synchronous and idempotent — a timeout-then-retry returns the already-issued result, never double-books. Under the hood Invoia's Dinero GUID guard is the same one the UI's issue button rides.

auto_send (cron-driven)

Every invoice carries an auto_send boolean. When it's on, the Invoia cron issues the invoice on its issue date without your involvement — the exact same behaviour as the UI. Leave it on for hands-off retainers and rely on the invoice.issued webhook to learn about the booking:

// Your webhook receiver.
app.post('/webhooks/invoia', (req, res) => {
  const event = req.body
  if (event.type === 'invoice.issued') {
    await syncInvoiceToPmTool(event.data)
  }
  res.status(200).end()
})

Toggle it via the invoice PATCH:

curl -X PATCH https://invoia.io/api/v1/invoices/ext:proj_ACME_migration \
  -H "Authorization: Bearer $INVOIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "auto_send": false }'

Booked-but-send-failed (200 + send_error)

Issuance in Invoia is two steps: book the invoice into Dinero, then send it to the customer (email or EAN). Booking is what makes the invoice real. If booking succeeds but the send fails (e.g. Dinero's email service returns 5xx), you get a 200 with a send_error:

{
  "object": "invoice",
  "id": "",
  "status": "issued",
  "dinero_invoice_guid": "",
  "send_error": {
    "code": "SEND_FAILED",
    "message": "Dinero email service unavailable."
  }
}

Do not retry issue — the invoice is already booked. Retry the send instead (POST /invoices/{ref}/resend; slice-forthcoming). This prevents the classic "retry the failure and double-book" trap.

Editing after issue

Once an invoice has a dinero_invoice_guid, it is frozen. Attempting to edit it returns 409 INVOICE_ALREADY_ISSUED. Raise a credit note instead — full or partial — via POST /credit-notes.

Bulk issuance

Bulk issuance stays cron-driven: auto_send=true on a set of invoices lets Invoia issue them together on the issue date. The API is single-item only. If you need to issue N invoices, iterate — each call is idempotent so re-runs are safe.