Tabba.
FunktionerPriserKontakt
Log indKom i gang
Tabba.

Moderne økonomistyring for virksomheder.

Produkt

  • Funktioner
  • Priser
  • Integrationer
  • Ændringslog

Ressourcer

  • Blog
  • Hjælpecenter
  • Udviklere

Virksomhed

  • Karriere
  • Kontakt

Juridisk

  • Privatlivspolitik
  • Servicevilkår
  • Cookie-politik
  • Sikkerhed

Forbind

  • Twitter
  • GitHub
  • LinkedIn
  • Discord

© 2026 Tabba. Alle rettigheder forbeholdes.

PrivatlivspolitikServicevilkårCookie-politik
Back to developer docs

Guides

  • Getting started
  • Authentication
  • external_id and idempotency
  • Work registration
  • Issuance and auto-send
  • Webhooks
  • Pagination
  • Errors

Issuance and auto-send

Issuing an invoice is the act of freezing it, booking it into Dinero, and (optionally) sending it to the customer. Tabba 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://www.tabba.io/api/v1/invoices/ext:proj_ACME_migration/issue \
  -H "Authorization: Bearer $TABBA_API_KEY"

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

Issuance is synchronous and idempotent — a timeout-then-retry returns the already-issued result, never double-books. Under the hood Tabba'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 Tabba 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/tabba', (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://www.tabba.io/api/v1/invoices/ext:proj_ACME_migration \
  -H "Authorization: Bearer $TABBA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "auto_send": false }'

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

Issuance in Tabba 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 Tabba 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.