Create and send Factur-X documents
France onlyThe Factur-X standard is a hybrid electronic invoicing format that combines a human-readable PDF with structured XML data in a single document. This API recipe demonstrates how to create and send a Factur-X invoice and validate the document before delivery.
Prerequisites
- A JSON payload containing the document metadata and required document information.
- A Factur-X PDF containing embedded XML that complies with the EN 16931 profile.
- Banqup permissions.
- The customer connection has been created in the space and at least one delivery channel (connector) has been activated. See this recipe.
- Resource IDs:
Step 1: Create document
Step 1.1: Create document with JSON
Endpoint: documents/core/transaction/v2/spaces/{spaceId}/documents
Path parameter:
spaceId
Requires a JSON request body.
- Add the customer (connection) information in the JSON to skip the step of assigning it to the document.
curl -L -X POST 'https://{{serverURL}}/documents/core/transaction/v2/spaces/{spaceId}/documents' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"connections": [
{
"displayName": "Coffee Corner Shop",
"relationType": "CUSTOMER",
"id": "475a2266-b151-4131-98cb-4cb5fcd98bfe"
}
],
"folder": "SALES",
"status": {
"pay": "UNPAID",
"document": "AWAITING_VALIDATION"
},
"category": "INVOICE",
"metadata": {
"$schema": "https://btx.unifiedpost.com/btx/datastore/document/document_metadata/v1/document-metadata-schema.json",
"documentNumber" : "ABC250226",
"issueDate" : "2026-08-01",
"documentTotals": {
"linesNetAmount": "200.00",
"netAmount": "200.00",
"vatAmount": "40.00",
"grossAmount": "240.00",
"payableAmount": "240.00"
},
"vatDetails": [
{
"netAmount": "200.00",
"vatAmount": "40.00",
"vatPercentage": "20.00",
"vatCategory": "S"
}
]
},
"lines": [
{
"$schema": "https://btx.unifiedpost.com/btx/datastore/document/document_line/v1/document-line-schema.json",
"quantity": "1",
"unit": "EA",
"netAmount": "200.00",
"currency": "EUR",
"metadata": {
"allowances": [
{
"netAmount": "50.00"
}
]
},
"vatDetails": {
"vatCategory": "S",
"vatPercentage": "20"
},
"pricing": {
"itemNetPrice": "250.00",
"itemPriceQuantity": "1"
},
"productIdentifiers": {
"itemId": "SERV-001",
"itemDescription": "Coffee beans"
}
}
],
"retentionTime": "2029-01-14T19:58:47+02:00"
}'
Successful response:
{
"timestamps": {
"createdAt": "2026-08-31T07:54:23.828883Z",
"updatedAt": "2026-08-31T07:54:23.828883Z"
},
"lines": [
{
"id": "0a627bfa-a73d-4b75-831f-23e2f5adddf8",
"sequence": 1,
"data": {
"productIdentifiers": {
"itemId": "SERV-001",
"itemDescription": "Coffee beans"
},
"unit": "EA",
"metadata": {
"allowances": [
{
"netAmount": "50.00"
}
]
},
"quantity": "1",
"$schema": "https://btx.unifiedpost.com/btx/datastore/document/document_line/v1/document-line-schema.json",
"netAmount": "200.00",
"currency": "EUR",
"vatDetails": {
"vatCategory": "S",
"vatPercentage": "20"
},
"pricing": {
"itemNetPrice": "250.00",
"itemPriceQuantity": "1"
}
}
}
],
"customCategories": {},
"connections": [
{
"displayName": "Coffee Corner Shop",
"relationType": "CUSTOMER",
"id": "475a2266-b151-4131-98cb-4cb5fcd98bfe"
}
],
"id": "06fff03f-41c5-4bdc-b484-b4ee1d2b2546",
"spaceId": "a2a801ff-41d8-40c5-9911-035c0cce8b47",
"folder": "SALES",
"status": {
"pay": "UNPAID",
"document": "AWAITING_VALIDATION"
},
"category": "INVOICE",
"metadata": {
"$schema": "https://btx.unifiedpost.com/btx/datastore/document/document_metadata/v1/document-metadata-schema.json",
"documentNumber": "ABC250226",
"issueDate": "2026-08-01",
"documentTotals": {
"linesNetAmount": "200.00",
"netAmount": "200.00",
"vatAmount": "40.00",
"grossAmount": "240.00",
"payableAmount": "240.00"
},
"vatDetails": [
{
"netAmount": "200.00",
"vatAmount": "40.00",
"vatPercentage": "20.00",
"vatCategory": "S"
}
]
},
"tags": [],
"retentionTime": "2029-01-14T17:58:47Z",
"readOnly": false
}
Step 1.2: Create document representation
Endpoint:
/documents/core/transaction/v1/spaces/{spaceId}/documents/{documentId}/representations
Path parameters:
spaceIddocumentId
Requires a JSON request body.
- Set the type to
fr.ctc:factur-x-en16931to create a Factur-X representation. - The representation uses
application/pdfbecause the Factur-X XML is embedded in the PDF.
curl -L -X POST 'https://{{serverURL}}/documents/core/transaction/v1/spaces/{spaceId}/documents/{documentId}/representations' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"fileSize": 32184,
"retentionTime": "2029-01-14T19:58:47+02:00",
"type": "fr.ctc:factur-x-en16931",
"filename": "sales_invoice.pdf",
"contentType": "application/pdf",
"main": true,
"original": true
}'
Successful response:
{
"id": "1ac258e4-1cbc-4bd3-94fc-b669034ec39b",
"documentId": "06fff03f-41c5-4bdc-b484-b4ee1d2b2546",
"retentionTime": "2029-01-14T19:58:47+02:00",
"type": "fr.ctc:factur-x-en16931,
"filename": "sales_invoice.pdf",
"contentType": "application/pdf",
"size": 32184,
"metadata": {
"trace-context": "500edbcb8e5932222061a92928a74e8a-45c995c9740a9fcf-0"
},
"status": "AWAITING_UPLOAD",
"main": true,
"uploadUrl": "https://storage.googleapis.com/gcs-hjctqakd-eu-datastore-dev/pending/a2a801ff-41d8-40c5-9911-035c0cce8b47/06fff03f-41c5-4bdc-b484-b4ee1d2b2546/1ac258e4-1cbc-4bd3-94fc-b669034ec39b?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=sw-btxdata-a8cd63-dev-eu%40pj-bu-btxdata-dev-eu.iam.gserviceaccount.com%2F20260831%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260831T075517Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=31077d51395bf6bbab0f959d96847efb612d3c5bc9b1b4d0e8227d9b095738ba7afa9c319b6b7f8eb295703c727977791ff6439e973c2a71a7a34a1c957de4465b5a756d9e05a0d6d38506f30e9d98494dcada8d846d2e0ced8177624169b73962cd1237f26d37fae45e9d773b6aefa66ca796293c81d8c0b1a134286d6672d36fcfbd446c093698feb005aa4785528fdc40594b0f21f46c2d8790da3dde254e037ad0906f5807bcab0ff24488e481ed697129cfaf25ad04f26f9c51bab1ac580ec63937106d941b3e1818dd0f973a0cb1afcd0ac05fece968843e01c7491576c61fbaadd7b73ce1b79295d2d926e6b11181fae0900f7451cadcb39f402f3e22",
"createdAt": "2026-08-31T07:55:17.237956Z",
"updatedAt": "2026-08-31T07:55:17.237956Z",
"original": true
}
Step 1.3: Upload PDF
Endpoint: /uploadUrl (returned in the response of the previous step).
The uploadUrl is a presigned URL in GCP (Google Cloud Platform) which allows users to temporarily and securely access bucket resources for upload.
Request body: Binary PDF file content. Use application/pdf.
curl -L -X PUT "$UPLOAD_URL" \
-H 'Content-Type: application/pdf' \
--data-binary '@sales_invoice.pdf'
Successful response: The file is uploaded successfully.
The generated uploadUrl is time-limited. Delayed background jobs or uploads outside its validity window will fail at the storage layer. Do not store URLs for deferred processing—always request a fresh URL immediately before initiating the file transfer.
Step 1.4: Assign customer to document (optional)
If you didn't add the customer connection when creating the document, assign it to the document in this step. Otherwise, skip to Step 2.
Endpoint: /documents/core/transaction/v2/spaces/{spaceId}/documents/{documentId}:assignConnection
Path parameter:
spaceIddocumentId
Requires a JSON request body.
Add the customer's connection ID in the request body.
curl -L 'https://{{serverURL}}/documents/core/transaction/v2/spaces/{spaceId}/documents/{documentId}:assignConnection' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"id": "475a2266-b151-4131-98cb-4cb5fcd98bfe",
"relationType": "CUSTOMER"
}'
Successful response: The customer has been assigned successfully to the document.
Step 2: Validate document
Endpoint: /connectors/core/v1/spaces/{spaceId}/documents/{documentId}:validate
Path parameter:
spaceIddocumentId
Requires a JSON request body.
dryRun=true: Validates the document and saves results without altering document status or triggering lifecycle/space events.dryRun=false: Runs full validation, transitions status to VALIDATED, and triggers all lifecycle and space events. (Returns 202 immediately if already VALIDATED.)
curl -L 'https://{{serverURL}}/connectors/core/v1/spaces/{spaceId}/documents/{documentId}:validate' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"dryRun": false
}'
Successful response:
- 202 Accepted indicates the validation request was successfully accepted into the queue - it does not confirm that the document was validated.
- If you need to check the document status, use this endpoint.
Step 3: Send document
Endpoint: /documents/core/v2/spaces/{spaceId}/documents/{documentId}:send
Path parameter:
spaceIddocumentId
- The request defaults to stored identifiers and the first viable connector (unless
connectorOverrideis set). - Reprocessing triggers automatically if the confirmed participant ID differs from the stored ID.
curl -L -X POST 'https://{{serverURL}}/documents/core/v2/spaces/{spaceId}/documents/{documentId}:send' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d ''
Successful response:
- 202 Accepted indicates the delivery request was successfully accepted into the queue — it does not confirm that the document was delivered.
- Final delivery status, failures, and updates must be monitored asynchronously through document lifecycle events.