---
title: "Issue Invoice"
method: POST
path: "/api/autopilot/invoices/{invoice_id}/issue"
tags: ["autopilot"]
---

# Issue Invoice

`POST /api/autopilot/invoices/{invoice_id}/issue`

## Request

- Base URL: `https://api.taxcompass.it` (the document declares no server; this is the origin it was published from)
- URL: `https://api.taxcompass.it/api/autopilot/invoices/{invoice_id}/issue`
- Auth: HTTP bearer

Turn one draft into a transmitted e-invoice (AP-031's issue transaction).

The whole of it — number, XML, XSD validation, transmission — happens in the
store, in that order and for reasons documented there. This route's own job
is the status code, and the mapping is the ticket's acceptance criteria:

* **404** — no invoice of that id for this caller. Unknown and somebody
  else's stay indistinguishable, as everywhere else here;
* **409** — the id names a real invoice of theirs that is not a draft, which
  is what a second issue call for the same document produces. Issuing is
  therefore idempotent in the only sense a fiscal sequence allows: the repeat
  is refused rather than absorbed, and no second number is spent;
* **422** — the draft is incomplete, or the profile/customer cannot produce a
  valid document. The store's message names every missing field at once and
  nothing has been written, so the fix is one edit and one retry;
* **503** — two numbering attempts lost a race. Transient by construction;
* **502** — the transmission seam failed. Where it left a numbered document
  behind, that document sits in ``error`` awaiting a retry; either way the
  failure is upstream rather than in the request, which a 500 would deny.

Carries the AP-099 write limiter: it is the most expensive mutation on the
router (a build, an XSD validation and an outbound call), and the only one
that consumes a number.

## Path parameters

- `invoice_id` string, uuid, required

## Response `200`

Successful Response

- InvoiceRead: One stored invoice as the API returns it (``payload`` decrypted). ``number`` is NULL until the issue transaction assigns it, so a draft is exactly the row whose ``status`` is ``draft`` and whose ``number`` is unset. ``total_amount`` is the imponibile the store computed from the lines, and ``bollo_applied`` the builder's verdict on it — both stored plaintext because the live estimate aggregates them in SQL. ``credit_note_of`` is what makes a TD04 legible on its own (AP-090): set, this row is a nota di credito and names the invoice it corrects; NULL on every ordinary document. It is the store's field and never a client's — a credit note is opened through its own route, not by writing this on a draft. ``client_label`` is the same kind of field for an ``imported`` row (AP-095): a pre-signup invoice names its customer as the text the user's own export carried, because there is no client record behind it and inventing one would put a half-filled customer — no address, no identifier — in the picker that issues real documents. It is NULL on every invoice that has a ``client_id``.
  - `client_id` string, uuid, nullable
  - `ateco` string, nullable
  - `issue_date` string, date, nullable
  - `due_date` string, date, nullable
  - `causale` string, nullable
  - `lines` InvoiceLineOutput[]
    - `description` string, required
    - `unit_price` string, required
    - `quantity` string
    - `unit` string, nullable
  - `id` string, uuid, required
  - `year` integer, required
  - `number` integer, nullable
  - `doc_type` string
  - `status` 'draft' | 'sending' | 'issued' | 'delivered' | 'not_delivered' | 'rejected' | 'error' | 'imported'
  - `total_amount` string
  - `bollo_applied` boolean
  - `credit_note_of` string, uuid, nullable
  - `client_label` string, nullable
  - `created_at` string, date-time, nullable
  - `updated_at` string, date-time, nullable
  - `payment` InvoicePayment: The payment side of one invoice — computed by ``services.invoice_payments``. Only ever computed on the server, from the ledger: a paid flag on the document would be a second copy of a fact the incassi table already holds, and the two would disagree the first time someone deleted a payment. * ``due`` — the invoice total minus the credit notes *issued* against it (a draft credit note has told the customer nothing yet, so it owes nothing less). * ``credited`` — that credit-note sum. * ``paid`` — net cash collected against this invoice: its own payments plus the refunds recorded against its credit notes (which are stored negative). * ``outstanding`` — what the customer still owes, never below zero. * ``overpaid_by`` — what arrived beyond ``due``, never below zero. * ``last_payment_date`` — the latest *incoming* payment (a refund is not a payment). * ``days_overdue`` — whole days past ``due_date`` while something is still owed; ``None`` when nothing is owed or the invoice has no due date.
    - `state` 'unpaid' | 'partly_paid' | 'paid' | 'overpaid' | 'credited', required
    - `due` string, required
    - `credited` string
    - `paid` string
    - `outstanding` string
    - `overpaid_by` string
    - `last_payment_date` string, date, nullable
    - `days_overdue` integer, nullable

## Other responses

- `409`: The invoice is no longer a draft
- `422`: The draft, the profile or the customer cannot produce a valid document
- `502`: The document was stored but the provider could not be reached
- `503`: Invoice numbering is contended — retry

---

[API](https://skmtc.dev/taxcompass/apis/taxcompass-api.md) · [All operations](https://skmtc.dev/taxcompass/apis/taxcompass-api/llms.txt) · [OpenAPI document](https://skmtc.dev/taxcompass/apis/taxcompass-api/revisions/fef5fc6a9b91?raw)
