Create an invoice
POST/api/v1/workspaces/:workspace_id/invoices
Creates a new invoice for the specified workspace.
Before the invoice is built, the payload is completed with company-side defaults:
- party_id resolution: a
partiesentry with aparty_id(optionallybilling_address_id) is filled from the company's directory (name, legal registration id/scheme, VAT id, routing identifier, billing address, default contact) and back-linked so the response'sparty_idround-trips. Lookup is scoped by STI type to matchdirection:buyeronsalesresolves against the company's customers,selleronpurchasesagainst its suppliers;payeeandtax_representativeresolve against the whole directory. Aparty_idon the company's own role (selleronsales,buyeronpurchases) returns 422 (api.invoices.errors.party_id_not_allowed_for_company_role) - that party is derived from the company record, not the directory.party_idandbilling_address_idmust be positive integers; anything else returns 422 (api.invoices.errors.invalid_reference_id) rather than being coerced. Any sibling attribute also sent on the entry overrides the corresponding directory value. An unresolvableparty_idreturns 422. When the directory record carries a SIRET declared under scheme0009, the party is filled with the SIREN of the legal unit - the first 9 digits - under scheme0002, because BR-FR-11 reads BT-47 off the0002selector and requires exactly 9 digits once the invoice is a B2B flux 2 piece; a value left under0009does not fill that selector at all and the assertion is fatal. Only the identity this endpoint copies from the directory is converted: alegal_registration_idsent explicitly on the entry is the declared intention of the caller and passes through untouched, and a 14-digit registration carrying no declared scheme is not converted either, since shape alone does not prove a French identity. - Company-side party default: when the payload has no entry for the
company's own role (
sellerondirection: sales,buyerondirection: purchases), one is filled from theCompanyand its headquarters establishment. A party entry the caller does supply is never overwritten. - item_notes default: when the key is OMITTED and
directionissales, the company's legal disclaimers are inserted.purchasesinvoices get none. Sending an explicit empty array clears the collection and is never refilled - that is how an integrator removes existing notes on a PATCH. - payment_means default: when the key is OMITTED (an explicit empty
array clears the collection and is never refilled), the company's
on-invoice bank accounts are inserted, on both directions. On
sales, when the buyer resolves to a directory customer that is confidentially factored, that customer's factor account replaces them. When asalesbuyer is present but cannot be resolved to a directory customer (sent by name only, with noparty_idand no persisted link), no payment means are inserted at all - factored status cannot be determined, and emitting the company's own accounts for a factored customer would misroute the payment. - Third-party payer profile guard: a
partiesentry withrole: "payer"(the EXT-FR-FE-BG-02 block) is accepted only whencustomization_idis one of the two EXTENDED-CTC-FR forms -urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended(Factur-X/CII) orurn:cen.eu:en16931:2017#conformant#urn.cpro.gouv.fr:1p0:extended-ctc-fr(UBL). An omitted, blank, or plain EN 16931customization_idreturns 422 (api.invoices.errors.payer_requires_extended_profile) and writes nothing: the UBL and CII generators refuse to emit a payer outside EXTENDED-CTC-FR, so accepting one here would create an invoice whose every structured export fails, which the caller would only discover at download time. - Structured actors (XP Z12-014):
buyer_agent(EXT-FR-FE-BG-01),seller_agent(EXT-FR-FE-BG-03),invoicee(EXT-FR-FE-BG-04) andinvoicer(EXT-FR-FE-BG-05) are returned under their own key on read, populated on received documents; none is ever read as the seller, the buyer or the payer. They are accepted on create and update only under one of the two EXTENDED-CTC-FRcustomization_idforms, and the UBL and CII exports emit them there; under any othercustomization_idan entry returns 422 (api.invoices.errors.extended_role_requires_extended_profile). Each entry must carry aname(EXT-FR-FE-03 / -66 / -89 / -112, 1..1), sent or filled fromparty_id, else 422 (api.invoices.errors.structured_actor_name_required); anidentifiermust come with itsidentifier_scheme_id(EXT-FR-FE-07 / -70 / -92-1 / -116, 1..1), else 422 (api.invoices.errors.structured_actor_identifier_scheme_required); anendpoint_idmust come with itsendpoint_scheme_id(EXT-FR-FE-13 / -76 / -99 / -122, 1..1), else 422 (api.invoices.errors.structured_actor_endpoint_scheme_required); alegal_registration_idmust come with itslegal_registration_scheme_id(EXT-FR-FE-09 / -72 / -95 / -118), else 422 (api.invoices.errors.structured_actor_legal_registration_scheme_required); an address stating any field must carry itscountry_code(EXT-FR-FE-107 / -130, Factur-X EXTENDED), else 422 (api.invoices.errors.structured_actor_country_required), and acountry_codethat is not ISO 3166-1 alpha-2 returns 422 (api.invoices.errors.structured_actor_country_unknown);endpoint_scheme_idmust be in the CEF EAS list (BR-CL-25),identifier_scheme_idandlegal_registration_scheme_idin the ISO 6523 ICD list (BR-CL-10 / -11), each narrowed to the codes Scribee's scheme table carries less0231(reserved for the single taxable entity), else 422 (api.invoices.errors.structured_actor_scheme_outside_code_list); anendpoint_idover 125 characters returns 422 (api.invoices.errors.structured_actor_endpoint_too_long, BR-FR-25, fatal); any of those three schemes sent without its value returns 422 (api.invoices.errors.structured_actor_value_required), since it is emitted only as the value's attribute; adirectory_routing_identifierreturns 422 (api.invoices.errors.structured_actor_routing_identifier_unsupported) - it routes the seller and the buyer only, an actor's electronic address is itsendpoint_id, and it is not copied from aparty_iddirectory sheet onto an actor; a non-stringnameor scheme counts as missing; and a second entry of the same actor role returns 422 (api.invoices.errors.structured_actor_duplicated); abuyer_agentorinvoiceewithout abuyer, or aseller_agentorinvoicerwithout aseller, returns 422 (api.invoices.errors.structured_actor_parent_required), since UBL nests the actor inside that party - the company-side party the API adds counts. An invoice naming aninvoiceris deposited only when the company holds an active third-party invoicer billing mandate for it on the issue date (XP Z12-014 cas 19a); otherwise the deposit returns 422 and the invoice stays a draft. - role_code guard:
role_codeis accepted on apayer(EXT-FR-FE-44), apayee(EXT-FR-FE-26) and a structured actor entry (EXT-FR-FE-04 / -67 / -90 / -113). Sending one on any other role returns 422 (api.invoices.errors.role_code_not_allowed_on_role), because no other role's value is ever emitted on the wire. The invoicee's code is alwaysIVand the invoicer'sII, and any other value returns 422 (api.invoices.errors.role_code_mismatch). On every accepted role, the value must come from the UN/CEFACT PartyRoleCode D22A list - the UNCL 3035 value space - and is matched case-sensitively; anything else returns 422 (api.invoices.errors.invalid_role_code).PRis the third-party payer code. On apayeeentry the code also requires one of the two EXTENDED-CTC-FRcustomization_idforms: EXT-FR-FE-26 is defined only in the EXTENDED profiles and CII-SR-352 / UBL-CR-270 forbid the element in plain EN 16931, so a payeerole_codeunder any other profile returns 422 (api.invoices.errors.payee_role_code_requires_extended_profile). A payee WITHOUT arole_codeis plain EN 16931 (BG-10) and is accepted under every profile. - Currency guard:
currency_code(BT-5),tax_currency_code(BT-6) and eachtax_subtotals[].currency_codemust be an ISO 4217 alpha-3 code drawn from the code lists Scribee vendors - the UN/CEFACT ISO3AlphaCurrencyCode enumeration unioned with the Peppol BISISO4217list. Matching is case-sensitive, soeuris refused rather than upcased, and anything outside those lists returns 422 (api.invoices.errors.invalid_currency_code); the message names which of the three fields was refused. Acceptance here is not Peppol conformance: PEPPOL-EN16931-CL007 is fatal against its own narrower list, so a handful of codes are accepted at write time and still refused at Peppol export. An omitted or blank value is never refused - BT-5 falls back toEURon create and to the invoice's existing currency on update. - VAT breakdown coherence guard (
direction: "sales"only): thetax_subtotalsmust reconcile with the document totals. The sum ofamount_without_taxes(BT-116) is compared withtotal_amount_excluding_taxes(BT-109), and the sum ofvat_amount(BT-117) withtotal_tax_amount(BT-110), each within 0.01 - the tolerance PPF rule F1-START-TOTAL-COHERENCE-G1.53 spends at deposit. A gap beyond it returns 422 withcode: "operation_failed"(api.invoices.errors.ventilation_not_reconciled) and writes nothing; the message names the total, the figure the document declares and the figure the breakdown sums to. Each half is judged on its own and is out of scope when its document total is omitted or when notax_subtotalsrow states its amount - an omitted total is not a zero total, which is how the schematron reads it too.direction: "purchases"is never judged: a purchase recorded through the API is the reflection of a piece the tenant received and this platform never deposits it. The guard exists because BT-116 carries the base EXCLUDING tax, so a caller filling it with the tax-inclusive amount used to get a 201 here and a PPF refusal hours later. - Already-paid coherence guard (
direction: "sales"only): an invoice or credit note stating the already-paid state -invoicing_process_idpaid_goods_invoice/paid_services_invoice/paid_goods_and_services_invoice(codesB2/S2/M2, BT-23), or one of those codes inprofile_id- must state the settlement itself:prepaid_amount(BT-113) equal totax_inclusive_amount(BT-112),payable_amount(BT-115)0, nopayable_rounding_amount(BT-114) other than0, and the payment date indue_date(BT-9), on or beforeissue_date. These are the fatal flux 2 rule BR-FR-CO-09 and EN 16931 BR-CO-16. Anything else returns 422 withcode: "operation_failed"(api.invoices.errors.already_paid_*) and writes nothing. The API never fills these totals in, and it never infers the already-paid state from them: a paid invoice may also stay in theB1/S1/M1family, which this guard does not judge. Stating the state creates no payment record and no lifecycle status. An already-paid invoice may not name a down-payment invoice bydocument_idininvoice_referenceseither: that makes it a final invoice settling down payments, whoseB4/S4/M4family has no already-paid variant (XP Z12-014 CU-21), so it returns the same 422 and writes nothing.
Request
Responses
- 201
- 401
- 403
- 422
The created invoice, including any party, item-notes, or payment-means fields the API filled in from the company's directory defaults.
The request carries no OAuth bearer token, or the token is invalid or expired.
The token's OAuth application has no access relationship with the requested workspace's tenant, or no such workspace exists.
The payload failed validation. The error body reports error: "unprocessable_entity" with a message describing the specific failure - a blank required field, an unresolvable party_id, a party_id sent for the company's own role, a payer party (EXT-FR-FE-BG-02) on an invoice whose customization_id is not one of the two EXTENDED-CTC-FR forms, or a role_code sent on a role other than payer (EXT-FR-FE-44) or payee (EXT-FR-FE-26), outside the UN/CEFACT PartyRoleCode D22A list, or on a payee whose customization_id is not one of the two EXTENDED-CTC-FR forms (EXT-FR-FE-26 is defined only in the EXTENDED profiles), or sent as a value that is not a string at all (a JSON boolean or number is never absence, so on a payer or payee it is refused as an unlisted code and on any other role it is refused for the role), or a currency_code (BT-5), tax_currency_code (BT-6) or tax_subtotals[].currency_code outside the vendored ISO 4217 code lists - matched case-sensitively, with the message naming which of the three fields was refused, and a value that is not a string at all refused the same way rather than read as absence, only an omitted key, an explicit null or an empty or whitespace-only string counting as sending no currency - or, on a direction: "sales" payload, a tax_subtotals breakdown that does not reconcile with the document totals, the sum of amount_without_taxes being compared with total_amount_excluding_taxes and the sum of vat_amount with total_tax_amount, each within the 0.01 tolerance of PPF rule G1.53 and each out of scope when its document total or its breakdown amounts are absent, refused with code: "operation_failed" (api.invoices.errors.ventilation_not_reconciled) - or, on a direction: "sales" payload stating the already-paid state (invoicing_process_id B2 / S2 / M2 or their paid_* keys, or one of those codes in profile_id), a prepaid_amount other than tax_inclusive_amount, a payable_amount other than 0, a payable_rounding_amount other than absent or 0, or a due_date that is missing or later than issue_date (flux 2 rule BR-FR-CO-09, EN 16931 BR-CO-16), or an invoice_references entry naming a down-payment invoice by document_id (XP Z12-014 CU-21), refused with code: "operation_failed" (api.invoices.errors.already_paid_*) - or a direction: "sales" payload targeting a company whose subscribed offer does not include sales invoicing - the same restriction, and the same status, that POST /invoices/upload reports; the company itself is visible in the workspace, so this refusal is never a 404. details is present and field-keyed whenever the refusal names attributes (a record validation failure, or a requested lifecycle_state the deposit guard refuses and whose missing fields it lists), and absent otherwise. A requested lifecycle_state: "deposited" runs the same deposit guard as PATCH /invoices/{id}/transition, so its refusals are reported here too - among them a party that states no country, with details keyed on seller.address.country_code or buyer.address.country_code. Only the flux 1 obligation carries that presence rule; a sale whose buyer owes an e-reporting declaration (flux 10) is not refused for it.