Formats and downloads
Your product must keep and present each invoice in its regulatory form: a readable PDF for your screens, a Factur-X, a UBL, or a CII for archiving and exchange with other systems. Every Scribee invoice, issued or received, downloads in these four formats from a single endpoint, GET /api/v1/invoices/{id}/download. The call transmits nothing to the outside and replays as many times as needed on your production account, including on a draft. It is not a pure read for all that: a format with no copy attached yet is generated during the request, and that generation can write to the invoice (see below).
What Scribee does for you
- Format conversion: the four representations are produced from the same invoice data. You do not write XML or PDF; you choose a format on the call. One exception, described below: when the invoice was deposited as a Factur-X, the
facturxformat converts nothing - it returns the deposited file. - PDF/A-3 conformance: the
facturxformat targets PDF/A-3 with the CII XML embedded, but conformance is an observed state, not a guarantee. When the invoice carries a PDF provided at creation (provided_pdfset totrue), its conformance is checked after generation and exposed in the invoice'sfacturx_conformancefield (pending,compliant,non_compliant). Anon_compliantresult does not stop generation: the file stays downloadable as is. It does block the invoice's deposit, however, on top of its regulatory transmission - an invoice with a non-conformant provided PDF does not passdeposit. Readfacturx_conformancebefore treating afacturxfile as a PDF/A-3. Without a provided PDF, this field stays null, since the Scribee rendering is conformant by construction. The one exception is a sales invoice imported as a Factur-X: its file is judged at its deposit, and the field carries that verdict (Import existing invoices). - Early generation: the files are generated in the background as soon as the invoice is created, and regenerated on every modification. If a file is not ready yet at the time of the call, it is generated on the fly within the same request: the download does not fail because generation is in progress.
- An incomplete creation does not attach your PDF: if the payload omits
invoice_number,issue_date,type_codeorcurrency_code, the invoice is still created (a201response, with placeholder values recorded) but the PDF you provided is not attached and no generation is triggered. Checkprovided_pdfin the creation response rather than assuming the file arrived. - Your PDF is kept until the first modification: when
provided_pdfistrue, thepdfformat returns the file provided at invoice creation, not a Scribee rendering. Two limits to know before relying on it, both detailed below: the file is only kept if creation produced no blocking error, and aPATCHon the invoice has it replaced by a Scribee rendering as soon as regeneration completes.
The four formats
The format parameter accepts four values; without a parameter, the endpoint returns the pdf.
format | Content | Content-Type | File name |
|---|---|---|---|
pdf (default) | PDF, the readable rendition of the invoice, followed by its attachments - or the deposited carrier as is for a deposited Factur-X | application/pdf | INV-2026-042.pdf |
ubl | UBL XML (OASIS UBL 2.1, EN16931) | application/xml | INV-2026-042-ubl.xml |
cii | CII XML (UN/CEFACT Cross Industry Invoice, EN16931) | application/xml | INV-2026-042-cii.xml |
facturx | Factur-X: PDF/A-3 with the CII XML embedded (EN16931) | application/pdf | INV-2026-042-facturx.pdf |
The file name is built from the invoice's invoice_number and carried by the Content-Disposition header. On the Factur-X side, the recognized conformance levels are Factur-X Minimum, Factur-X Basic WL, Factur-X Basic, EN16931, and Factur-X Extended; the level recorded in the produced file is derived from the profile of the embedded XML.
The pdf format of a Scribee-rendered invoice does not contain the invoice alone: supporting documents flagged as attached to the invoice (PDF formats only) are concatenated after the invoice pages, followed by the company's general terms of sale when it has any. The page count is therefore not predictable from the invoice data alone. This composition does not apply to an invoice carrying provided_pdf set to true, nor to an invoice deposited as a Factur-X: the download then serves the file as is, with nothing appended.
A deposited Factur-X is returned to you as is
When the invoice entered Scribee as a Factur-X - a PDF/A-3 carrying a CII, which source_format signals with the value facturx (Import existing invoices) -, the facturx and pdf formats give you back the deposited bytes, unchanged. Scribee does not recompose the file: it reads back the carrier archived at import and serves it untouched, and the CII XML published for that document is the one actually embedded in those bytes.
What you can concretely expect from it: the sha256 fingerprint of the downloaded file is the one of the deposited file. The AFNOR XP Z12-013 standard distinguishes, in §5.4.1, the docType Original, the invoice as received, from the docType Converted, a converted version, and recommends in §5.2.3 that the platform compute the sha256 fingerprint of the deposited file and answer 4XX when the comparison differs. A regeneration, however faithful to the data, produces a different file and therefore a different fingerprint: it cannot satisfy that comparison. Returning the file lets you run it end to end, and preserves the visual layer and the seal applied by the issuer.
The scope is narrow, and it follows the carrier:
facturxof an invoice deposited as a Factur-X: the deposited bytes, returned.facturxof any other invoice: generation, as before. A CII or a UBL deposited as bare XML has no PDF carrier to give back;source_formatthen readsciiorubl, and the Factur-X is produced from the data.ublandcii: always generated from the invoice data, including for a deposited Factur-X.pdfof an invoice deposited as a Factur-X: the deposited bytes, returned as well. A Factur-X is a PDF/A-3: its visual layer is a readable view, the issuer's own. Scribee does not manufacture a second one over it.pdfof any other invoice: a readable rendering produced by Scribee, as before.
The file is still returned after a modification of the invoice. What you deposited does not change because the extracted data was corrected: the ubl and cii formats are the ones carrying the up-to-date data.
One condition suspends it: the original file must have been retained at import, which is not the case above 50 MB (Import existing invoices). With no archived carrier, the facturx format is produced from the data, as for any other invoice.
If the carrier was retained but turns out to be unreadable in storage at export time, the download fails with a 422 (see below) instead of handing you a regenerated PDF in its place. Scribee never silently substitutes a regeneration for the file you deposited: you could not tell the difference, and nothing would prompt you to look.
:::warning Behaviour change
Until now, the facturx format of an invoice deposited as a Factur-X returned a PDF regenerated by Scribee from the extracted data, and never the original file. Its fingerprint therefore did not match the one of the deposited file, and its visual layer was the Scribee rendering rather than the issuer's. If your integration archives this download, or compares its fingerprint to the one of the file you sent, it now receives your own bytes.
:::
:::info customization_id is resolved when you do not send one
The ubl, cii and facturx formats carry the customization_id you send at creation. If you do not send one, the specification identifier (BT-24) of the produced file is the EXTENDED-CTC-FR profile's, written in the requested format's own syntax, and the facturx XMP announces that same profile in fx:ConformanceLevel. The file's two layers agree.
Send the customization_id explicitly as soon as you target another profile - the EN 16931 core or a Peppol profile: the value you transmit always wins over the resolved one.
This resolution applies only to invoices issued from Scribee. A document you import keeps the customization_id its issuer declared, and receives none when it declared none: Scribee does not invent a third party's specification declaration.
What changes if you were sending nothing. The produced BT-24 used to be empty while the facturx XMP still wrote EN 16931 - the two layers contradicted each other, and a recipient could reject the file. Your calls do not change; the produced file does.
An invoice carrying a payer party requires a customization_id of the EXTENDED-CTC-FR profile: it is the only profile where that party is legal, since the standard EN 16931 chain forbids it. The combination is refused at write time: POST /api/v1/workspaces/{workspace_id}/invoices and PATCH /api/v1/invoices/{id} answer 422 as soon as the payload carries a payer party without an EXTENDED-CTC-FR customization_id, and the invoice is neither created nor modified (Issue a sales invoice). The download refusal now only concerns invoices whose payer party arrived by a route other than those two calls - importing a UBL or CII file with POST /api/v1/workspaces/{workspace_id}/invoices/upload in particular: ubl and cii then fail at generation.
:::
The parties' electronic address in ubl and cii
The ubl and cii files carry the electronic address of every party on the invoice - BT-34 for the seller, BT-49 for the buyer. For those two roles, Scribee resolves it in this order: directory_routing_identifier, the directory routing identifier, under scheme 0225; failing that legal_registration_id, under that same scheme 0225; failing that endpoint_id, under its own endpoint_scheme_id. The other roles (payee, payer, delivery, tax_representative) read endpoint_id directly.
That last step is new for the seller and the buyer: a party with neither directory_routing_identifier nor legal_registration_id used to produce a file with no electronic address at all, even when endpoint_id was filled in. The field you set on the customer or supplier record (Customers and suppliers) is now carried over.
endpoint_id is carried under the scheme you gave it, never relabelled 0225: an identifier declared under 0208 stays under 0208 in the produced file.
Step 1: download the PDF
Retrieve the readable rendition with the invoice's identifier (the id field returned at its creation or by the invoice list). The read scope is enough.
curl https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/download \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-D - -o facture.pdf
The response is the binary file itself, as an attachment. The headers that carry the format and the file name:
HTTP/2 200
content-type: application/pdf
content-disposition: attachment; filename="INV-2026-042.pdf"; filename*=UTF-8''INV-2026-042.pdf
content-transfer-encoding: binary
The file name is repeated in both forms, transliterated ASCII (filename) and percent-encoded UTF-8 (filename*): if you parse this header, expect both parameters.
Step 2: choose another format
The same call with the format parameter returns the structured artifact. For regulatory archiving, facturx is the format that combines the readable layer and the structured data in a single file.
curl "https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/download?format=facturx" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o facture-facturx.pdf
ubl and cii return an XML document the same way (Content-Type: application/xml).
When the files are generated
- At creation: as soon as an invoice is created through the API, the four files are generated in the background, with no additional call on your part.
- On every modification: updating a draft restarts the generation of the files from the new data, in the background. Nothing is deleted first: the previous copies stay downloadable until regeneration replaces them, and a file downloaded before the modification no longer matches the invoice. If the invoice carried a PDF you provided, it stops being served:
provided_pdfgoes back tofalseandfacturx_conformanceis reset to null as soon as thePATCHlands, then regeneration replaces the file and thepdfformat now returns a Scribee rendering. Keep a copy of your PDF on your side if you need it after a modification. This does not concern the Factur-X deposited at import, which thefacturxformat keeps returning after the modification (see above): the two files have distinct origins. - At deposit: the draft's move into the lifecycle triggers one last regeneration, in the background and after the status change. The old files are not purged first, and the download serves the existing copy when there is one: a call made right after the deposit can therefore return the draft's artifact, under the final file name. Let the regeneration land before archiving, or check the content against the final invoice number.
- On demand: if the call arrives before a background generation finishes, the file is produced on the fly within the request, from the invoice's data at the time of the call. That generation only happens when no copy is attached: the download serves the existing copy whenever there is one, so a call made between a modification and the end of its regeneration may still return the previous file.
What happens next
The download does not change the lifecycle status and does not transmit anything to the PPF (Portail Public de Facturation), the Peppol network, or the recipient. It is not a pure read for all that: when the requested format has no copy attached yet, it is generated during the request, and a facturx produced that way records its conformance result (facturx_conformance) and any import errors along the way. That on-the-fly generation does not attach the file it returns: until the background job has stored a copy, every call redoes the generation and rewrites those fields. So it is not "the first call only" - it is any call that falls back to on-the-fly generation. A download served from an already-attached copy writes nothing.
You do not need to query the API to know what to download: every Webhooks notification (invoice creation, lifecycle event) carries a download object with the download URL for the four formats (pdf, facturx, ubl, cii). These URLs point to this endpoint and are called with your access token, like any other request.
The case of quotes
Quotes download in PDF only, through their own endpoint GET /api/v1/quotes/{id}/download (Quotes).
Errors and edge cases
400 Bad Request: unknown format
A format value outside the four codes returns:
{
"error": "invalid_format",
"message": "Format non supporté : xml. Formats supportés : ubl, cii, facturx, pdf"
}
Use pdf, ubl, cii, or facturx, in lowercase.
401 Unauthorized
Token missing, expired, or invalid. The response body is empty; request a new token at /oauth/token (Authentication) and replay the request.
404 Not Found
{
"error": "not_found",
"message": "La ressource demandée est introuvable"
}
Four situations produce this response, without distinguishing them - the existence of a resource outside your scope is never revealed:
- No invoice carries this identifier.
- It belongs to a workspace not linked to your application.
- It belongs to a linked workspace whose allowed-IP list excludes the address the call comes from. This route carries no
workspace_id, so the scope refusal surfaces as a404rather than a403: an integration that works from one address returns404from another. - It is a sales invoice of a company whose Scribee plan does not cover sales. Purchase invoices are never hidden this way.
Check the identifier against the workspace's invoice list.
422 Unprocessable Entity: generation not possible
{
"error": "export_failed",
"code": "operation_failed",
"message": "Le bloc tiers payeur (EXT-FR-FE-BG-02) n'est autorisé qu'en profil EXTENDED-CTC-FR ; export refusé pour éviter un document non conforme."
}
The requested file could not be produced. The message carries the exact reason the generator gave - here, a third-party payer block that is only legal in an EXTENDED-CTC-FR profile, on a ubl or cii export; that cause can no longer come from an invoice created or modified through the API, which refuses the combination at write time. Other refusals surface the same way:
- BR-FREXT rubrique sub-lines outside an EXTENDED profile, on
ublorcii; the message then names the offending line identifiers; - several invoiced object identifiers (BT-128) on one line outside the EXTENDED-CTC-FR profile, on
ublorcii; the message there too names the offending line identifiers (Issue a sales invoice); - on
ublonly and under the EXTENDED-CTC-FR profile, a line that carriespurchase_order_referencewithoutorder_line_reference, ordespatch_advice_referencewithoutdespatch_advice_line_reference: UBL cannot state one without the other. The message names the lines and suggests theciiorfacturxexport, which carry them (Issue a sales invoice); - on
facturx, a supplied PDF that could not be processed, or whose conformance was evaluated as non-compliant - see Provide your own PDF; - on
facturxand onpdf, an invoice deposited as a Factur-X whose archived file is unreadable in storage. Themessagethen states that Scribee refuses to hand back a regenerated PDF in place of the deposited file. This refusal is a storage incident to report to your Scribee contact, not a defect of the invoice: replaying the call will not fix it.
When the generator exposes no reason, the message falls back to the generic text Impossible de générer le fichier d'export.
The error key is export_failed on this route, not unprocessable_entity as on the API's other 422 responses; code is operation_failed, as everywhere else. The response never carries a details key.
A refusal caused by the invoice's content or by the PDF you supplied will reproduce identically: fix the invoice rather than replaying the call. If the error persists with no identifiable cause, report the invoice identifier to your Scribee contact.
Related pages
- Issue a sales invoice - create the invoice whose artifacts you download
- Quotes - the PDF download of quotes
- API reference: download an invoice