France E-Invoice & E-Reporting Factur-X
How to get “API Key” from Portal ?
To obtain the API key to be used in the request body of the login endpoint, navigate to Settings > ERP Management > API Management in the Portal and use the "Generate" button.
Login and Authorization Configuration
Technical Details
| Property | Value |
|---|---|
| Endpoint | /auth/login |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | None (Initial access) |
Request Body (JSON)
The following fields are used to define login criteria:
| Field | Type | Description |
|---|---|---|
| apiKey | String | A unique key assigned specifically to the user for portal access, verifying the system identity. (it is explained in previous section “How to get API Key from portal”) |
| String | The registered email address in the system belonging to the authorized user performing the operation. |
Response Details
Upon a successful request, a 200 OK code is returned with the following details:
| Field | Type | Description |
|---|---|---|
| jwt | — | The secure session token that must be used as a 'R-Auth' API Key in all subsequent API calls. |
| expirationDate | DateTime | Indicates the exact time the session key will expire; the ERP system can use this data to manage automatic re-login processes. |
The JWT token successfully obtained during the authentication step (auth/login) acts as a key to access the secure endpoints of the APIs. After the first successful login, the JWT token obtained from the response of a successful login is used as the R-Auth value in the authorization section of other queries. This configuration ensures that every data exchange between the ERP and the portal occurs over an authenticated and secure channel.
Technical Details
| Property | Value |
|---|---|
| Key | Enter R-Auth in the Key field. |
| Value | {{apiKey}} or {{jwt}} (Copy the jwt string returned from the login endpoint.) |
| Header Setting | Navigate to the "Headers" tab of the request to be sent. |
Chorus Pro Test SIREN Guide
This guide explains how to create test SIREN numbers for the Docnova stage environment.
To view the PDF version of the guide, click the button below.
Open PDF Guide
EDI / iDoc - FR Invoices Standard Mappings
1. Introduction
This guide is structured to allow development teams to incorporate portal features into their business workflows with minimum effort and maximum compliance.
2. Authentication POST
Purpose of Use: This endpoint is utilized by ERP systems to obtain the session key (JWT Token) required to establish a secure connection and initiate data exchange with the docnova portal.
An enterprise ERP system must trigger this endpoint to receive a valid authentication token before performing actions such as transmitting invoices or querying compliance reports via the portal. The acquired token is then provided in the "Authorization" header for all subsequent API requests. This mechanism ensures that data traffic between the ERP and the portal is conducted via a secure, time-bound key rather than transmitting sensitive user credentials for every transaction.
Endpoint Information
| Property | Value |
|---|---|
| URL | /auth/login |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | Not required (public endpoint) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/auth/login' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--data-raw '{
"apiKey": "{{your_api_key}}",
"email": "user@example.com"
}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| String | Optional | User's registered email address | |
| apiKey | String | Yes | Obtained from the portal, via the settings > ERP Management > API Management menu. |
Responses
200 - Login Successful
Full Response (AccountInfo)
{
"id": "a1b2c3d4-e5f6-7890-abcd-...",
"superAdmin": false,
"companies": [
{
"id": "60ccd1a7-5348-47b2-9ef6-...",
"name": "Example Company Ltd.",
"taxNumber": "1234567890",
"vatNumber": "DE123456789",
"email": "info@examplecompany.com",
"website": "https://www.examplecompany.com",
"address": "Example Street No: 1",
"city": "Berlin",
"state": "Berlin",
"country": "DE",
"postalCode": "10115",
"phoneNumber": "+49 30 1234567",
"credit": 1000,
"userCount": 5,
"portalType": "RECHNUNG",
"mailLanguage": "DE",
"currencyCode": "EUR",
"sftp": false,
"isSubCompany": false,
"featureAllowed": true,
"participants": [
{
"id": "participant-uuid",
"peppolId": "0088:1234567890"
}
]
}
],
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expirationDate": "2026-01-30T10:30:00.000Z",
"refreshToken": "refresh-token-string",
"refreshTokenExpiration": "2026-02-28T10:30:00.000Z",
"user": {
"id": "user-uuid",
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"phoneNumber": "+49 170 1234567",
"photoUrl": "https://example.com/photo.jpg",
"mailLang": "EN",
"isSuperAdmin": false,
"lastLoginTime": "2026-01-29T10:30:00",
"featureAllowed": true
},
"mfaEnabled": false,
"mfaType": null,
"secretImageUri": null,
"lastCompanyId": "60ccd1a7-5348-47b2-9ef6-...",
"requiresRecaptchaV2": false,
"message": null,
"active": true,
"isAppLogin": false
}
Basic Response (JwtBasicResponse)
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expirationDate": "2026-01-30T10:30:00.000Z"
}
Response Fields
Account Information Fields
| Field | Type | Description |
|---|---|---|
| id | String | User unique identifier |
| superAdmin | Boolean | Whether user has super admin privileges |
| companies | Array<AuthorizedCompany> | List of companies user is authorized to access |
| jwt | String | JWT access token. Used in R-Auth header for API requests |
| expirationDate | DateTime | JWT token expiration date |
| refreshToken | String | Refresh token for obtaining new access tokens |
| refreshTokenExpiration | DateTime | Refresh token expiration date |
| user | Object | User detail information |
| mfaEnabled | Boolean | Whether multi factor authentication is enabled |
| mfaType | Enum | MFA type (GOOGLE, WHATSAPP) |
| secretImageUri | String | Google Authenticator QR code URI |
| lastCompanyId | String | Last selected company ID |
| requiresRecaptchaV2 | Boolean | Whether reCAPTCHA v2 verification is required |
| message | String | Status message (e.g., "MFA required") |
| active | Boolean | Whether user account is active |
| isAppLogin | Boolean | Whether this is a mobile app login |
Parameter Values Reference Table
currentCountry Values (Sample List)
| Value | Description |
|---|---|
| DE | Germany |
| AT | Austria |
| RO | Romania |
| KZ | Kazakhstan |
| TR | Turkey |
| FI | Finland |
| FR | France |
| IT | Italy |
| NL | Netherlands |
| ES | Spain |
| SE | Sweden |
| PL | Poland |
| BE | Belgium |
| DK | Denmark |
| NO | Norway |
| MY | Malaysia |
| SG | Singapore |
| AU | Australia |
| NZ | New Zealand |
| JP | Japan |
| EG | Egypt |
| RS | Serbia |
| GLOBAL | Global (default) |
Company Information Fields
| Field | Type | Description |
|---|---|---|
| id | String | Company unique identifier |
| name | String | Company name |
| taxNumber | String | Tax number |
| vatNumber | String | VAT number |
| String | Company email address | |
| website | String | Company website |
| address | String | Address |
| city | String | City |
| state | String | State or Region |
| country | Enum | Country code |
| postalCode | String | Postal code |
| phoneNumber | String | Phone number |
| faxNumber | String | Fax number |
| credit | Integer | Available credit |
| userCount | Integer | Total user count |
| portalType | Enum | Portal type |
| mailLanguage | Enum | Email language |
| currencyCode | String | Currency code |
| sftp | Boolean | Whether SFTP integration is active |
| isSubCompany | Boolean | Whether it's a sub company |
| featureAllowed | Boolean | Whether feature access is granted |
| participants | Array | Peppol participant information |
User Information Fields
| Field | Type | Description |
|---|---|---|
| id | String | User unique identifier |
| String | User email address | |
| firstName | String | User first name |
| lastName | String | User last name |
| phoneNumber | String | User phone number |
| photoUrl | String | User photo URL |
| mailLang | Enum | User email language |
| isSuperAdmin | Boolean | Whether user has super admin privileges |
| lastLoginTime | DateTime | Last login time |
| featureAllowed | Boolean | Whether feature access is granted |
Enum Values Reference Table
mfaType Values
| Value | Description |
|---|---|
| Google Authenticator verification | |
| WhatsApp verification |
portalType Values
| Value | Description |
|---|---|
| DEFAULT | Default portal |
| RECHNUNG | Germany main portal |
| KZ | Kazakhstan portal |
| RO | Romania portal |
| AU | Australia portal |
| AT | Austria portal |
| BE | Belgium portal |
| DK | Denmark portal |
| EG | Egypt portal |
| FI | Finland portal |
| FR | France portal |
| IT | Italy portal |
| MY | Malaysia portal |
| NL | Netherlands portal |
| NO | Norway portal |
| PL | Poland portal |
| RS | Serbia portal |
| SE | Sweden portal |
| SG | Singapore portal |
mailLanguage Values
| Value | Description |
|---|---|
| DE | German |
| EN | English |
| TR | Turkish |
| RO | Romanian |
| PL | Polish |
| FR | French |
| IT | Italian |
| ES | Spanish |
| NL | Dutch |
200 - Login Successful
Basic Response (JwtBasicResponse)
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expirationDate": "2026-01-30T10:30:00.000Z"
}
401 - Unauthorized
{
"timestamp": "2026-01-29T10:30:00.000Z",
"status": 401,
"error": "Unauthorized",
"message": "Invalid email or password"
}
403 - MFA Required
{
"id": "user-uuid",
"mfaEnabled": true,
"mfaType": "GOOGLE",
"message": "MFA verification required",
"jwt": null
}
429 - Too Many Requests
{
"timestamp": "2026-01-29T10:30:00.000Z",
"status": 429,
"error": "Too Many Requests",
"message": "Too many failed login attempts. Please try again later.",
"requiresRecaptchaV2": true
}
3. Search Processing History POST
Purpose of Use: The POST /invoice/document-process/search endpoint serves as the central monitoring and querying interface for all document processing activities within the system. Every document whether it is an invoice, credit note, or waybill that enters or leaves the platform passes through an asynchronous processing pipeline. This endpoint provides full visibility into that pipeline.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/document-process/search |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
| Required Authority | ADMIN, INCOMING_INVOICE_DISPLAY, or OUTGOING_INVOICE_DISPLAY (at least one) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/document-process/search?page=0&size=20&sort=createdAt,desc' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--data '{
"companyId": "<COMPANY_UUID>",
"createdAt": {
"from": "2024-01-01",
"to": "2026-02-28"
}
}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Unique identifier of the company to search |
| direction | String (Enum) | No | Document direction filter (INCOMING or OUTGOING) |
| source | String (Enum) | No | Source system filter |
| filename | String | No | Exact match filter by filename |
| status | String (Enum) | No | Document processing status filter |
| createdAt | Object (DateRange) | No | Creation date range filter |
| createdAt.from | String (LocalDate) | No | Start date (inclusive). Format: yyyy-MM-dd. Must be past or present |
| createdAt.to | String (LocalDate) | No | End date (inclusive). Format: yyyy-MM-dd. Must be past or present |
Query Parameters (Pagination)
| Field | Type | Default | Description |
|---|---|---|---|
| page | Integer | 0 | Page number (0 indexed) |
| size | Integer | 20 | Number of records per page (max 100) |
| sort | String | createdAt,desc | Sort field and direction. Format: field,asc|desc |
Enum Value Reference
direction Values (Document Direction)
| Value | Description |
|---|---|
| INCOMING | Incoming document |
| OUTGOING | Outgoing document |
status Values (Processing Status)
| Value | Description |
|---|---|
| PENDING | Queued and waiting for processing |
| PROCESSING | Currently being processed |
| COMPLETED | Successfully completed |
| FAILED | Processing failed (retriable) |
| SENDING_FAILED | Failed at the sending stage |
| PERMANENT_FAILED | Permanently failed (will not be retried) |
source Values (Source and Target System)
| Value | Description |
|---|---|
| ERP | ERP integration |
| PORTAL | Web portal |
| PORTAL_OCR | Portal upload via OCR |
| EMAIL_OCR | OCR via email |
| PEPPOL | Peppol network |
| SFTP | SFTP connection |
| KSEF | Poland KSeF system |
| ANAF | Romania ANAF system |
| LHDNM | Malaysia LHDNM system |
| NEMHANDEL | Denmark NemHandel |
| RS_API | Serbia API |
| ETA | Egypt ETA system |
| ERACUN | eRacun system |
| HARVEST | Harvest integration |
| SHOPIFY | Shopify integration |
| AMAZON_SP | Amazon SP API |
| EBAY | eBay integration |
| HUBSPOT | HubSpot integration |
| LAZADA | Lazada integration |
| STRIPE | Stripe integration |
| SERVICE | Internal service |
documentType Values (Document Format)
| Value | Description |
|---|---|
| PEPPOL_BIS | Peppol BIS 3.0 |
| XRECHNUNG_CII | XRechnung (CII) |
| ZUGFERD | ZUGFeRD |
| FACTUR_X | Factur X |
| CII | Cross Industry Invoice |
| CID | CID format |
| RO_EFACTURA | Romania e Factura |
| MY_INVOIS | Malaysia MyInvois |
| MY_PINT | Malaysia PINT |
| DK_OIOUBL | Denmark OIOUBL |
| EG_INVOICE | Egypt invoice |
| HR_INVOICE | Croatia invoice |
| UAE_PINT | UAE PINT |
| KZ_ESF_V2 | Kazakhstan ESF v2 |
| KSEF | Poland KSeF |
| KSEF_OFFLINE | Poland KSeF (offline) |
waybillType Values (Waybill Type)
| Value | Description |
|---|---|
| RS_WAYBILL_DESPATCH | Serbia despatch waybill |
| RS_WAYBILL_RECEIPT | Serbia receipt waybill |
| RS_APPLICATION_RESPONSE | Serbia application response |
| RO_ETRANSPORT | Romania e Transport |
Responses
200 - Successful Response
{
"content": [
{
"trackingId": "a1b2c3d4-...",
"companyId": "60ccd1a7-...",
"direction": "INCOMING",
"documentType": "XRECHNUNG",
"waybillType": null,
"source": "ERP",
"target": "PEPPOL",
"status": "COMPLETED",
"filename": "invoice_2024_001.xml",
"invoiceNumber": "INV-2024-001",
"documentId": "f5e6d7c8-...",
"sendingResult": "OK",
"errorType": null,
"errors": null,
"additionalData": null,
"createdAt": "2024-06-15T10:30:00",
"statusUpdatedAt": "2024-06-15T10:30:45",
"completedAt": "2024-06-15T10:31:00"
}
],
"totalElements": 150,
"totalPages": 8,
"number": 0,
"size": 20
}
Response Fields
| Field | Type | Description |
|---|---|---|
| content | Array<Object> | Page content (document processing records) |
| content[].trackingId | UUID | Processing tracking identifier |
| content[].companyId | UUID | Company identifier |
| content[].direction | String (Enum) | Document direction (INCOMING / OUTGOING) |
| content[].documentType | String (Enum) | Document format (see documentType enum table) |
| content[].waybillType | String (Enum) | null | Waybill type (only for waybill documents) |
| content[].source | String (Enum) | Source system of the document |
| content[].target | String (Enum) | null | Target system for the document |
| content[].status | String (Enum) | Current processing status |
| content[].filename | String | Original filename |
| content[].invoiceNumber | String | null | Invoice number |
| content[].documentId | UUID | null | Associated document identifier |
| content[].sendingResult | String | null | Sending result message |
| content[].errorType | String (Enum) | null | Error type code (on failed processes) |
| content[].errors | Object | null | Error details (validation errors, message list, or text) |
| content[].additionalData | Object | null | Country or document type specific metadata |
| content[].createdAt | String (DateTime) | Creation timestamp. Format: yyyy-MM-ddTHH:mm:ss |
| content[].statusUpdatedAt | String (DateTime) | Last status update timestamp |
| content[].completedAt | String (DateTime) | null | Completion timestamp (only when COMPLETED) |
| totalElements | Long | Total number of matching records |
| totalPages | Integer | Total number of pages |
| number | Integer | Current page number (0-indexed) |
| size | Integer | Number of records per page |
400 - Bad Request
Trigger: When the companyId field is sent as null in the request body (@NotNull validation) or when required fields are missing.
Scenario: Sending a request without providing companyId.
{
"errorMessage": "Document process required fields: companyId",
"errorType": "DOCUMENT_PROCESS_REQUIRED_FIELDS",
"errorTitle": "BAD_REQUEST",
"errorId": "corr-8f2a1b3c",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/document-process/search"
}
400 - Bad Request
Trigger: When the request body JSON format is malformed, an invalid enum value is sent, or the date format is incorrect.
Scenario: Sending a value like "UNKNOWN_STATUS" that is not defined in the enum for the status field, or sending an invalid date like "2024-13-45" for the createdAt.from field.
{
"errorMessage": "Invalid request. Cannot deserialize value of type `DocumentProcessStatus` from String \"UNKNOWN_STATUS\"",
"errorType": "INVALID_REQUEST",
"errorTitle": "BAD_REQUEST",
"errorId": "corr-4d5e6f7a",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/document-process/search"
}
401 - Unauthorized
Trigger: When the R-Auth header is not provided or the JWT token signature is invalid. This error is caught at the Spring Security filter chain and does not reach the RestExceptionHandler.
Scenario: Sending a request without the header or with a corrupted/tampered token.
{
"error": "Unauthorized",
"message": "Full authentication is required to access this resource",
"status": 401
}
401 - Unauthorized
Trigger: When the JWT token is valid but the user does not have any of the ADMIN, INCOMING_INVOICE_DISPLAY, or OUTGOING_INVOICE_DISPLAY authorities on the specified companyId. Thrown by AuthorizationService.checkAnyAuthorityByCompanyAndUser().
Scenario: Performing a search with a companyId for which the user has no access permissions.
{
"errorMessage": "User is not authorized for this operation",
"errorType": "AUTHORIZATION_FAILED",
"errorTitle": "UNAUTHORIZED",
"errorId": "corr-9a8b7c6d",
"status": 401,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/document-process/search"
}
404 - Not Found
Trigger: When the provided companyId value is not found in the database. A NotFoundException is thrown by CompanyService.
Scenario: Sending a UUID as companyId that has been deleted or never existed.
{
"errorMessage": "Company not found!",
"errorType": "COMPANY_NOT_FOUND",
"errorTitle": "NOT_FOUND",
"errorId": "corr-1b2c3d4e",
"status": 404,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/document-process/search"
}
498 - Token Expired
Trigger: When the JWT token has expired. Returned by CustomAuthenticationEntryPoint at the Spring Security filter level.
Scenario: Sending a request with an expired JWT token.
{
"errorMessage": "Your session has expired. Please login again.",
"errorType": "TOKEN_EXPIRED",
"errorTitle": "UNAUTHORIZED",
"status": null,
"timestamp": null,
"path": null
}
Note: Since this response is generated at the Security filter level, the timestamp, path, and status fields are not populated by enrichResponse and return null. A custom HTTP status code of 498 is used.
500 - Internal Server Error
Trigger: When an unexpected error occurs on the server side (database connection failure, NullPointerException, etc.). Caught by the RestExceptionHandler catch-all handler.
Scenario: Database access failure, unexpected runtime exception.
{
"errorMessage": "An unexpected error occurred",
"errorType": "SERVER_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "corr-5e6f7a8b",
"status": 500,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/document-process/search"
}
Response Structure Reference (ExceptionResponse)
| Field | Type | Description | Inclusion Condition |
|---|---|---|---|
| errorMessage | String | Human readable error description | Always |
| errorType | String | Machine readable error code (ErrorType enum name) | Always |
| errorTitle | String (HttpStatus) | HTTP status description (BAD_REQUEST, UNAUTHORIZED, etc.) | Always |
| errorId | String | Correlation ID (for log tracing) | If present in ThreadContext |
| status | Integer | HTTP status code (numeric) | Always |
| timestamp | String (DateTime) | Timestamp when the error occurred | By RestExceptionHandler |
| path | String | URI of the request | By RestExceptionHandler |
| data | String | Additional data information | If present (@JsonInclude NON_NULL) |
| details | Map<String, Object> | Additional detail information | If present (@JsonInclude NON_NULL) |
| validationErrors | Array<ValidationError> | Field level validation errors | If present (@JsonInclude NON_NULL) |
Note: The ExceptionResponse class uses @JsonInclude(JsonInclude.Include.NON_NULL). Therefore, fields with null values are excluded from the JSON response.
4. Send Document Async POST
Purpose of Use: This endpoint enables ERP systems to transmit e-invoice data to the docnova portal asynchronously. It is designed to enhance system responsiveness and efficiently manage the process queue during high-volume data transfers.
After generating an invoice in compliance with German legal standards (XRechnung or ZUGFeRD), the ERP system converts the document into base64 format and transmits it to the portal. Since this method operates asynchronously, the ERP system receives a tracking ID (trackingId) without waiting for the full processing of the document. This prevents delays in ERP-side workflows, and the final status of the document can be queried later using the provided tracking ID.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/send-document-async |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | JWT Token (R-Auth header) or API Key |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/send-document-async' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: {{jwt_token}}' \
--data-raw '{
"apiKey": "{{your_api_key}}",
"base64Document": "{{base64_encoded_xml}}",
"base64Pdf": "{{base64_encoded_pdf}}",
"businessType": "B2B",
"compId": "{{company_uuid}}",
"invoiceSource": "PORTAL",
"invoiceType": "ZUGFERD",
"receiverEmails": [
"recipient@example.com"
],
"mailTemplateId": "{{template_id}}"
}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| compId | String (UUID) | Conditional* | Company unique identifier. Required if apiKey is not provided. |
| apiKey | String | Conditional* | API key. Required if compId is not provided. |
| base64Document | String | Conditional** | Base64-encoded XML document. Required if base64Pdf is not provided. |
| base64Pdf | String | Conditional** | Base64-encoded PDF document. Required if base64Document is not provided. |
| invoiceType | Enum | Conditional*** | Invoice format type. Required if waybillType is not provided. |
| waybillType | Enum | Conditional*** | Waybill format type. Required if invoiceType is not provided. |
| businessType | Enum | No | Business model type (B2B, B2C, B2G). |
| invoiceSource | Enum | No | Document source. |
| receiverEmails | Array<String> | No | List of recipient email addresses. |
| mailTemplateId | String | No | Email template identifier. |
Note:
- (*) At least one of compId or apiKey must be provided.
- (**) At least one of base64Document or base64Pdf must be provided.
- (***) At least one of invoiceType or waybillType must be provided.
businessType Values
| Value | Description |
|---|---|
| B2B | Business to Business |
| B2C | Business to Consumer |
| B2G | Business to Government |
invoiceSource Values
| Value | Description |
|---|---|
| PORTAL | Submission via web portal |
| PORTAL_OCR | Portal with OCR processing |
| Via email | |
| EMAIL_OCR | Email with OCR processing |
| ERP | ERP system integration |
| PEPPOL | Via Peppol network |
| LHDNM | Malaysia LHDNM system |
| NEMHANDEL | Denmark NemHandel |
| SERVICE | Service integration |
| HARVEST | Harvest integration |
| SHOPIFY | Shopify integration |
| AMAZON_SP | Amazon SP-API integration |
| EBAY | eBay integration |
| HUBSPOT | HubSpot integration |
| ANAF | Romania ANAF system |
| LAZADA | Lazada integration |
| SFTP | Via SFTP |
| KSEF | Poland KSeF system |
| RS_API | Serbia API |
| ETA | Egypt ETA system |
| ERACUN | Indonesia e-Racun |
| STRIPE | Stripe integration |
invoiceType Values
| Value | Group | Description |
|---|---|---|
| PEPPOL_BIS | XRECHNUNG | Peppol BIS 3.0 format |
| XRECHNUNG | XRECHNUNG | German XRechnung format |
| RO_EFACTURA | XRECHNUNG | Romania e-Factura format |
| ZUGFERD | ZUGFERD | ZUGFeRD format (PDF/A-3 with XML) |
| FACTUR_X | ZUGFERD | Factur-X format (France) |
| XRECHNUNG_CII | ZUGFERD | XRechnung CII profile |
| CII | ZUGFERD | Cross Industry Invoice format |
| CID | ZUGFERD | CID format |
| ZUGFERD | PDF format | |
| MY_INVOIS | Country-Specific | Malaysia MyInvois format |
| MY_PINT | Country-Specific | Malaysia PINT format |
| DK_OIOUBL | Country-Specific | Denmark OIOUBL format |
| EG_INVOICE | Country-Specific | Egypt e-Invoice format |
| HR_INVOICE | Country-Specific | Croatia e-Invoice format |
| UAE_PINT | Country-Specific | UAE PINT format |
| KZ_ESF_V2 | Kazakhstan | Kazakhstan ESF v2 |
| KSEF | Poland | Poland KSeF format |
| KSEF_OFFLINE | Poland | Poland KSeF offline |
waybillType Values
| Value | Description |
|---|---|
| RS_WAYBILL_DESPATCH | Serbia despatch waybill |
| RS_WAYBILL_RECEIPT | Serbia receipt waybill |
| RS_APPLICATION_RESPONSE | Serbia application response |
| RO_ETRANSPORT | Romania e-Transport |
Responses
200 - Successful Response
{
"trackingId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": "PENDING",
"message": "Document queued for processing"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| trackingId | UUID | Unique process tracking identifier. This ID can be used to query the processing status. |
| status | Enum | Current status of the process. |
| message | String | Descriptive message about the status. |
status Values
| Value | Description |
|---|---|
| PENDING | Process queued, not yet started |
| PROCESSING | Process in progress |
| COMPLETED | Process completed successfully |
| FAILED | Process failed |
| SENDING_FAILED | Sending failed |
| PERMANENT_FAILED | Permanent failure, will not be retried |
400 - Bad Request
{
"trackingId": null,
"status": "FAILED",
"message": "Either invoiceType or waybillType must be provided"
}
401 - Unauthorized
{
"timestamp": "2026-01-29T10:30:00.000Z",
"status": 401,
"error": "Unauthorized",
"message": "Invalid or expired token"
}
500 - Internal Server Error
{
"trackingId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "FAILED",
"message": "An unexpected error occurred"
}
5. Send Document Async JSON POST
Purpose of Use: This endpoint allows invoice data compliant with UBL 2.1 / PEPPOL BIS standards to be submitted asynchronously as a JSON object (ublDto). No base64-encoded file upload is required; all invoice details are provided directly in a structured JSON format.
When the request is accepted, the document is placed in the processing queue and a trackingId is returned. The processing status can be queried at any time using this ID via the /invoice/document-status/{trackingId} endpoint.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/send-document-async-json |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/send-document-async-json' \
--header 'accept: */*' \
--header 'R-Auth: eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJNTU0iLCJzdWIiOiJsYmxyRWNuT2JZUVN3KzNtQ29yM1RJSGFLOFQ4UmlwTGlwai9QREtkVk9pNktPazNSOEhldEdES0FQNzJoQStwV00rZUJLREtLWmpZWXBEN1pzK3JCZz09IiwiY2xhaW0iOiJJU0dXSXIvb2F3elUrdnVPK1FleWx4UzUrL280NnhNR3lFdXE2ZDVyaEpuRjNVRW1xVFRya01uUTRzZng5ZmhQWklyOW1Qb3lIUVV4RnpYMU82WkpndkVoVkRoTElWV2F4L1JCNUVVY0xUaz0iLCJ1c2VyVHlwZSI6IkNMSUVOVCIsImV4cCI6MTc4MjIxNzIyMX0.gg4J1DZ8URY5DrFApiPZ81Pb_QmLMn9W16PppRA1dv7syxbmRQakPYs8w4Op-WVf64SgPtBDCaoNL1d2bZ3O0g' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiKey": "tBhGHW7gREjwJ0AGcAK5GNO8pWORIjw4",
"businessType": "B2B",
"ublDto": {
"UBLVersionID": {
"Value": "2.1",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"CustomizationID": {
"Value": "urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"ProfileID": {
"Value": "B1",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"ID": {
"Value": "35000205577",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"IssueDate": {
"Value": "2025-01-17"
},
"DueDate": {
"Value": "2025-01-17"
},
"InvoiceTypeCode": {
"Value": "380",
"listAgencyID": "",
"listID": "",
"listVersionID": "",
"name": ""
},
"Note": [
{
"Value": "BANQUE POPULAIRE AUVERGNE RHÔNE ALPES IBAN : FR76 1680 7004 0082 0722 9721 667 SWIFT : CCBPFRPPGRE"
}
],
"TaxPointDate": {
"Value": "2026-06-17"
},
"DocumentCurrencyCode": {
"Value": "EUR",
"listAgencyID": "",
"listID": "",
"listVersionID": "",
"name": ""
},
"CompanyId": "b7844db0-57a1-4f5d-af65-...",
"Format": "EASY_INVOICE",
"Type": "FR_UBL_CIUS",
"ProfileType": "EN16931",
"IsPeppolParticipant": false,
"PeppolParticipantId": "",
"OrderReference": {
"ID": {
"Value": "969118",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"SalesOrderID": {
"Value": "0000969118",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
},
"AccountingSupplierParty": {
"Party": {
"EndpointID": {
"Value": "271688503",
"schemeID": "0002",
"schemeAgencyID": "",
"schemeAgencyName": ""
},
"PartyName": [
{
"Name": {
"Value": "Kerakoll France"
}
}
],
"PostalAddress": {
"StreetName": {
"Value": "Avenue de l'\''industrie"
},
"BuildingNumber": {
"Value": "25"
},
"CityName": {
"Value": "Corbas Cedex"
},
"PostalZone": {
"Value": "69964"
},
"Country": {
"IdentificationCode": {
"Value": "FR",
"listAgencyID": "",
"listID": "",
"listVersionID": ""
}
}
},
"PartyTaxScheme": [
{
"CompanyID": {
"Value": "FR99271688503",
"schemeID": "",
"schemeAgencyID": "",
"schemeAgencyName": ""
},
"TaxScheme": {
"ID": {
"Value": "VAT",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
}
}
],
"PartyLegalEntity": [
{
"RegistrationName": {
"Value": "Kerakoll France"
},
"CompanyID": {
"Value": "FR99271688503",
"schemeID": "",
"schemeAgencyID": "",
"schemeAgencyName": ""
},
"CompanyLegalForm": null
}
],
"Contact": {
"Name": {
"Value": "Kerakoll France"
},
"ElectronicMail": null,
"Telephone": null
}
}
},
"AccountingCustomerParty": {
"Party": {
"EndpointID": {
"Value": "142057869",
"schemeID": "0002",
"schemeAgencyID": "",
"schemeAgencyName": ""
},
"PartyName": [
{
"Name": {
"Value": "PLATTARD CARRELAGES-VILLEFRANCHE"
}
}
],
"PostalAddress": {
"StreetName": {
"Value": "3027008449225"
},
"AdditionalStreetName": null,
"CityName": {
"Value": "VILLEFRANCHE SUR SAONE"
},
"PostalZone": {
"Value": "69654"
},
"Country": {
"IdentificationCode": {
"Value": "FR",
"listAgencyID": "",
"listID": "",
"listVersionID": ""
}
}
},
"PartyTaxScheme": [
{
"CompanyID": {
"Value": "FR99142057869",
"schemeID": "",
"schemeAgencyID": "",
"schemeAgencyName": ""
},
"TaxScheme": {
"ID": {
"Value": "VAT",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
}
}
],
"PartyLegalEntity": [
{
"RegistrationName": {
"Value": "PLATTARD CARRELAGES-VILLEFRANCHE"
},
"CompanyID": null,
"CompanyLegalForm": null
}
],
"Contact": {
"Name": {
"Value": "PLATTARD CARRELAGES-VILLEFRANCHE"
},
"Telephone": {
"Value": "0478801221"
},
"ElectronicMail": {
"Value": "jeremy-gandois@plattard.com"
}
}
}
},
"PaymentMeans": [
{
"PaymentMeansCode": {
"Value": "42",
"listAgencyID": "",
"listID": "",
"listVersionID": "",
"name": ""
},
"PayeeFinancialAccount": null
}
],
"TaxTotal": [
{
"TaxAmount": {
"Value": "15.76",
"currencyID": "EUR"
},
"TaxSubtotal": [
{
"TaxableAmount": {
"Value": "78.81",
"currencyID": "EUR"
},
"TaxAmount": {
"Value": "15.76",
"currencyID": "EUR"
},
"TaxCategory": {
"ID": {
"Value": "S",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"Percent": {
"Value": "20",
"format": ""
},
"TaxScheme": {
"ID": {
"Value": "VAT",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
}
}
}
]
}
],
"LegalMonetaryTotal": {
"LineExtensionAmount": {
"Value": "78.81",
"currencyID": "EUR"
},
"TaxExclusiveAmount": {
"Value": "78.81",
"currencyID": "EUR"
},
"TaxInclusiveAmount": {
"Value": "94.57",
"currencyID": "EUR"
},
"AllowanceTotalAmount": {
"Value": "",
"currencyID": "EUR"
},
"ChargeTotalAmount": {
"Value": "",
"currencyID": "EUR"
},
"PrepaidAmount": {
"Value": "",
"currencyID": "EUR"
},
"PayableAmount": {
"Value": "94.57",
"currencyID": "EUR"
}
},
"InvoiceLine": [
{
"ID": {
"Value": "10",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"InvoicedQuantity": {
"Value": "12.000",
"unitCode": "KGM"
},
"LineExtensionAmount": {
"Value": 41.86,
"currencyID": "EUR"
},
"Item": {
"Name": {
"Value": "K0001E.01"
},
"Description": null,
"ClassifiedTaxCategory": [
{
"ID": {
"Value": "S",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"Percent": {
"Value": "20",
"format": ""
},
"TaxScheme": {
"ID": {
"Value": "VAT",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
}
}
]
},
"Price": {
"PriceAmount": {
"Value": "3.4883",
"currencyID": "EUR"
},
"BaseQuantity": null
}
},
{
"ID": {
"Value": "20",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"InvoicedQuantity": {
"Value": "12.000",
"unitCode": "KGM"
},
"LineExtensionAmount": {
"Value": 36.95,
"currencyID": "EUR"
},
"Item": {
"Name": {
"Value": "K0001I.01"
},
"Description": null,
"ClassifiedTaxCategory": [
{
"ID": {
"Value": "S",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
},
"Percent": {
"Value": "20",
"format": ""
},
"TaxScheme": {
"ID": {
"Value": "VAT",
"schemeAgencyID": "",
"schemeAgencyName": "",
"schemeID": ""
}
}
}
]
},
"Price": {
"PriceAmount": {
"Value": "3.0792",
"currencyID": "EUR"
},
"BaseQuantity": null
}
}
],
"BillingReference": null,
"AdditionalDocumentReference": null,
"AllowanceCharge": null,
"Delivery": null,
"BuyerReference": null,
"PartnerUuid": "e960da1f-4240-44d0-9070-...",
"DraftUuid": "",
"ExternalInvoiceId": "",
"InvoiceUuid": "",
"OcrUuid": "",
"LeitwegId": "",
"ehfNorwayForetaksregisteret": false,
"ehfNorwayPaymentAccountKind": "BBAN"
}
}
'
Request Parameters
Body Parameters
Root Object
| Field Name | Type | Required | Description |
|---|---|---|---|
| apiKey | string | Conditional | API key used to identify the company. Required if ublDto.CompanyId is not provided. |
| ublDto | object (UBLDto) | Yes | UBL 2.1 compliant invoice data structure containing all invoice details. |
ublDto — Document Object
| Field Name | Type | Required | Description |
|---|---|---|---|
| ublDto.Type | string (enum) | Optional | Document format type. E.g.: PEPPOL_BIS, XRECHNUNG, ZUGFERD. See Parameter Values Reference table for full list. |
| ublDto.IsPeppolParticipant | boolean | Optional | Indicates whether the recipient is registered on the Peppol network. If true, the document is routed via Peppol. |
| ublDto.CompanyId | string (UUID) | Conditional | UUID of the sending company. Required if apiKey is not provided. |
| ublDto.ProfileType | string (enum) | Optional | ZUGFeRD / Factur-X profile type. Default: EN16931. |
| ublDto.CustomizationID.Value | string | Optional | Invoice customization identifier (urn value). Specifies PEPPOL / EN16931 compliance. |
| ublDto.ID.Value | string | Optional | Invoice number / unique document identifier. |
| ublDto.IssueDate.Value | string (ISO 8601) | Optional | Invoice issue date. Format: YYYY-MM-DD. |
| ublDto.DueDate.Value | string (ISO 8601) | Optional | Invoice due date. Format: YYYY-MM-DD. |
| ublDto.InvoiceTypeCode.Value | string | Optional | UN/CEFACT invoice type code. E.g.: 380 = Commercial Invoice, 381 = Credit Note, 384 = Corrected Invoice. |
| ublDto.Note[].Value | string | Optional | Free-text note attached to the invoice. |
| ublDto.DocumentCurrencyCode.Value | string | Optional | Invoice currency code (ISO 4217). E.g.: EUR, USD, GBP. |
| ublDto.BuyerReference.Value | string | Optional | Buyer reference number (Buyer Reference / Leitweg-ID). |
| ublDto.OrderReference.ID.Value | string | Optional | Purchase order number. |
| ublDto.OrderReference.SalesOrderID.Value | string | Optional | Sales order number. |
| ublDto.AccountingSupplierParty | object | Optional | Supplier / seller information. The Party object contains EndpointID (Peppol ID), PartyName, PostalAddress, PartyTaxScheme, PartyLegalEntity, and Contact sub-objects. |
| ublDto.AccountingSupplierParty.Party.EndpointID.Value | string | Optional | Supplier's Peppol Endpoint ID value. |
| ublDto.AccountingSupplierParty.Party.EndpointID.schemeID | string | Optional | Endpoint ID scheme code. E.g.: 9930 = German Tax No, 0088 = GLN. |
| ublDto.AccountingCustomerParty | object | Optional | Customer / buyer information. The Party object contains EndpointID, PartyName, PostalAddress, PartyTaxScheme, PartyLegalEntity, and Contact sub-objects. |
| ublDto.Delivery[].ActualDeliveryDate.Value | string (ISO 8601) | Optional | Actual delivery date. Format: YYYY-MM-DD. |
| ublDto.Delivery[].DeliveryLocation.Address | object | Optional | Delivery address. Contains StreetName, CityName, PostalZone, and Country sub-fields. |
| ublDto.PaymentMeans[].PaymentMeansCode.Value | string | Optional | Payment method code. E.g.: 58 = SEPA Credit Transfer, 30 = Credit Transfer, 49 = Direct Debit. |
| ublDto.PaymentMeans[].PayeeFinancialAccount.ID.Value | string | Optional | Payee bank account IBAN number. |
| ublDto.PaymentMeans[].PayeeFinancialAccount.Name.Value | string | Optional | Bank account holder name. |
| ublDto.PaymentTerms[].Note[].Value | string | Optional | Free-text description of payment terms. |
| ublDto.TaxTotal[].TaxAmount.Value | number | Optional | Total tax amount. |
| ublDto.TaxTotal[].TaxAmount.currencyID | string | Optional | Currency code for the tax amount (ISO 4217). |
| ublDto.TaxTotal[].TaxSubtotal[].TaxableAmount.Value | number | Optional | Taxable base amount. |
| ublDto.TaxTotal[].TaxSubtotal[].TaxCategory.ID.Value | string | Optional | Tax category code. E.g.: S = Standard, Z = Zero Rated, E = Exempt, AE = Reverse Charge. |
| ublDto.TaxTotal[].TaxSubtotal[].TaxCategory.Percent.Value | number | Optional | Tax rate percentage. E.g.: 19, 7, 10. |
| ublDto.LegalMonetaryTotal.LineExtensionAmount.Value | number | Optional | Sum of invoice line net amounts (excluding tax). |
| ublDto.LegalMonetaryTotal.TaxExclusiveAmount.Value | number | Optional | Total amount excluding VAT. |
| ublDto.LegalMonetaryTotal.TaxInclusiveAmount.Value | number | Optional | Total amount including VAT. |
| ublDto.LegalMonetaryTotal.PayableAmount.Value | number | Optional | Net payable amount. |
| ublDto.InvoiceLine[].ID.Value | string | Optional | Invoice line sequence number. |
| ublDto.InvoiceLine[].InvoicedQuantity.Value | number | Optional | Invoiced quantity. |
| ublDto.InvoiceLine[].InvoicedQuantity.unitCode | string | Optional | Unit of measure code (UN/ECE Rec. 20). E.g.: MTQ = Cubic Metre, C62 = Each, KGM = Kilogram. |
| ublDto.InvoiceLine[].LineExtensionAmount.Value | number | Optional | Invoice line net amount (excluding tax). |
| ublDto.InvoiceLine[].Item.Name.Value | string | Optional | Product / service name. |
| ublDto.InvoiceLine[].Item.SellersItemIdentification.ID.Value | string | Optional | Seller's item/product code. |
| ublDto.InvoiceLine[].Price.PriceAmount.Value | number | Optional | Unit price. |
| ublDto.InvoiceLine[].Price.BaseQuantity.Value | number | Optional | Base quantity the price applies to. Typically 1. |
| receiverEmails | array (string) | Optional | Recipient email addresses for sending the invoice via email after processing. |
| mailTemplateId | string | Optional | Custom mail template ID to be used for email delivery. |
| businessType | string (enum) | Optional | Business model type: B2B, B2C, or B2G. |
Notes:
- At least one of apiKey or ublDto.CompanyId must be provided. Both cannot be null simultaneously.
- When ublDto.CompanyId is not provided, the system resolves the company via the apiKey.
- For AccountingSupplierParty and AccountingCustomerParty, the EndpointID.schemeID uses Peppol Participant Identifier Scheme codes (e.g.: 9930 = German Tax No, 0088 = GLN, 0184 = Danish CVR).
- InvoiceLine[].InvoicedQuantity.unitCode uses UN/ECE Recommendation 20 unit codes (e.g.: MTQ = Cubic Metre, C62 = Each, KGM = Kilogram, LTR = Litre).
Responses
200 - Successful Response
Request accepted successfully. The document has been placed in the processing queue. Use the returned trackingId to query processing status at /invoice/document-status/{trackingId}.
Response body (AsyncERPResponse)
{
"trackingId": "{{entity_uuid}}",
"status": "PENDING",
"message": "Document process started successfully"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| trackingId | string (UUID) | Document processing tracking ID. Used in the /invoice/document-status/{trackingId} endpoint. |
| status | string (enum) | Immediate processing status of the document. Returns PENDING initially. |
| message | string | Informational message about the process initiation. |
Parameter Value Reference
Document Format Type (ublDto.Type)
| Value | Description |
|---|---|
| PEPPOL_BIS | PEPPOL BIS Billing 3.0 format (UBL-based) |
| XRECHNUNG | Germany XRechnung format (UBL-based) |
| ZUGFERD | ZUGFeRD format (PDF/A-3 + embedded XML) |
| FACTUR_X | France Factur-X format (PDF/A-3 + embedded XML) |
| XRECHNUNG_CII | Germany XRechnung CII format |
| CII | UN/CEFACT Cross Industry Invoice format |
| CID | Cross Industry Document format |
| MY_INVOIS | Malaysia MyInvois format |
| MY_PINT | Malaysia PINT format |
| DK_OIOUBL | Denmark OIOUBL format |
| RO_EFACTURA | Romania e-Invoice format |
| UAE_PINT | UAE PINT format |
| HR_INVOICE | Croatia invoice format |
| EG_INVOICE | Egypt invoice format |
| KSEF | Poland KSeF format |
Profile Type (ublDto.ProfileType)
| Value | Description |
|---|---|
| EN16931 | EN 16931 compliant profile (default) |
| EXTENDED | Extended profile |
| BASIC | Basic profile |
Business Model Type (businessType)
| Value | Description |
|---|---|
| B2B | Business to Business |
| B2C | Business to Consumer |
| B2G | Business to Government |
400 - Bad Request
Trigger: When both apiKey and ublDto.CompanyId are null.
Response body:
{
"errorMessage": "apiKey or companyId field is required",
"errorType": "DOCUMENT_PROCESS_REQUIRED_FIELDS",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/send-document-async-json"
}
An IllegalArgumentException is thrown when both apiKey and ublDto.CompanyId are null, returning a 400 Bad Request response.
Trigger: When the provided apiKey does not match any record in the system.
Response body:
{
"errorMessage": "Api Key Didnt Match",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/send-document-async-json"
}
An IllegalArgumentException is thrown when the apiKey provided does not match any registered company, returning a 400 Bad Request response.
401 - Unauthorized
Trigger: When the JWT token is invalid or expired, or the user is not authorized for the specified company.
Response body:
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/send-document-async-json"
}
An AuthorizationServiceException is thrown when the JWT token in the R-Auth header is invalid/expired or when the authenticated user does not have access to the specified company, returning a 401 Unauthorized response.
500 - Internal Server Error
Trigger: When an unexpected server error occurs.
Response body:
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/send-document-async-json"
}
Returns a 500 Internal Server Error when an unexpected server-side error occurs.
6. Document Status GET
Purpose of Use: The GET /invoice/document-status/{trackingId} endpoint is used to query the processing status of documents (invoices, waybills, etc.) that were submitted asynchronously.
When a document is submitted through any of the send-document-async, send-document-async-json, send-by-file-async, or send-portal-new-async endpoints, the system immediately returns a trackingId and begins processing the document in the background.
Polling stops when the status becomes COMPLETED or FAILED.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/document-status/{trackingId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/document-status/{trackingId}' \
--header 'Accept: */*' \
--header 'R-Auth: {JWT_TOKEN}'
}'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| trackingId | UUID | Yes | The tracking identifier returned from an asynchronous document submission. This is the trackingId value included in the response of send-document-async, send-document-async-json, send-by-file-async, or send-portal-new-async endpoints. |
Responses
200 - Successful Response
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": "OUTGOING",
"documentType": "FR_UBL_CIUS",
"waybillType": null,
"source": "ERP",
"target": null,
"status": "COMPLETED",
"filename": "invoice_2025.xml",
"invoiceNumber": "INV-2025-001234",
"documentId": "f47ac10b-58cc-4372-a567-...",
"sendingResult": "SUCCESS",
"errorType": null,
"errors": null,
"additionalData": null,
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:30:45",
"completedAt": "2025-06-15T10:30:45"
}
Success Response Field Descriptions
| Field | Type | Description |
|---|---|---|
| trackingId | UUID | Unique tracking identifier for the document processing |
| companyId | UUID | Unique identifier of the company the document belongs to |
| direction | String (Enum) | Document direction: INCOMING or OUTGOING |
| documentType | String (Enum) | Document format (e.g., XRECHNUNG, UBL, ZUGFERD) |
| waybillType | String (Enum) | Waybill type. Only populated for waybill operations |
| source | String (Enum) | Source platform the document was submitted from (e.g., ERP, PORTAL) |
| target | String (Enum) | null | Target platform for the document |
| status | String (Enum) | Current processing status: PENDING, PROCESSING, COMPLETED, FAILED, SENDING_FAILED, PERMANENT_FAILED |
| filename | String | Name of the processed file |
| invoiceNumber | String | null | Invoice number assigned to the document. Populated when processing completes |
| documentId | UUID | null | Unique system identifier of the created document. Populated when processing completes |
| sendingResult | String | null | Sending result (e.g., SUCCESS, SENT_TO_PEPPOL). Populated when processing completes |
| errorType | String (Enum) | null | Error category when an error occurs. Null for successful operations |
| errors | Object | null | Error details. Variable type: can be List<ValidationError>, List<String>, or String |
| additionalData | Object | Country specific additional metadata. Structure varies by country/document type (e.g., Poland KSeF: ksefNumber, Romania: submissionId) |
| createdAt | DateTime | Timestamp when the processing record was created (ISO 8601) |
| statusUpdatedAt | DateTime | Timestamp when the status was last updated (ISO 8601) |
| completedAt | DateTime | null | Timestamp when processing completed. Null while processing is ongoing |
Parameter Value Reference
DocumentProcessStatus — Possible Status Values
| Value | Description |
|---|---|
| PENDING | Document is queued, processing has not started yet |
| PROCESSING | Document is actively being processed (conversion, validation, sending, etc.) |
| COMPLETED | Document processing completed successfully |
| FAILED | An error occurred during document processing (may be retried) |
| SENDING_FAILED | Document was created but failed during the sending phase |
| PERMANENT_FAILED | Document processing permanently failed (will not be retried) |
DocumentType — Document Direction
| Value | Description |
|---|---|
| INCOMING | Incoming document |
| OUTGOING | Outgoing document |
DataType — Document Format
| Value | Description |
|---|---|
| PEPPOL_BIS | Peppol BIS 3.0 UBL format |
| XRECHNUNG | XRechnung (Germany) UBL format |
| RO_EFACTURA | Romania eFactura format |
| MY_INVOIS | Malaysia MyInvois format |
| MY_PINT | Malaysia PINT format |
| DK_OIOUBL | Denmark OIOUBL format |
| EG_INVOICE | Egypt e-Invoice format |
| HR_INVOICE | Croatia e-Invoice format |
| UAE_PINT | UAE PINT format |
| ZUGFERD | ZUGFeRD format |
| FACTUR_X | Factur-X (France) format |
| XRECHNUNG_CII | XRechnung CII format |
| CII | UN/CEFACT CII format |
| Unstructured PDF (paper invoices, images, etc.) | |
| KSEF | Poland KSeF format |
| KSEF_OFFLINE | Poland KSeF Offline format |
| KZ_ESF_V2 | Kazakhstan ESF v2 format |
InvoiceSource — Document Source
| Value | Description |
|---|---|
| ERP | Submitted via ERP integration |
| PORTAL | Submitted via web portal |
| PEPPOL | Received via Peppol network |
| Received via email | |
| SFTP | Transferred via SFTP |
| KSEF | Via KSeF system |
| ANAF | Via ANAF system (Romania) |
| ERACUN | Via eRacun system (Croatia) |
| Others | PORTAL_OCR, EMAIL_OCR, LHDNM, NEMHANDEL, SERVICE, HARVEST, SHOPIFY, AMAZON_SP, EBAY, HUBSPOT, LAZADA, RS_API, ETA, STRIPE |
WaybillDataType — Waybill Type
| Value | Description |
|---|---|
| RS_WAYBILL_DESPATCH | Serbia despatch waybill |
| RS_WAYBILL_RECEIPT | Serbia receipt waybill |
| RS_APPLICATION_RESPONSE | Serbia application response |
| RO_ETRANSPORT | Romania eTransport waybill |
ErrorType — Error Types Specific to This Endpoint
| Value | Message |
|---|---|
| INVOICE_PROCESS_NOT_FOUND | Tracking ID not found |
| VALIDATION_FAILED | Validation failed! |
| INVOICE_NULL_COULD_NOT_SAVE | Invoice is NULL and/or could not be saved! |
| ZUGFERD_VALIDATION_ERROR | ZUGFeRD validation error |
| INVOICE_CREATION_FAILED | Invoice creation failed! |
| INVOICE_SENDING_FAILED | Invoice sending failed: {details} |
401 - Unauthorized
Returned when the R-Auth header is missing, contains an invalid JWT token, or the token has expired.
{
"status": 401,
"error": "Unauthorized",
"message": "Full authentication is required to access this resource"
}
| Detail | Description |
|---|---|
| HTTP Status | 401 Unauthorized |
| Trigger | JWT token is missing, malformed, expired, or signature verification failed |
| Resolution | Send a valid, non-expired JWT token in the R-Auth header |
404 - Not Found
Returned when the provided trackingId does not exist in the database.
Response Body: null (body is empty)
| Detail | Description |
|---|---|
| HTTP Status | 404 Not Found |
| Response Body | null (body is empty) |
| Trigger | No DocumentProcessEntity record matches the given trackingId in the database |
| Internal Error Type | INVOICE_PROCESS_NOT_FOUND — "Tracking ID not found" |
| Resolution | Verify the trackingId value is correct. Use the value returned in the response of the async submission endpoint |
500 - Internal Server Error
Returned when an unexpected server error occurs during the status query.
Response Body: null (body is empty)
| Detail | Description |
|---|---|
| HTTP Status | 500 Internal Server Error |
| Response Body | null (body is empty) |
| Trigger | Database connection failure, entity conversion error, or other unexpected runtime exceptions |
| Resolution | Check server logs. Contact the support team if the issue persists |
Status-Based Response Examples
PENDING — Queued for Processing
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": null,
"documentType": "XRECHNUNG",
"status": "PENDING",
"documentId": null,
"invoiceNumber": null,
"sendingResult": null,
"errorType": null,
"errors": null,
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:30:00",
"completedAt": null
}
PROCESSING — Currently Processing
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": "OUTGOING",
"documentType": "XRECHNUNG",
"status": "PROCESSING",
"documentId": "f47ac10b-58cc-4372-a567-...",
"invoiceNumber": "INV-2025-001234",
"sendingResult": null,
"errorType": null,
"errors": null,
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:30:20",
"completedAt": null
}
FAILED — Processing Failed (Validation Error)
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": null,
"documentType": "ZUGFERD",
"status": "FAILED",
"documentId": null,
"invoiceNumber": null,
"sendingResult": null,
"errorType": "VALIDATION_FAILED",
"errors": [
{
"field": "invoiceNumber",
"message": "Invoice number is required"
},
{
"field": "issueDate",
"message": "Issue date format is invalid"
}
],
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:30:15",
"completedAt": "2025-06-15T10:30:15"
}
FAILED — Processing Failed (General Error)
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": "OUTGOING",
"documentType": "XRECHNUNG",
"status": "FAILED",
"documentId": null,
"invoiceNumber": null,
"sendingResult": null,
"errorType": "INVOICE_NULL_COULD_NOT_SAVE",
"errors": [
"Invoice is NULL and/or could not be saved! XML parsing error at line 42"
],
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:30:12",
"completedAt": "2025-06-15T10:30:12"
}
SENDING_FAILED — Sending Failed
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": "OUTGOING",
"documentType": "PEPPOL_BIS",
"status": "SENDING_FAILED",
"documentId": "f47ac10b-58cc-4372-a567-...",
"invoiceNumber": "INV-2025-001234",
"sendingResult": null,
"errorType": "INVOICE_SENDING_FAILED",
"errors": [
"Invoice sending failed: Peppol access point unreachable"
],
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:31:00",
"completedAt": "2025-06-15T10:31:00"
}
COMPLETED — With Country-Specific Metadata (Poland KSeF)
{
"trackingId": "e20a112a-fcb2-4da2-9efd-...",
"companyId": "a1b2c3d4-e5f6-7890-abcd-...",
"direction": "OUTGOING",
"documentType": "KSEF",
"status": "COMPLETED",
"documentId": "f47ac10b-58cc-4372-a567-...",
"invoiceNumber": "FA/2025/06/001",
"sendingResult": "SUCCESS",
"errorType": null,
"errors": null,
"additionalData": {
"sessionReferenceNumber": "20250615-SE-ABC123",
"invoiceReferenceNumber": "20250615-IR-DEF456",
"ksefNumber": "1234567890-20250615-..."
},
"createdAt": "2025-06-15T10:30:00",
"statusUpdatedAt": "2025-06-15T10:31:30",
"completedAt": "2025-06-15T10:31:30"
}
7. Get Invoice/Document Status GET
Purpose of Use: This endpoint is used to query the real-time processing status of an invoice/document by using the trackingId returned from an asynchronous document submission request.
After an invoice or document is submitted through an async flow, the first response may only contain a trackingId. This endpoint allows the client to follow the internal processing lifecycle of that document, including whether it is queued, processing, failed, or completed.
Once a documentId has been assigned to the document, this endpoint also returns invoice-level status information such as invoiceStatus and invoiceStatusDate. If the document has not yet been assigned a final documentId, those fields may be null, and only the process-level status fields should be used.
The request requires that the authenticated user in the R-Auth JWT has authority over the queried companyId.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/get-document-status-by-tracking |
| Method | GET |
| Content-Type | None — query parameters only, no request body |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth: {{jwt_token}} |
Example Request
curl -X GET 'https://api-fr-stage.docnova.ai/invoice/get-document-status-by-tracking?companyId={{company_uuid}}&trackingId={{tracking_uuid}}' \
-H 'accept: */*' \
-H 'R-Auth: {{jwt_token}}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | String (UUID) | Yes | Unique identifier of the company that the queried tracking record belongs to. The requesting user must hold a role in this company. |
| trackingId | String (UUID) | Yes | The tracking identifier returned in the response of the document's asynchronous submission request. The document status is looked up via this identifier. |
Notes
- The
R-Authheader is mandatory. - The user in the JWT must have a role in the company matching
companyId. - If
trackingIdis not associated withcompanyId, for example when trying to access a record belonging to another company, a401 Unauthorizedresponse is returned. - If the tracking process is found but no
documentIdhas been assigned yet, only the process-level status fields are returned.
Responses
200 - Successful Response
{
"trackingId": "{{tracking_uuid}}",
"documentId": "{{document_uuid}}",
"invoiceStatus": "SENT_TO_PEPPOL",
"invoiceStatusDate": "2026-01-15T12:00:00",
"processStatus": "COMPLETED",
"processStatusUpdatedAt": "2026-01-15T12:00:00"
}
Description: Request succeeded. If the document has not yet been assigned a documentId, the documentId, invoiceStatus, and invoiceStatusDate fields are null, and only processStatus / processStatusUpdatedAt are meaningful.
Response Fields
| Field | Type | Description |
|---|---|---|
| trackingId | String (UUID) | Echoes the trackingId sent in the request. Always populated. |
| documentId | String (UUID) | Populated once the document is assigned a final ID. null if the document has not yet been assigned. |
| invoiceStatus | String (Enum) | Populated once documentId is assigned. Contains the invoice's country/channel-specific final status. null if documentId is not yet assigned. |
| invoiceStatusDate | String (ISO 8601) | Timestamp of the last update to invoiceStatus. null if documentId is not yet assigned. |
| processStatus | String (Enum) | Status of the document's own processing pipeline. Always populated, even before documentId is assigned. |
| processStatusUpdatedAt | String (ISO 8601) | Timestamp of the last update to processStatus. Always populated. |
Parameter Values Reference Table
processStatus Values
| Value | Description |
|---|---|
| PENDING | Process has not started yet; queued. |
| PROCESSING | Document is currently being processed. |
| FAILED | Processing failed; may be retried. |
| SENDING_FAILED | An error occurred during the sending stage. |
| PERMANENT_FAILED | Permanent failure; will not be retried. |
| COMPLETED | Process completed successfully. |
invoiceStatus Values
| Value | Description |
|---|---|
| CREATED | Invoice/document has been created. |
| SAVED_AS_UBL | Saved in UBL format. |
| SAVED_AS_ZUGFERD | Saved in ZUGFeRD format. |
| SAVED_AS_FACTUR_X | Saved in Factur-X format. |
| SAVED_AS_CII | Saved in CII format. |
| SAVED_AS_CID | Saved in CID format. |
| READY_FOR_KSEF | Ready for submission to KSeF in Poland. |
| SENT_TO_ACCESS_POINT | Sent to the Access Point. |
| OCR_WAITING | Waiting for OCR processing. |
| OCR_PARSED | Successfully parsed by OCR. |
| OCR_FAILED | OCR processing failed. |
| OCR_PARSED_PENDING_PAYMENT | OCR completed, awaiting payment. |
| OCR_WAITING_TOKEN | Waiting for a token for OCR. |
| CANCELED | Canceled. |
| PENDING | Pending. |
| SAVED_AS_PDF | Saved as PDF. |
| DELETED | Deleted. |
| COMPLETED_BY_MELA_AI | Completed by Mela AI. |
| SENT_VIA_EMAIL | Sent via email. |
| SENT_VIA_SFTP | Sent via SFTP. |
| SENT_TO_PEPPOL | Sent to the Peppol network. |
| SUCCESS | Operation succeeded. |
| INVALID_PARAMETERS | Invalid parameters. |
| TRANSPORT_ERROR | Peppol transport error; no automatic retry. |
| TRANSPORT_ERROR_NO_RETRY | Peppol transport error; retry disabled. |
| NO_SIGNAL_MESSAGE_RECEIVED | No signal message received. |
| AS4_ERROR_MESSAGE_RECEIVED | AS4 error message received. |
| INVALID_SIGNAL_MESSAGE_RECEIVED | Invalid signal message received. |
| SMP_LOOKUP_FAILED | SMP lookup failed. |
| CREDIT_BLOCKED | Payment blocked due to credit limit. |
France invoiceStatus Values
| Value | Description |
|---|---|
| FR_DEPOSITED | Deposited to PPF in France. |
| FR_REJECTED | Rejected by PPF. |
| FR_RECEIVED | Received by PPF. |
| FR_AVAILABLE | Available in PPF. |
| FR_PROCESSING | Processing in PPF. |
| FR_APPROVED | Approved by PPF. |
| FR_PARTIALLY_APPROVED | Partially approved by PPF. |
| FR_DISPUTED | Disputed in PPF. |
| FR_SUSPENDED | Suspended in PPF. |
| FR_PLATFORM_ISSUED | Issued by the platform in France. |
| FR_REFUSED | Refused by PPF. |
| FR_PAYMENT_SENT | Payment sent in France. |
| FR_COLLECTED | Payment collected in France. |
| FR_COMPLETED | France process completed. |
| FR_CANCELLED | Cancelled in the France process. |
All error responses share the following structure:
{
"errorMessage": "<human-readable message>",
"errorType": "<error type key>",
"errorTitle": "<HTTP status name>",
"status": 400,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/get-document-status-by-tracking"
}
400 - Bad Request
Tracking ID Not Found
{
"errorMessage": "Tracking ID not found",
"errorType": "INVOICE_PROCESS_NOT_FOUND",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/get-document-status-by-tracking"
}
Description: An ApiError(INVOICE_PROCESS_NOT_FOUND) is thrown when the trackingId is not found in the database.
Note: Although Swagger annotation documents this case as 404, the code currently calls withStatus() on this exception, so RestExceptionHandler returns the default 400 Bad Request.
401 - Unauthorized
{
"errorMessage": "User is not authorized for this operation",
"errorType": "AUTHORIZATION_FAILED",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/get-document-status-by-tracking"
}
Trigger: The user in the R-Auth JWT has no role or authority in the given companyId, or the trackingId belongs to a different company than the given companyId.
500 - Internal Server Error
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"errorId": "{{correlation_id}}",
"timestamp": "2026-01-15T12:00:00",
"path": "/invoice/get-document-status-by-tracking"
}
Trigger: An unexpected server-side error occurs.
This may happen because of a database connectivity issue, an unhandled exception, or another server-side runtime error.
8. Retrieve Doc by ID and Type GET
Purpose of Use: The GET /invoice/get-document/{documentId}/{documentTypes} endpoint allows downloading a previously stored invoice or document in a specific format such as PDF, XML, or JSON.
The client provides the document UUID (documentId) and the desired output format (documentTypes). The API returns the document content as Base64 encoded data. This is mainly used in ERP integrations to programmatically fetch, view, archive, or store invoice documents.
When the requested format is pdf, the API returns the printable or viewable PDF file content as Base64 encoded data.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/get-document//{documentTypes} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/get-document/{documentId}/pdf' \
--header 'Accept: */*' \
--header 'R-Auth: {auth-token}'
}'
Request Parameters
Path Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| documentId | String (UUID) | Yes | Unique identifier of the document. Must be in UUID v4 format. Example: 550e8400-e29b-41d4-a716-... |
| documentTypes | String (Enum) | Yes | Requested document format type. Multiple types can be separated by hyphen -. Example: PDF, XML |
Header Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| R-Auth | String (JWT) | Yes | Authentication token. JWT signed with HS512 algorithm. |
| Accept | String | No | Accepted response media type. Default: / |
documentTypes Parameter Values
| Value | Format Type | Description |
|---|---|---|
| FormatType.PDF | Returns Base64-encoded PDF representation of the invoice | |
| XML | FormatType.XML | Returns Base64-encoded UBL XML content of the invoice |
| JSON | FormatType.JSON | Returns Base64-encoded UBL DTO JSON content of the invoice |
| PDF-XML | Multiple formats | Multiple formats can be requested simultaneously using hyphen separator |
| XML-PDF-JSON | Multiple formats | All three formats can be requested at once |
Note: JSON format is only supported for invoices processed by OCR (OCR_PARSED) or completed by MelAI (COMPLETED_BY_MELAI_AI).
Responses
200 - Successful Response
{
"documents": [
{
"file_type": "PDF",
"data": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC..."
}
]
}
Successful Response Field Descriptions
| Field Name | Type | Description |
|---|---|---|
| documents | List<Document> | List of documents in requested formats. Contains one Document object per format. |
| documents[].file_type | String (Enum) | Document format type. Possible values: PDF, XML, JSON |
| documents[].data | String (Base64) | Base64-encoded content of the document. When decoded for PDF, produces a valid PDF file. |
Multi-Format Response Example
{
"documents": [
{
"file_type": "XML",
"data": "PD94bWwgdmVy... (base64)"
},
{
"file_type": "PDF",
"data": "JVBERi0xLjQK... (base64)"
}
]
}
400 - Bad Request
Returned when an invalid documentTypes value is provided.
{
"errorMessage": "Unsupported document type: DOCX",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"errorId": "corr-def456",
"status": 400,
"timestamp": "2026-02-11T14:31:00",
"path": "/invoice/get-document/af6e8982-b791-4704-bc06-.../docx"
}
| Field | Description |
|---|---|
| errorMessage | Specifies the unsupported document type and which type was invalid. |
| errorType | INVALID_ARGUMENT An invalid parameter was provided. |
| status | 400 |
400 - Bad Request
Returned when the document's OCR processing has not yet completed (waiting state).
{
"errorMessage": "Invoice is waiting for MelaAIParser. Please try again later",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"errorId": "corr-ghi789",
"status": 400,
"timestamp": "2026-02-11T14:32:00",
"path": "/invoice/get-document/af6e8982-b791-4704-bc06-.../json"
}
| Field | Description |
|---|---|
| errorMessage | Indicates the invoice has not been processed by MelaAI yet and should be retried later. |
| errorType | INVALID_ARGUMENT The invoice is not in a processable state currently. |
| status | 400 |
401 - Unauthorized
Returned when an invalid or missing R-Auth token is provided.
{
"errorMessage": "Authentication is required. Please complete the authentication process.",
"errorType": "AUTHENTICATION_REQUIRED",
"errorTitle": "UNAUTHORIZED",
"errorId": "corr-abc123",
"status": 401,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/get-document/af6e8982-b791-4704-bc06-.../pdf"
}
| Field | Description |
|---|---|
| errorMessage | Indicates that the authentication process must be completed. |
| errorType | AUTHENTICATION_REQUIRED Token is missing, expired, or invalid. |
| status | 401 |
404 - Not Found
Returned when no document matches the provided UUID. Specifically occurs when JSON format is requested and the invoice is not found.
{
"errorMessage": "af6e8982-b791-4704-bc06-d4655faa4b4c Invoice not found!",
"errorType": "NOT_FOUND_INVOICE",
"errorTitle": "NOT_FOUND",
"errorId": "corr-jkl012",
"status": 404,
"timestamp": "2026-02-11T14:33:00",
"path": "/invoice/get-document/af6e8982-b791-4704-bc06-.../json"
}
| Field | Description |
|---|---|
| errorMessage | Returns a not found message along with the document UUID. |
| errorType | NOT_FOUND_INVOICE No matching invoice record exists in the database. |
| status | 404 |
500 - Internal Server Error
Returned when an unexpected error occurs (e.g., file cannot be retrieved from S3, PDF conversion fails).
{
"errorMessage": "Internal server error",
"errorType": "SERVER_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "corr-mno345",
"status": 500,
"timestamp": "2026-02-11T14:34:00",
"path": "/invoice/get-document/af6e8982-b791-4704-bc06-.../pdf"
}
| Field | Description |
|---|---|
| errorMessage | Generic server error message. |
| errorType | SERVER_ERROR An unexpected error occurred. |
| status | 500 |
Common Error Response Field Descriptions
| Field Name | Type | Description |
|---|---|---|
| errorMessage | String | Human readable description of the error |
| errorType | String | Programmatic classification code of the error |
| errorTitle | String (HttpStatus) | Text representation of the HTTP status code |
| errorId | String | Request correlation ID (for log tracking) |
| status | Integer | HTTP status code (numeric) |
| timestamp | String (ISO 8601) | Timestamp when the error occurred |
| path | String | Endpoint path where the error occurred |
| details | Map<String, Object> | Additional error details (if available) |
| validationErrors | List<ValidationError> | List of validation errors (if available) |
9. Search Document with Filter POST
Purpose of Use: The POST /invoice/search-documents endpoint is used to search for invoices and documents belonging to a specific company using various filtering criteria.
This API enables users to list documents associated with their company by applying filters such as date range, document direction (incoming or outgoing), invoice status, and document format (ZUGFERD, XRECHNUNG, etc.). Results are returned with pagination support, and each page includes the total document count, tax exclusive total amount, and tax inclusive total amount.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/search-documents |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
{
curl --location 'https://api-fr-stage.docnova.ai/invoice/search-documents' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--data '{
"companyId": "<COMPANY_UUID>",
"documentType": "OUTGOING",
"endDate": "2026-01-31",
"page": 0,
"size": 10,
"startDate": "2026-01-01",
"status": "SAVED_AS_ZUGFERD",
"type": "ZUGFERD"
}'
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Unique identifier of the company to search documents for |
| documentType | String (Enum) | No | Document direction filter. Used to filter incoming or outgoing documents |
| status | String (Enum) | No | Invoice status filter. Returns invoices in a specific status |
| type | String (Enum) | No | Document format type filter. Filters by invoice format |
| startDate | String (ISO Date) | No | Search start date. Format: YYYY-MM-DD |
| endDate | String (ISO Date) | No | Search end date. Format: YYYY-MM-DD |
| tin | String | No | Tax Identification Number filter |
| uit | String | No | UIT identifier filter |
| referenceDocument | String | No | Search by reference document number |
| page | Integer | No | Page number (0-based). Default: 0 |
| size | Integer | No | Number of records per page. Default: 50 |
Parameter Values
documentType Values
| Value | Description |
|---|---|
| INCOMING | Incoming documents (invoices sent by suppliers) |
| OUTGOING | Outgoing documents (invoices sent to customers) |
type Values
| Value | Group | Description |
|---|---|---|
| MY_INVOIS | MY_INVOIS | Malaysian MyInvois format |
| MY_PINT | MY_PINT | Malaysian PINT format |
| DK_OIOUBL | DK_OIOUBL | Danish OIOUBL format |
| EG_INVOICE | EG_INVOICE | Egyptian e-Invoice format |
| HR_INVOICE | HR_INVOICE | Croatian eRacun format |
| UAE_PINT | UAE_PINT | UAE PINT format |
| ZUGFERD | ZUGFERD | ZUGFeRD format (PDF + embedded XML) |
| FACTUR_X | ZUGFERD | French Factur-X format |
| XRECHNUNG_CII | ZUGFERD | XRechnung CII format |
| CII | ZUGFERD | UN/CEFACT CII format |
| CID | ZUGFERD | CID format |
| ZUGFERD | Unstructured invoices (paper, images, etc.) | |
| KSEF | KSEF | Polish KSeF format |
| KSEF_OFFLINE | KSEF_OFFLINE | Polish KSeF offline format |
| KZ_ESF_V2 | KZ_ESF_V2 | Kazakhstan e-Invoice v2 format |
Note: When using the type filter on the search-documents endpoint, only XRECHNUNG, ZUGFERD, and FACTUR_X values actively filter results. Other values return an empty result set.
status Values
| Category | Value | Description |
|---|---|---|
| General | CREATED | Invoice created |
| PENDING | Awaiting processing | |
| CANCELED | Cancelled | |
| DELETED | Deleted | |
| SENT_VIA_EMAIL | Sent via email | |
| Saved | SAVED_AS_UBL | Saved as UBL |
| SAVED_AS_ZUGFERD | Saved as ZUGFeRD | |
| SAVED_AS_FACTUR_X | Saved as Factur-X | |
| SAVED_AS_CII | Saved as CII | |
| SAVED_AS_CID | Saved as CID | |
| SAVED_AS_KSEF | Saved as KSeF | |
| SAVED_AS_PDF | Saved as PDF | |
| OCR | OCR_WAITING | OCR processing pending |
| OCR_PARSED | OCR completed successfully | |
| OCR_FAILED | OCR processing failed | |
| OCR_PARSED_PENDING_PAYMENT | OCR completed, payment pending | |
| OCR_WAITING_TOKEN | OCR waiting for token | |
| COMPLETED_BY_MELA_AI | Completed by Mela AI | |
| Peppol | SENT_TO_PEPPOL | Sent to Peppol network |
| SENT_TO_ACCESS_POINT | Sent to Access Point | |
| SUCCESS | Successfully delivered | |
| TRANSPORT_ERROR | Transport error | |
| INVALID_PARAMETERS | Invalid parameters | |
| NO_SIGNAL_MESSAGE_RECEIVED | No signal message received | |
| AS4_ERROR_MESSAGE_RECEIVED | AS4 error message received | |
| INVALID_SIGNAL_MESSAGE_RECEIVED | Invalid signal message received | |
| INCOMING_RESPONSE_ACKNOWLEDGED | Incoming response acknowledged (MLR/MLS) | |
| INCOMING_RESPONSE_REJECTED | Incoming response rejected | |
| INCOMING_RESPONSE_ACCEPTED | Incoming response accepted | |
| OUTGOING_RESPONSE_ACKNOWLEDGED | Outgoing response acknowledged (MLR/MLS) | |
| OUTGOING_RESPONSE_REJECTED | Outgoing response rejected | |
| OUTGOING_RESPONSE_ACCEPTED | Outgoing response accepted | |
| Romania (ANAF) | SENT_TO_ANAF | Sent to ANAF |
| PORTAL_OKAY | Portal approved | |
| PORTAL_ERROR | Portal error | |
| PORTAL_ERRORS | Portal multiple errors | |
| PORTAL_SYSTEM_ERROR | Portal system error | |
| PORTAL_IN_PROCESS | Portal processing | |
| Poland (KSeF) | KSEF_PENDING | KSeF processing |
| KSEF_ACCEPTED | KSeF accepted | |
| KSEF_REJECTED | KSeF rejected | |
| KSEF_DUPLICATE | KSeF duplicate record | |
| Malaysia (LHDNM) | LHDNM_SUBMITTED | Submitted to LHDNM |
| LHDNM_VALID | LHDNM valid | |
| LHDNM_INVALID | LHDNM invalid | |
| LHDNM_CANCELLED | LHDNM cancelled | |
| LHDNM_REJECT_REQUESTED | LHDNM rejection requested | |
| LHDNM_REJECTED | LHDNM rejected | |
| LHDNM_ERROR | LHDNM error | |
| Egypt (ETA) | ETA_SUBMITTED | Submitted to ETA |
| Croatia (eRacun) | ERACUN_ERROR | eRacun error |
| ERACUN_PENDING | eRacun pending | |
| ERACUN_WAITING_TO_SEND | eRacun waiting to send | |
| ERACUN_SENT | eRacun sent | |
| ERACUN_RECEIVED | eRacun received | |
| ERACUN_APPROVED | eRacun approved | |
| ERACUN_REJECTED | eRacun rejected | |
| ERACUN_FULLY_PAID | eRacun fully paid | |
| ERACUN_PARTIALLY_PAID | eRacun partially paid | |
| ERACUN_DELIVERY_FAILED | eRacun delivery failed | |
| Denmark | SENT_TO_NEMHANDEL | Sent to Nemhandel |
| Other | CREDIT_BLOCKED | Credit blocked (returns masked data) |
Responses
200 - Successful Response
{
"totalCount": 2,
"netTotal": 1500.00,
"total": 1785.00,
"invoiceList": [
{
{
"id": "a1b2c3d4-e5f6-7890-abcd-...",
"companyId": "60ccd1a7-5348-47b2-9ef6-...",
"userId": "user-uuid",
"customerName": "Muster GmbH",
"supplierName": "Lieferant AG",
"supplierId": "supplier-uuid",
"supplierVat": "DE123456789",
"status": "SAVED_AS_ZUGFERD",
"invoiceNumber": "INV-2026-001",
"taxExclusiveAmount": 750.00,
"taxInclusiveAmount": 892.50,
"lineExtensionAmount": 750.00,
"payableAmount": 892.50,
"allowanceTotalAmount": 0.00,
"currency": "EUR",
"createdTime": "2026-01-15T10:30:00",
"localCreatedTime": "2026-01-15T11:30:00",
"issueDate": "2026-01-15",
"deliveryDate": "2026-01-20",
"dueDate": "2026-02-15",
"supplierCountryCode": "DE",
"supplierEndpoint": "0204:DE123456789",
"customerId": "customer-uuid",
"customerVat": "DE987654321",
"customerEndpoint": "0204:DE987654321",
"customerCountryCode": "DE",
"typeCode": "380",
"documentType": "OUTGOING",
"errorMessage": null,
"lastUpdatedTime": "2026-01-15T10:30:00",
"localLastUpdatedTime": "2026-01-15T11:30:00",
"type": "ZUGFERD",
"source": "PORTAL",
"sendViaPeppol": false,
"statusTime": "2026-01-15T10:30:00",
"localStatusTime": "2026-01-15T11:30:00",
"fileName": "invoice_001.pdf",
"ocrParser": null,
"paymentDetails": null,
"profileType": "EN16931",
"isActive": true,
"countrySpecificData": null
}
]
}
}
Successful Response Field Descriptions
Top-Level Fields
| Field | Type | Description |
|---|---|---|
| totalCount | Long | Total number of documents matching the filters |
| netTotal | Double | Tax-exclusive total amount (excludes CREDIT_BLOCKED) |
| total | Double | Tax-inclusive total amount (excludes CREDIT_BLOCKED) |
| invoiceList | Array<Invoice> | List of invoice objects |
Invoice Object Fields
| Field | Type | Description |
|---|---|---|
| id | String (UUID) | Unique identifier of the invoice |
| companyId | String (UUID) | Company ID the invoice belongs to |
| userId | String (UUID) | User ID who created the invoice |
| customerName | String | Customer (buyer) name |
| supplierName | String | Supplier (seller) name |
| supplierId | String | Supplier ID |
| supplierVat | String | Supplier VAT number |
| status | String (Enum) | Current invoice status |
| invoiceNumber | String | Invoice number |
| taxExclusiveAmount | Double | Tax-exclusive amount |
| taxInclusiveAmount | Double | Tax-inclusive amount |
| lineExtensionAmount | Double | Line items total amount |
| payableAmount | Double | Amount payable |
| allowanceTotalAmount | Double | Total allowance/discount amount |
| currency | String | Currency code (ISO 4217: EUR, USD, TRY, etc.) |
| createdTime | String (DateTime) | Creation timestamp (UTC) |
| localCreatedTime | String (DateTime) | Creation timestamp (local time) |
| issueDate | String (Date) | Invoice issue date |
| deliveryDate | String (Date) | Delivery date |
| dueDate | String (Date) | Due date |
| supplierCountryCode | String | Supplier country code (ISO 3166-1 alpha-2) |
| supplierEndpoint | String | Supplier Peppol endpoint |
| customerId | String | Customer ID |
| customerVat | String | Customer VAT number |
| customerEndpoint | String | Customer Peppol endpoint |
| customerCountryCode | String | Customer country code |
| typeCode | String | Invoice type code (e.g., 380=Invoice, 381=Credit Note) |
| documentType | String (Enum) | Document direction: INCOMING or OUTGOING |
| errorMessage | String | Error message (if any) |
| lastUpdatedTime | String (DateTime) | Last update timestamp (UTC) |
| localLastUpdatedTime | String (DateTime) | Last update timestamp (local time) |
| type | String (Enum) | Document format type (DataType) |
| source | String (Enum) | Invoice source (PORTAL, ERP, PEPPOL, EMAIL, etc.) |
| sendViaPeppol | Boolean | Whether sent via Peppol |
| statusTime | String (DateTime) | Status change timestamp (UTC) |
| localStatusTime | String (DateTime) | Status change timestamp (local time) |
| fileName | String | File name |
| ocrParser | String (Enum) | OCR parser type |
| paymentDetails | Object | Payment details (null for certain statuses) |
| profileType | String (Enum) | ZUGFeRD profile type: BASIC, EN16931, EXTENDED |
| isActive | Boolean | Whether the invoice is active |
| countrySpecificData | Object | Country-specific additional data |
Note: Invoices with CREDIT_BLOCKED status are masked — only id, companyId, documentType, type,invoiceNumber ,supplierName,supplierVat , status and isActive fields are returned; all other fields are null.
400 - Bad Request
Returned when an invalid parameter value is provided (e.g., incorrect enum value, malformed UUID format).
{
"errorMessage": "Invalid value 'INVALID_STATUS' for parameter 'status'",
"errorType": "ILLEGAL_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"errorId": "corr-abc123-def456",
"status": 400,
"timestamp": "2026-01-15T10:30:00",
"path": "/invoice/search-documents"
}
Error Response Fields
| Field | Type | Description |
|---|---|---|
| errorMessage | String | Human-readable error description |
| errorType | String | Error type code |
| errorTitle | String | HTTP status name |
| errorId | String | Correlation ID (for log tracing) |
| status | Integer | HTTP status code |
| timestamp | String (DateTime) | Error occurrence time |
| path | String | Request path |
401 - Unauthorized
Returned when an invalid, expired, or missing JWT token is provided.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"errorId": "corr-abc123-def456",
"status": 401,
"timestamp": "2026-01-15T10:30:00",
"path": "/invoice/search-documents"
}
Unauthorized Error Response Fields
| Field | Type | Description |
|---|---|---|
| errorMessage | String | Authorization error description |
| errorType | String | Fixed value: NOT_AUTHORITY |
| errorTitle | String | HTTP status name: UNAUTHORIZED |
| errorId | String | Correlation ID |
| status | Integer | 401 |
| timestamp | String (DateTime) | Error occurrence time |
| path | String | Request path |
500 - Internal Server Error
Returned in case of database connection errors, unexpected runtime exceptions, or other server-side failures.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "corr-abc123-def456",
"status": 500,
"timestamp": "2026-01-15T10:30:00",
"path": "/invoice/search-documents"
}
Server Error Response Fields
| Field | Type | Description |
|---|---|---|
| errorMessage | String | General error message |
| errorType | String | RUNTIME_ERROR, IO_ERROR, or SERVER_ERROR |
| errorTitle | String | HTTP status name: INTERNAL_SERVER_ERROR |
| errorId | String | Correlation ID (for log tracing) |
| status | Integer | 500 |
| timestamp | String (DateTime) | Error occurrence time |
| path | String | Request path |
10. Get Invoice Details GET
Purpose of Use:
The GET /invoice/get-invoice/{invoiceId} endpoint allows retrieving the full structured details of a single invoice, including header data, party details, tax breakdown, and all invoice line items, in one consistent JSON structure regardless of the invoice's underlying document format, such as UBL, CII, Factur-X, etc.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/get-invoice/{invoiceId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header, JWT token |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/get-invoice/{invoiceId}' \
--header 'R-Auth: {your JWT}'
Request Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| invoiceId | String (UUID) | Yes | Unique identifier of the invoice. Must be in UUID v4 format. Obtained from the id field in the search-documents response. |
| R-Auth | String (JWT) | Yes | Authentication token. JWT signed with HS512 algorithm. |
Responses
200 - Successful Response
Returns an object with two top-level fields: invoice, the full invoice data, and paymentDetails, the payment status summary.
{
"invoice": {
"Type": "FACTUR_X",
"ProfileType": "EN16931",
"CustomizationID": {
"Value": "urn:cen.eu:en16931:2017"
},
"ID": {
"Value": "EXAMPLE-INV-001"
},
"IssueDate": {
"Value": "2026-07-29"
},
"DueDate": {
"Value": "2026-08-05"
},
"InvoiceTypeCode": {
"Value": "380"
},
"DocumentCurrencyCode": {
"Value": "EUR"
},
"AccountingSupplierParty": {
"Party": {
"PartyIdentification": [
{
"ID": {
"schemeID": "0225",
"Value": "000000000"
}
}
],
"PartyName": [
{
"Name": {
"Value": "Example Seller SAS"
}
}
],
"PostalAddress": {
"StreetName": {
"Value": "1 Example Street"
},
"CityName": {
"Value": "Paris"
},
"PostalZone": {
"Value": "75000"
},
"Country": {
"IdentificationCode": {
"Value": "FR"
}
}
},
"PartyTaxScheme": [
{
"CompanyID": {
"Value": "FR00000000000"
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
]
}
},
"AccountingCustomerParty": {
"Party": {
"PartyIdentification": [
{
"ID": {
"schemeID": "0225",
"Value": "000000001"
}
}
],
"PartyName": [
{
"Name": {
"Value": "Example Buyer SAS"
}
}
],
"PostalAddress": {
"StreetName": {
"Value": "2 Example Avenue"
},
"CityName": {
"Value": "Paris"
},
"PostalZone": {
"Value": "75008"
},
"Country": {
"IdentificationCode": {
"Value": "FR"
}
}
},
"PartyTaxScheme": [
{
"CompanyID": {
"Value": "FR00000000001"
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
]
}
},
"TaxTotal": [
{
"TaxAmount": {
"currencyID": "EUR",
"Value": 227.5
},
"TaxSubtotal": [
{
"TaxableAmount": {
"currencyID": "EUR",
"Value": 1000
},
"TaxAmount": {
"currencyID": "EUR",
"Value": 200
},
"TaxCategory": {
"ID": {
"Value": "S"
},
"Percent": {
"Value": 20
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
},
{
"TaxableAmount": {
"currencyID": "EUR",
"Value": 500
},
"TaxAmount": {
"currencyID": "EUR",
"Value": 27.5
},
"TaxCategory": {
"ID": {
"Value": "S"
},
"Percent": {
"Value": 5.5
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
},
{
"TaxableAmount": {
"currencyID": "EUR",
"Value": 300
},
"TaxAmount": {
"currencyID": "EUR",
"Value": 0
},
"TaxCategory": {
"ID": {
"Value": "Z"
},
"Percent": {
"Value": 0
},
"TaxExemptionReasonCode": {
"Value": "VATEX-EU-O"
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
}
]
}
],
"LegalMonetaryTotal": {
"LineExtensionAmount": {
"currencyID": "EUR",
"Value": 1800
},
"TaxExclusiveAmount": {
"currencyID": "EUR",
"Value": 1800
},
"TaxInclusiveAmount": {
"currencyID": "EUR",
"Value": 2027.5
},
"PayableAmount": {
"currencyID": "EUR",
"Value": 2027.5
}
},
"InvoiceLine": [
{
"ID": {
"Value": "1"
},
"InvoicedQuantity": {
"unitCode": "EA",
"Value": 1
},
"LineExtensionAmount": {
"currencyID": "EUR",
"Value": 1000
},
"Item": {
"Name": {
"Value": "Standard rate item"
},
"ClassifiedTaxCategory": [
{
"ID": {
"Value": "S"
},
"Percent": {
"Value": 20
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
]
},
"Price": {
"PriceAmount": {
"currencyID": "EUR",
"Value": 1000
}
}
},
{
"ID": {
"Value": "2"
},
"InvoicedQuantity": {
"unitCode": "EA",
"Value": 1
},
"LineExtensionAmount": {
"currencyID": "EUR",
"Value": 500
},
"Item": {
"Name": {
"Value": "Reduced rate item"
},
"ClassifiedTaxCategory": [
{
"ID": {
"Value": "S"
},
"Percent": {
"Value": 5.5
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
]
},
"Price": {
"PriceAmount": {
"currencyID": "EUR",
"Value": 500
}
}
},
{
"ID": {
"Value": "3"
},
"InvoicedQuantity": {
"unitCode": "EA",
"Value": 1
},
"LineExtensionAmount": {
"currencyID": "EUR",
"Value": 300
},
"Item": {
"Name": {
"Value": "VAT-exempt item"
},
"ClassifiedTaxCategory": [
{
"ID": {
"Value": "Z"
},
"Percent": {
"Value": 0
},
"TaxScheme": {
"ID": {
"Value": "VAT"
}
}
}
]
},
"Price": {
"PriceAmount": {
"currencyID": "EUR",
"Value": 300
}
}
}
]
},
"paymentDetails": {
"paymentStatus": "SENT",
"paidAmount": 0.0,
"totalAmount": 2027.5,
"remainingAmount": 2027.5,
"paymentDate": null
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| invoice | object | Full structured invoice data. |
| invoice.Type | string | Underlying invoice document type, e.g. FACTUR_X. |
| invoice.ProfileType | string | Invoice profile type, e.g. EN16931. |
| invoice.ID.Value | string | Business invoice number. |
| invoice.IssueDate.Value | date | Invoice issue date. |
| invoice.DueDate.Value | date | Invoice due date. |
| invoice.InvoiceTypeCode.Value | string | Invoice type code, e.g. 380. |
| invoice.DocumentCurrencyCode.Value | string | Invoice currency, e.g. EUR. |
| invoice.AccountingSupplierParty | object | Supplier party details. |
| invoice.AccountingCustomerParty | object | Customer party details. |
| invoice.TaxTotal | array | Tax total and tax breakdown information. |
| invoice.LegalMonetaryTotal | object | Invoice monetary totals. |
| invoice.InvoiceLine | array | Invoice line items. |
| paymentDetails | object | Payment status summary. |
| paymentDetails.paymentStatus | string | Current payment status. |
| paymentDetails.paidAmount | number | Amount already paid. |
| paymentDetails.totalAmount | number | Total invoice amount. |
| paymentDetails.remainingAmount | number | Remaining unpaid amount. |
| paymentDetails.paymentDate | datetime | Payment date, if available. |
401 - Unauthorized
{
"errorMessage": "User is not authorized for this operation",
"errorType": "NOT_AUTHORITY",
"status": 401,
"timestamp": "2026-07-29T12:00:00",
"path": "/invoice/get-invoice/{invoiceId}"
}
404 - Not Found
Returned when no invoice exists with the given invoiceId.
{
"errorMessage": "{invoiceId} Invoice not found!",
"errorType": "NOT_FOUND_INVOICE",
"status": 404,
"timestamp": "2026-07-29T12:00:00",
"path": "/invoice/get-invoice/{invoiceId}"
}
500 - Internal Server Error
Returned when invoiceId is not a valid UUID.
{
"errorMessage": "Invalid UUID string: {invoiceId}",
"errorType": "RUNTIME_ERROR",
"status": 500,
"timestamp": "2026-07-29T12:00:00",
"path": "/invoice/get-invoice/{invoiceId}"
}
11. Merge PDF and XML POST
Purpose of Use: This endpoint is used to merge a PDF invoice document with a ZUGFeRD/Factur-X compliant XML invoice data to create a ZUGFeRD-compliant PDF/A-3 document.
Detailed Description:
- Combines the visual PDF invoice with the structured XML invoice data into a single file intended for the recipient.
- The XML data is embedded into the PDF document as an attachment named factur-x.xml.
- Before merging, the XML data is validated against the ZUGFeRD schema. If validation fails, an error is returned.
- The result is a hybrid e-invoice document that is both human-readable (PDF) and machine-processable (embedded XML).
- This endpoint is specifically designed for producing ZUGFeRD/Factur-X standard-compliant documents used in German (DE) e-invoicing processes.
Endpoint Information
| Property | Value |
|---|---|
| URL | POST /invoice/merge-zugferd-pdf-xml |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authentication | R-Auth header (JWT Token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/merge-zugferd-pdf-xml' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--data '{
"base64Pdf": "<BASE64_ENCODED_PDF>",
"base64Xml": "<BASE64_ENCODED_XML>"
}'
Request Body Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| base64Pdf | String | Yes | Base64-encoded PDF document to be merged. Must contain a valid PDF file. |
| base64Xml | String | Yes | Base64-encoded ZUGFeRD/Factur-X XML invoice data to be merged. Must conform to the ZUGFeRD schema (EN 16931). |
Parameter Value Constraints
| Parameter | Accepted Value | Constraint | Source |
|---|---|---|---|
| base64Pdf | Valid Base64 String | Must be a Base64 encoding of a valid PDF document. Invalid Base64 or corrupted PDF returns an error. | ErpController.java |
| base64Xml | Valid Base64 String | Must be XML conforming to ZUGFeRD EN 16931:2017 schema. Validated by Mustang ZUGFeRDValidator. | ValidationService.java |
| file_type (response) | PDF, XML, SIGN, JSON, GPDF, HTML | This endpoint always returns PDF. | FormatType.java |
Responses
200 - Successful Response
{
"file_type": "PDF",
"data": "<BASE64_ENCODED_MERGED_PDF>"
}
Successful Response Field Descriptions
| Field Name | Type | Description |
|---|---|---|
| file_type | String | Format of the returned file. Always PDF for this endpoint. |
| data | String | Base64-encoded merged ZUGFeRD PDF document. Contains the XML data embedded as factur-x.xml. |
400 - Bad Request
Returned when the base64Pdf or base64Xml is not a valid Base64 string or the decoded data is corrupted.
{
"errorMessage": "Illegal base64 character ...",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "<CORRELATION_ID>",
"timestamp": "2026-02-11T10:30:00",
"path": "/invoice/merge-zugferd-pdf-xml"
}
| Field Name | Type | Description |
|---|---|---|
| errorMessage | String | Detailed description of the error |
| errorType | String | Error classification. API_ERROR in this case |
| errorTitle | String | HTTP status code name: BAD_REQUEST |
| status | Integer | HTTP status code: 400 |
| errorId | String | Request tracking identifier (Correlation ID) |
| timestamp | String (ISO 8601) | Time when the error occurred |
| path | String | Request URL path |
400 - Bad Request
Returned when the XML data does not conform to the schema, along with validation errors.
{
"errorMessage": "Validation failed!",
"errorType": "VALIDATION_FAILED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "<CORRELATION_ID>",
"timestamp": "2026-02-11T10:30:00",
"path": "/invoice/merge-zugferd-pdf-xml",
"validationErrors": [
{
"field": "/rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID",
"code": "BR-02",
"message": "An Invoice shall have an Invoice number."
}
]
}
validationErrors Array Field Descriptions
| Field Name | Type | Description |
|---|---|---|
| field | String | XML XPath location where the error was found |
| code | String | ZUGFeRD/EN 16931 business rule code (e.g., BR-02, BR-CO-15) |
| message | String | Detailed description of the validation error |
400 - Bad Request
Returned when the validation result cannot be parsed.
{
"errorMessage": "JAXBException occurred: ...",
"errorType": "VALIDATION_FAILED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "<CORRELATION_ID>",
"timestamp": "2026-02-11T10:30:00",
"path": "/invoice/merge-zugferd-pdf-xml"
}
401 - Unauthorized
Returned when the R-Auth header is missing, the JWT token is expired, or the token is invalid.
{
"errorMessage": "Unauthorized",
"errorType": "UNAUTHORIZED",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"errorId": "<CORRELATION_ID>",
"timestamp": "2026-02-11T10:30:00",
"path": "/invoice/merge-zugferd-pdf-xml"
}
500 - Internal Server Error
Returned when an unexpected error occurs during PDF merging (corrupted PDF structure, memory issues, etc.).
{
"errorMessage": "An unexpected error occurred during PDF merging",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "<CORRELATION_ID>",
"timestamp": "2026-02-11T10:30:00",
"path": "/invoice/merge-zugferd-pdf-xml"
}
Note: The "catch (Exception e)" block in the controller throws all exceptions as ApiError, which defaults to HTTP 400. However, errors caught at the Spring framework level (e.g., JSON parse errors) may return HTTP 500.
12. Generate PDF POST
Purpose of Use: This API endpoint generates a human-readable PDF invoice document from structured XML invoice data (ZUGFeRD, Factur-X, XRechnung, etc.). The submitted Base64-encoded XML data is first transformed into HTML via XSLT templates, then converted into a professionally formatted PDF file using the iText 7 library. For ZUGFeRD/Factur-X/CII formats, the original XML data is embedded within the PDF file (PDF/A-3 compliant), creating a hybrid invoice. Optionally, the country and vatNumber fields can be used to match company records, enabling company logo placement and country-specific language settings on the PDF. It is specifically designed for invoice visualization, printing, and archiving processes in ERP integrations (SAP, etc.).
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/generate/pdf |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authentication | R-Auth header (JWT Bearer Token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/invoice/generate/pdf' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJNTU0iLCJzdWIiOiJwNjR9.IpGPX...' \
--data '{
"base64XML": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KC...",
"country": "DE",
"type": "ZUGFERD",
"vatNumber": "DE777111222"
}
Request Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| base64XML | String | Yes | Base64-encoded invoice XML data. Must be a valid XML in UBL 2.1, CrossIndustryInvoice (CII), or the relevant country-specific format. |
| type | Enum (DataType) | Yes | Invoice format type. Specifies the standard of the provided XML. Valid values are listed in the table below. |
| country | Enum (Country) | No | Country code of the invoice (ISO 3166-1 alpha-2). When used together with vatNumber, company matching is performed to add logo and language settings to the PDF. |
| vatNumber | String | No | VAT number of the invoicing company. When used together with country, it matches against the company record in the system. |
Valid Values for type Parameter
UBL-Based Formats
| Value | Description | XSLT Group |
|---|---|---|
| XRECHNUNG | German XRechnung standard (EN 16931 compliant) | XRECHNUNG |
| PEPPOL_BIS | PEPPOL BIS 3.0 standard | XRECHNUNG |
| RO_EFACTURA | Romania e-Factura format | XRECHNUNG |
| MY_INVOIS | Malaysia MyInvois format | MY_INVOIS |
| MY_PINT | Malaysia PINT format | MY_PINT |
| DK_OIOUBL | Denmark OIOUBL format | DK_OIOUBL |
| EG_INVOICE | Egypt invoice format | EG_INVOICE |
| HR_INVOICE | Croatia invoice format | HR_INVOICE |
| UAE_PINT | UAE PINT format | UAE_PINT |
CII / ZUGFeRD-Based Formats
| Value | Description | XSLT Group |
|---|---|---|
| ZUGFERD | ZUGFeRD 2.x format (XML-embedded PDF) | ZUGFERD |
| FACTUR_X | French Factur-X format | ZUGFERD |
| XRECHNUNG_CII | XRechnung CII format | ZUGFERD |
| CII | UN/CEFACT CrossIndustryInvoice | ZUGFERD |
| CID | CrossIndustryDocument format | ZUGFERD |
| Unstructured invoice (paper invoices, images, etc.) | ZUGFERD |
Other Formats
| Value | Description | XSLT Group |
|---|---|---|
| KZ_ESF_V2 | Kazakhstan ESF v2 format | KZ_ESF_V2 |
| KSEF | Poland KSeF format | KSEF |
| KSEF_OFFLINE | Poland KSeF offline format | KSEF_OFFLINE |
country Parameter
| Country Code | Country | PDF Language |
|---|---|---|
| DE | Germany | German (DE) |
| AT | Austria | German (DE) |
| FR | France | French (FR) |
| IT | Italy | Italian (IT) |
| NL | Netherlands | Dutch (NL) |
| RO | Romania | Romanian (RO) |
| ES | Spain | Spanish (ES) |
| TR | Turkey | Turkish (TR) |
| KZ | Kazakhstan | Kazakh (KK) |
| MY | Malaysia | Malay (MS) |
| BN | Brunei | Malay (MS) |
| All others | — | English (EN) |
Responses
200 - Successful Response
| Property | Value |
|---|---|
| HTTP Status | 200 |
| Content-Type | application/octet-stream |
| Body | Binary PDF data (byte array) |
%PDF-1.7
%����
1 0 obj
<<
/Pages 2 0 R
/Type /Catalog
/Names 21 0 R
/Metadata 27 0 R
>>
endobj
5 0 obj
<<
400 - Bad Request
Trigger Condition: When the XML data is invalid, Base64 cannot be decoded, XSLT transformation fails, or any error occurs during iText PDF generation.
{
"errorMessage": "PDF convert error: [detail message]",
"errorType": "PDF_CONVERT_ERROR",
"errorTitle": "BAD_REQUEST",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
Possible Detail Messages:
- PDF convert error: PDF conversion failed due to an unexpected error — XSLT template not found or unexpected error during HTML-to-PDF conversion
- PDF convert error: Illegal base64 character — The base64XML field is not in valid Base64 format
- PDF convert error: [XSLT transformation error]` — XML structure does not match the expected format
400 - Bad Request — Invalid Parameter
Trigger Condition: When an invalid enum value is sent for the type field or required fields are missing.
{
"errorMessage": "Invalid argument! Argument: type",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
400 - Bad Request — Invalid PDF Type
Trigger Condition: When the submitted type value is an unsupported format for PDF conversion.
{
"errorMessage": "Invalid PDF type",
"errorType": "INVALID_PDF_TYPE",
"errorTitle": "BAD_REQUEST",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
400 - Bad Request — Empty XML Data
Trigger Condition: When the base64XML field is sent as null or empty.
{
"errorMessage": "Data XML cannot be NULL!",
"errorType": "NULL_DATA_XML",
"errorTitle": "BAD_REQUEST",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
401 - Unauthorized
Trigger Condition: When the R-Auth header is missing, the JWT token has expired, or an invalid token is provided.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 401,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
500 - Internal Server Error
Trigger Condition: When an unexpected server error occurs (XSLT file cannot be loaded, insufficient memory, etc.).
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 500,
"timestamp": "2026-02-11T14:30:00",
"path": "/invoice/generate/pdf"
}
Error Codes and Response Details
The following errors are specific to this endpoint. All error responses follow the ExceptionResponse format:
Error Response Structure
| Field Name | Type | Description |
|---|---|---|
| errorMessage | String | Detailed description of the error |
| errorType | String | Error type identifier |
| errorTitle | String | HTTP status name (BAD_REQUEST, INTERNAL_SERVER_ERROR, etc.) |
| errorId | String | Correlation ID (for log tracing) |
| status | Integer | HTTP status code (400, 500, etc.) |
| timestamp | String (ISO 8601) | Time when the error occurred |
| path | String | Requested URL path |
13. Send Invoice via E-mail POST
Purpose of Use This API endpoint enables sending invoices to recipients via email. Users can select one or more invoices and send them in the desired format (PDF, XML, etc.) to specified email addresses. Invoice files are automatically converted to the requested format and attached to the email. Before sending, the user’s authorization is verified; only users with ADMIN or OUTGOING_INVOICE_SEND_EMAIL authority can perform this operation. Email delivery is first attempted via AWS SES; if that fails, an SMTP fallback mechanism is activated. Upon successful delivery, the invoice status is updated to SENT_VIA_EMAIL and the action is logged in the invoice history.
Endpoint Information
| Property | Value |
|---|---|
| URL | /email/send |
| Method | POST |
| Content-Type | multipart/form-data |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authentication | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/email/send' \
--header 'Content-Type: multipart/form-data' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--form 'invoiceIdList="<INVOICE_UUID>"' \
--form 'companyId="<COMPANY_UUID>"' \
--form 'body="Your Invoice is attached."' \
--form 'subject="2026_006"' \
--form 'formatTypes="PDF"' \
--form 'toList="recipient@example.com"'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| invoiceIdList | List<UUID> | Yes | List of invoice IDs to be sent. Multiple invoices can be included. |
| companyId | UUID | Yes | The company ID that the invoices belong to. |
| formatTypes | List<FormatType> | Yes | Format(s) in which invoice attachments will be generated. Multiple formats can be specified. |
| toList | List<String> | No | List of recipient email addresses. |
| ccList | List<String> | No | List of CC (Carbon Copy) recipient email addresses. |
| bccList | List<String> | No | List of BCC (Blind Carbon Copy) recipient email addresses. |
| subject | String | No | Email subject line. If omitted, a template or default subject is used. |
| body | String | No | Email body text. If omitted, a template or default content is used. |
| attachments | List<MultipartFile> | No | Additional file attachments (beyond the auto-generated invoice files). |
FormatType Values
| Value | Description |
|---|---|
| Invoice attached in PDF format | |
| XML | Invoice attached in XML (UBL/CII) format |
| SIGN | Signed invoice file attached |
| JSON | Invoice attached in JSON format |
| GPDF | Invoice attached in graphic PDF format |
| HTML | Invoice attached in HTML format |
Attachment Constraints
| Constraint | Value |
|---|---|
| Maximum file count | 3 |
| Maximum file size (per file) | 5 MB |
| Allowed content types | application/pdf, application/xml, text/xml, image/png, image/jpg, image/jpeg, message/rfc822, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
Responses
200 - Successful Response
| Field | Type | Value | Description |
|---|---|---|---|
| HTTP Status | Integer | 200 | Operation successful |
| Body | Boolean | true | Email sent successfully |
true
400 - Bad Request
Condition: invoiceIdList field is empty or not provided.
{
"errorMessage": "Validation failed",
"errorType": "VALIDATION_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send",
"validationErrors": [
{
"field": "invoiceIdList",
"message": "must not be empty"
}
]
}
400 - Bad Request — Validation Error (companyId null)
Condition: companyId field is not provided.
{
"errorMessage": "Validation failed",
"errorType": "VALIDATION_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send",
"validationErrors": [
{
"field": "companyId",
"message": "must not be null"
}
]
}
400 - Bad Request — Validation Error (formatTypes empty)
Condition: formatTypes field is empty or not provided.
{
"errorMessage": "Validation failed",
"errorType": "VALIDATION_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send",
"validationErrors": [
{
"field": "formatTypes",
"message": "must not be empty"
}
]
}
400 - Bad Request — Invoice Not Found
Condition: No invoice found matching the provided invoiceIdList and companyId combination.
{
"errorMessage": "Invoices not found with id list [d2fc7bb5-4ffe-44ab-b9e9-92a833df65ec]",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
400 - Bad Request — Invoice Attachment Generation Failed
Condition: Invoice file could not be generated in the requested format (e.g., file not found in S3).
{
"errorMessage": "Attachments not found with invoice id list [d2fc7bb5-4ffe-44ab-b9e9-92a833df65ec]",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
400 - Bad Request — Attachment Count Exceeded
Condition: More than 3 additional files were uploaded.
{
"errorMessage": "Maximum 3 files are allowed, found 5",
"errorType": "EMAIL_ATTACHMENT_COUNT_EXCEED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
400 - Bad Request — Attachment File Size Exceeded
Condition: An attachment exceeds the 5 MB limit.
{
"errorMessage": "Maximum 5MB file size is allowed, report.pdf file size is 8MB",
"errorType": "EMAIL_ATTACHMENT_FILE_SIZE_EXCEED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
400 - Bad Request — Attachment Content Type Not Allowed
Condition: The uploaded file's content type is not in the allowed list.
{
"errorMessage": "Allowed content types are [application/pdf, application/xml, text/xml, image/png, image/jpg, image/jpeg, message/rfc822, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet], malware.exe file content type is application/octet-stream",
"errorType": "EMAIL_ATTACHMENT_CONTENT_TYPE_NOT_ALLOWED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
400 - Bad Request — Email Sending Failed
Condition: Email could not be sent via both AWS SES and SMTP.
{
"errorMessage": "Failed to send email: Connection refused",
"errorType": "EMAIL_SENDING_FAILED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
401 - Unauthorized
Condition: Invalid or expired JWT token provided in the R-Auth header.
{
"errorMessage": "Unauthorized",
"errorType": "UNAUTHORIZED",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
403 - Forbidden
Condition: The user does not have ADMIN or OUTGOING_INVOICE_SEND_EMAIL authority.
{
"errorMessage": "Access denied",
"errorType": "FORBIDDEN",
"errorTitle": "FORBIDDEN",
"status": 403,
"timestamp": "2026-02-11T14:30:00",
"path": "/email/send"
}
14. Peppol - Get MLR GET
Purpose of Use This endpoint is used to query Message Level Response (MLR) records for invoices sent or received through the Peppol network.
MLR is a message level response mechanism in the Peppol infrastructure that indicates whether a document was successfully delivered, accepted, or rejected by the receiving party.
With this API you can:
- List all MLR responses belonging to a specific company
- Query MLR status for a specific invoice (invoiceId) or document (documentId)
- Filter by the counterpart’s Peppol participant identifier (counterpartParticipantId)
- Perform time based searches by specifying a date range (fromDate, toDate)
- Returned responses include detail lines for each MLR record (error field, status reason, description)
This enables developers to programmatically track the final status of the invoice delivery process and take necessary actions in case of errors.
Endpoint Information
| Property | Value |
|---|---|
| URL | /peppol/search-mlr |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
{
curl --location 'https://api-fr-stage.docnova.ai/peppol/search-mlr?companyId={companyId}&counterpartParticipantId={counterpartParticipantId}&documentId={documentId}&fromDate={fromDate}&invoiceId={invoiceId}&toDate={toDate}' \
--header 'Accept: */*' \
--header 'R-Auth: {jwt_token}'
}
Request Parameters
| Field | Type | Required | Format | Description |
|---|---|---|---|---|
| companyId | String (UUID) | Yes | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | Unique identifier of the company to query |
| documentId | String (UUID) | No | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | Peppol document identifier (instance identifier) |
| counterpartParticipantId | String | No | {scheme}:{identifier} (e.g., 9930:de111222777) | Counterpart’s Peppol participant identifier |
| invoiceId | String | No | Free text | Invoice number or identifier |
| fromDate | String (ISO Date) | No | yyyy-MM-dd (e.g., 2025-09-09) | Search start date (inclusive) |
| toDate | String (ISO Date) | No | yyyy-MM-dd (e.g., 2026-09-09) | Search end date (inclusive) |
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
| R-Auth | String (JWT) | Yes | User authentication token. JWT signed with HS512 algorithm |
| Accept | String | No | Default /. Response is returned as application/json |
Parameter Values
counterpartParticipantId Format
| Scheme | Description | Example |
|---|---|---|
| 9930 | Germany VAT number | 9930:de111222777 |
| 0204 | Leitweg-ID | 0204:1234567890123 |
| 0088 | EAN location code | 0088:1234567890123 |
responseType Response Type Enum Values
| Value | Description |
|---|---|
| ACCEPTANCE | Document was accepted by the counterpart |
| ACKNOWLEDGING | Document was acknowledged (received) by the counterpart |
| REJECTION | Document was rejected by the counterpart |
statusReasonCode Status Reason Code Enum Values
| Value | Description |
|---|---|
| BUSINESS_RULE_VIOLATION_FATAL | Business rule violation. Critical error. Document was not processed |
| BUSINESS_RULE_VIOLATION_WARNING | Business rule violation. Warning. Document can still be processed |
| SYNTAX_VIOLATION | Syntax error. Document format is invalid |
Responses
200 - Successful Response
Type: List<SearchMLRResponse>
{
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-...",
"companyId": "60ccd1a7-5348-47b2-9ef6-...",
"documentId": "8fa4606f-94f2-45e1-a8cb-...",
"responseType": "ACCEPTANCE",
"receivedTime": "2026-01-15T14:30:00",
"counterpartParticipantId": "9930:de111222777",
"invoiceId": "2026_007_peppol",
"responseLines": [
{
"id": "f1e2d3c4-b5a6-7890-abcd-...",
"errorField": null,
"responseCode": "ACCEPTANCE",
"description": "Document successfully processed",
"statusReasonCode": null
}
]
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier of the MLR record |
| companyId | String | Identifier of the related company |
| documentId | String | Peppol document identifier |
| responseType | Enum (MessageLevelResponseType) | Overall response type: ACCEPTANCE, ACKNOWLEDGING, REJECTION |
| receivedTime | DateTime (ISO 8601) | Date and time the MLR response was received |
| counterpartParticipantId | String | Counterpart’s Peppol participant identifier |
| invoiceId | String | Related invoice number |
| responseLines | List<SearchMLRLineResponse> | MLR detail lines |
Response Detail Lines
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier of the detail line |
| errorField | String (nullable) | The field / XPath expression where the error occurred |
| responseCode | Enum (MessageLevelResponseType) | Line level response code: ACCEPTANCE, ACKNOWLEDGING, REJECTION |
| description | String (nullable) | Error or status description |
| statusReasonCode | Enum (MLRStatusReasonCode) (nullable) | Status reason code: BUSINESS_RULE_VIOLATION_FATAL, BUSINESS_RULE_VIOLATION_WARNING, SYNTAX_VIOLATION |
400 - Bad Request
Occurs when the required companyId parameter is missing or when the date format is invalid.
{
"errorMessage": "Required request parameter 'companyId' for method parameter type String is not present",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"errorId": "corr-xxx-xxx",
"timestamp": "2026-01-15T14:30:00",
"path": "/peppol/search-mlr"
}
Description: The companyId parameter is mandatory and Spring framework automatically returns this error when it is missing. Additionally, if fromDate or toDate parameters do not conform to the yyyy-MM-dd ISO format, the same error code is returned.
401 - Unauthorized
Occurs when the JWT token is invalid, expired, or the R-Auth header is missing. Also returned when the user is not associated with the specified companyId.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"errorId": "corr-xxx-xxx",
"timestamp": "2026-01-15T14:30:00",
"path": "/peppol/search-mlr"
}
Description: The authorizationService.checkIfCompanyUser(companyId, userId) method verifies that the user identity in the JWT token matches the specified companyId. If they do not match, an AuthorizationServiceException is thrown. This error is also returned when the token is expired or its signature is invalid.
500 - Internal Server Error
Returned in case of database access errors, unexpected runtime exceptions, or other server-side failures.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"errorId": "corr-xxx-xxx",
"timestamp": "2026-01-15T14:30:00",
"path": "/peppol/search-mlr"
}
Description: Returned in case of database connection errors, JPA/Hibernate query failures, or unexpected internal server errors. The errorId (correlation id) field can be used to trace detailed error information from log records.
Error Response General Format
| Field | Type | Description |
|---|---|---|
| errorMessage | String | Human readable description of the error |
| errorType | String | Error classification code (e.g., NOT_AUTHORITY, RUNTIME_ERROR) |
| errorTitle | String (HttpStatus) | HTTP status code name (e.g., BAD_REQUEST, UNAUTHORIZED, INTERNAL_SERVER_ERROR) |
| status | Integer | HTTP status code numeric value (e.g., 400, 401, 500) |
| errorId | String (nullable) | Correlation ID used for log tracing |
| data | String (nullable) | Additional data (if available) |
| details | Map<String, Object> (nullable) | Detailed error information (if available) |
| validationErrors | List<ValidationError> (nullable) | Field level validation errors (if available) |
| timestamp | DateTime (ISO 8601) | Time when the error occurred |
| path | String | Endpoint path where the error occurred |
15. Peppol - Send MLR POST
Purpose of Use The POST /peppol/send-mlr endpoint is used to send a Message Level Response (MLR) within the Peppol infrastructure.
An MLR is the official response given by the receiving party to an e-invoice received through Peppol. This response communicates to the sender whether the invoice was successfully received and accepted, is being processed (acknowledged), or has been rejected. The receiver can inform the sender in detail by specifying errors in the invoice (IBAN error, syntax error, business rule violation, etc.).
After the MLR is sent, the related invoice status is automatically updated.
Endpoint Information
| Property | Value |
|---|---|
| URL | /peppol/send-mlr |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authentication | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/peppol/send-mlr' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--data '{
"errorLines": [
{
"description": "The IBAN number provided in the payment instructions is invalid or missing",
"errorField": "PaymentMeans/PayeeFinancialAccount/ID",
"responseCode": "ACKNOWLEDGING",
"statusReasonCode": "BUSINESS_RULE_VIOLATION_WARNING"
}
],
"invoiceId": "<INVOICE_UUID>",
"responseCode": "ACCEPTANCE"
}'
Request Parameters
Root Level Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| invoiceId | String (UUID) | Yes | Unique identifier of the invoice to send the MLR for (UUID format) |
| responseCode | Enum (MessageLevelResponseType) | Yes | Overall response code for the invoice |
| errorLines | Array<MLRErrorLine> | No | List of error details in the invoice. Can be left empty |
errorLines Array Element
| Field Name | Type | Required | Description |
|---|---|---|---|
| description | String | No | Human readable description of the error |
| errorField | String | No | UBL/XML field path where the error was detected (XPath-like) |
| responseCode | Enum (MessageLevelResponseType) | No | Response code specific to this error line |
| statusReasonCode | Enum (MLRStatusReasonCode) | No | Classification code of the error |
Allowed Parameter Values
MessageLevelResponseType (responseCode)
| Value | Description |
|---|---|
| ACCEPTANCE | Invoice accepted. It has been processed and approved |
| ACKNOWLEDGING | Invoice received. Receipt is confirmed but not yet fully processed |
| REJECTION | Invoice rejected. Not processed due to errors |
MLRStatusReasonCode (statusReasonCode)
| Value | Description |
|---|---|
| BUSINESS_RULE_VIOLATION_FATAL | Fatal business rule violation. A critical error that prevents the invoice from being processed |
| BUSINESS_RULE_VIOLATION_WARNING | Warning level business rule violation. The invoice can be processed but correction is recommended |
| SYNTAX_VIOLATION | Syntax error. Format or schema incompatibility in the XML/UBL structure |
Responses
200 - Successful Response
| Field | Type | Value | Description |
|---|---|---|---|
| HTTP Status | Integer | 200 | Operation successful |
| Body | String | "MLR sent successfully" | Response text returned from the Access Point service |
"MLR sent successfully"
400 - Bad Request
Trigger Condition: When an error occurs while forwarding the MLR to the Access Point service (connection error, timeout, Access Point rejection).
{
"errorMessage": "Failed to send MLR: <detailed error message>",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"errorId": "<correlation-id>",
"status": 400,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: The MLR was saved to the database but could not be forwarded to the Access Point. The error message contains the detail returned from the Access Point. Check your network connectivity and Access Point service availability.
400 - Bad Request — Invalid responseCode
Trigger Condition: When the responseCode field contains an invalid enum value (i.e., a value other than ACCEPTANCE, ACKNOWLEDGING, REJECTION).
{
"errorMessage": "Unknown response code: <invalid_value>",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"errorId": "<correlation-id>",
"status": 400,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: The responseCode field only accepts ACCEPTANCE, ACKNOWLEDGING, or REJECTION values. Verify the value you are sending.
400 - Bad Request — Invalid UUID Format
Trigger Condition: When the invoiceId field is not in a valid UUID format.
{
"errorMessage": "Invalid UUID string: <invalid_value>",
"errorType": "API_ERROR",
"errorTitle": "BAD_REQUEST",
"errorId": "<correlation-id>",
"status": 400,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: : The invoiceId value must be a valid UUID in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
401 - Unauthorized
Trigger Condition: When the R-Auth header is missing, invalid, or contains an expired JWT token.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"errorId": "<correlation-id>",
"status": 401,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: The JWT token has expired or is malformed. Obtain a new token and retry.
404 - Not Found
Trigger Condition: When no invoice matching the provided invoiceId is found in the database.
{
"errorMessage": "<invoiceId> Invoice not found",
"errorType": "NOT_FOUND_INVOICE",
"errorTitle": "NOT_FOUND",
"errorId": "<correlation-id>",
"status": 404,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: The invoiceId parameter contains an invalid or unregistered UUID in the database. Ensure the invoice ID is correct.
500 - Internal Server Error
Trigger Condition: When a database error, network error, or unexpected exception occurs.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "<correlation-id>",
"status": 500,
"timestamp": "2026-02-12T14:30:00",
"path": "/peppol/send-mlr"
}
Description: An unexpected error occurred on the server side. Forward the errorId (correlation ID) value to the support team for detailed investigation.
Error Response Model (ExceptionResponse)
| Field Name | Type | Description |
|---|---|---|
| errorMessage | String | Detailed description of the error |
| errorType | String | Error classification code (e.g., NOT_FOUND_INVOICE, API_ERROR) |
| errorTitle | String (HttpStatus) | HTTP status name (e.g., NOT_FOUND, BAD_REQUEST) |
| errorId | String | Correlation identifier (for log tracing) |
| status | Integer | HTTP status code (e.g., 400, 404, 500) |
| data | String | Additional data (if available) |
| details | Map<String, Object> | Additional detail information (if available) |
| validationErrors | Array<ValidationError> | Validation error list (if available) |
| timestamp | String (ISO 8601) | Timestamp of when the error occurred |
| path | String | Endpoint path of the request |
16. Search SIREN number GET
Purpose of Use This endpoint queries the PPF (Plateforme Publique de Facturation) — France's official public e-invoicing platform — to retrieve basic directory information about a French legal entity using its 9-digit SIREN number from the Annuaire (Directory) system.
SIREN (Système d'Identification du Répertoire des Entreprises) is the unique 9-digit identifier assigned to French companies by INSEE. Through this endpoint, callers can retrieve the company's legal name, entity type (public/private), administrative status, and directory record details in a single request.
Typical use cases:
- Verifying that a SIREN is registered and active in the PPF Annuaire before sending an e-invoice to a French recipient
- Determining whether a company belongs to the public or private sector in order to select the correct e-invoicing channel
- Checking the diffusible (publishable) status of a legal entity during the onboarding flow
- Retrieving the company's PPF instance ID for use in subsequent directory queries
Endpoint Information
| Property | Value |
|---|---|
| URL | /annuaire/FR/siren/{siren} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/annuaire/FR/siren/123456789' \
--header 'Accept: application/json' \
--header 'R-Auth: <JWT_TOKEN>'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| siren | String | Yes | The 9-digit French SIREN number for the target legal entity |
Path Parameter Values
| Field | Rule | Valid Example | Invalid Example |
|---|---|---|---|
| siren | Exactly 9 digits; leading zeros are preserved | 271688503 | 271-685, 27168850, ABCDEFGHI, 2716885030 |
Responses
200 - Successful Response
{
"siren": "271688503",
"raisonSociale": "SIREN_271688503",
"typeEntite": "Privée assujettie",
"etatAdministratif": "A",
"diffusible": "O",
"historisation": {
"idInstance": 1003843,
"dateDebutEffet": null,
"dateDefinition": null,
"creePar": null,
"masque": null
}
}
400 - Bad Request
Returned when the SIREN parameter does not consist of exactly 9 digits.
{
"error": "VALIDATION_ERROR",
"message": "SIREN must be exactly 9 digits for French companies",
"code": "FR_SIREN_INVALID"
}
Description: The client has sent a value with fewer or more than 9 digits, or a non-numeric character. The SIREN format is validated against the regex pattern ^\d{9}$.
401 - Unauthorized
Returned when the JWT token in the R-Auth header cannot be verified.
{
"error": "UNAUTHORIZED",
"message": "Invalid or expired authentication token",
"code": "AUTH_TOKEN_INVALID"
}
Description: The token has expired, its signature is invalid, or the header is missing. The system internally attempts to obtain a new token; if that also fails, this error is propagated to the client. Token TTL is 50 minutes.
403 - Forbidden
Returned when the authenticated user does not have access rights to the requested SIREN record.
{
"error": "FORBIDDEN",
"message": "Access denied to this resource",
"code": "ACCESS_DENIED"
}
Description: Authentication succeeds, but the authorization layer rejects the request. This may result from PPF Annuaire access policies or user role restrictions.
404 - Not Found
Returned when the provided SIREN number is not registered in the PPF Annuaire.
{
"error": "NOT_FOUND",
"message": "No entity found for SIREN: 271688503",
"code": "COMPANY_NOT_FOUND"
}
Description: Even though the SIREN format is valid, no matching record exists in France's official directory. The company may not yet have registered with PPF, or the record may have been removed.
422 - Unprocessable Entity
Returned when the request is technically valid but cannot be processed due to business logic constraints.
{
"error": "UNPROCESSABLE_ENTITY",
"message": "PPF Annuaire registration failed. Please verify your company information and try again.",
"code": "FR_PPF_ONBOARD_FAILED"
}
Description: Typically triggered by data inconsistencies in the PPF system for the queried SIREN, or when the company is not marked as publishable (diffusible).
500 - Internal Server Error
Returned when an unexpected error occurs while communicating with the upstream PPF Annuaire service.
{
"error": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred while contacting PPF Annuaire",
"code": "GENERAL_ERROR"
}
Description: May be triggered by the upstream PPF API being unreachable, a timeout (default 15,000 ms), or an unexpected response format from the PPF Annuaire service.
17. Search SIRET number GET
Purpose of Use This endpoint queries the PPF (Plateforme Publique de Facturation) Annuaire to retrieve detailed information about a specific French business establishment using its 14-digit SIRET number.
SIRET (Système d'Identification du Répertoire des Établissements) is a unique 14-digit code that identifies a specific establishment (branch, headquarters, factory, etc.) of a French company. The first 9 digits are the company's SIREN number; the last 5 digits are the NIC (Numéro Interne de Classement) code that distinguishes the specific establishment.
Typical use cases:
- Verifying that a SIRET is registered and active in the PPF Annuaire before sending an e-invoice to a French establishment
- Retrieving the branch address (postal code, city, country) and establishment-level invoicing parameters
- Determining whether the establishment is publishable (diffusible) and its administrative status
- Obtaining the
idInstancevalue to use in onboarding or routing flows
Endpoint Information
| Property | Value |
|---|---|
| URL | /annuaire/FR/siret/{siret} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/annuaire/FR/siret/27168850399286' \
--header 'Accept: application/json' \
--header 'R-Auth: <JWT_TOKEN>'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| siret | String | Yes | The 14-digit French SIRET number for the target establishment |
Path Parameter Values
| Field | Rule | Valid Example | Invalid Example |
|---|---|---|---|
| siret | Exactly 14 digits; leading zeros are preserved. The first 9 digits must match the parent company's SIREN. | 27168850399286, 00000000000001 | 2716885039928 (13 digits), 271688503992860 (15 digits), 2716-8850-3992-86, ABCDEFGHIJKLMN |
Responses
200 - Successful Response
{
"siret": "27168850399286",
"siren": "271688503",
"denomination": "Valideur 27168850399286",
"typeEtablissement": "S",
"diffusible": "O",
"etatAdministratif": "A",
"adresse": {
"ligneAdresse1": "test street",
"ligneAdresse2": null,
"ligneAdresse3": null,
"codePostal": "75001",
"localite": "test city",
"codePays": "FR",
"libellePays": "France (la)",
"subDivisionPays": null
},
"historisation": {
"idInstance": 1015764,
"dateDebutEffet": null,
"dateDefinition": null,
"creePar": null,
"masque": null
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| siret | String | The queried 14-digit SIRET number. |
| siren | String | The parent company's 9-digit SIREN number. |
| denomination | String | Official establishment name (may differ from parent company name). |
| typeEtablissement | String | Establishment type (e.g., 'S' = secondary, 'P' = principal). |
| diffusible | String | Publishability flag: "O" = Yes, "N" = No. |
| etatAdministratif | String | Administrative status enum (e.g., "A", "F"). |
| adresse | Object | Establishment address details. |
| historisation | Object | Audit metadata for the record (idInstance, dates, creator, mask). |
400 - Bad Request
Returned when the SIRET parameter does not consist of exactly 14 digits.
{
"error": "VALIDATION_ERROR",
"message": "Invalid SIRET: must be exactly 14 digits",
"code": "FR_SIRET_INVALID"
}
Description: The client has sent a value with fewer or more than 14 digits, or a non-numeric character. The SIRET format is validated against the regex pattern ^\d{14}$.
401 - Unauthorized
Returned when the JWT token in the R-Auth header cannot be verified.
{
"error": "UNAUTHORIZED",
"message": "Invalid or expired authentication token",
"code": "AUTH_TOKEN_INVALID"
}
403 - Forbidden
{
"error": "FORBIDDEN",
"message": "Access denied to this resource",
"code": "ACCESS_DENIED"
}
404 - Not Found
{
"error": "NOT_FOUND",
"message": "No establishment found for SIRET: 27168850399286",
"code": "COMPANY_NOT_FOUND"
}
422 - Unprocessable Entity
{
"error": "UNPROCESSABLE_ENTITY",
"message": "PPF Annuaire registration failed. Please verify your company information and try again.",
"code": "FR_PPF_ONBOARD_FAILED"
}
500 - Internal Server Error
{
"error": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred while contacting PPF Annuaire",
"code": "GENERAL_ERROR"
}
Description: May be triggered by the upstream PPF API being unreachable, a timeout (default 15,000 ms), or an unexpected response format returned by the PPF Annuaire service.
18. PPF Directory Line Instance Lookup GET
Purpose of Use: This endpoint is a live proxy to the PPF Annuaire API. When called, Docnova immediately forwards the request to the PPF's external /ligne-annuaire/id-instance:{idInstance} endpoint, returns the raw PPF response, and does not cache or store the result. The caller receives a real-time snapshot of the directory line as it currently exists in the national PPF Annuaire.
The PPF Annuaire (Portail Public de Facturation Directory) is France's central registry of all VAT-registered companies and their associated Plateformes Agréées, also known as approved e-invoicing platforms. Every company participating in the French e-invoicing mandate must have at least one ligne d'annuaire or directory line entry that specifies:
- Which PA (Plateforme Agréée) the company is connected to, and via which channel
- The company's addressing granularity (
SIREN,SIRET,SUFFIXE, orCODE_ROUTAGE) - The routing and addressing identifiers needed to deliver e-invoices to the company
- Validity dates, effect start and end dates, and historisation metadata
An idInstance is a unique numeric identifier assigned by the PPF to each version of a directory line entry. Because a company's annuaire entry can change over time, for example when switching platforms or updating routing codes, each historical version is preserved and assigned its own idInstance.
This endpoint is used for the following purposes:
- Precise version lookup: Retrieve a specific historical version of a directory line using its immutable
idInstance, even after the entry has been superseded by a newer version. - Annuaire data verification: Verify that a directory line known to Docnova still matches the live PPF Annuaire record for the same instance number. This is used in onboarding diagnostics and reconciliation.
- Platform and routing detail retrieval: Fetch the full
plateforme,etablissement,uniteLegale, andcodeRoutagedetail blocks that are needed to construct valid Peppol / PPF delivery addresses for the target company. - Support and audit use cases: Support teams use this endpoint to inspect the exact PPF record for a given instance, diagnose routing failures, and confirm validity dates.
🔄 Live PPF proxy — no caching: This endpoint makes a real-time call to the PPF Annuaire API on every request. The response reflects the current state of the PPF directory, not a Docnova-stored snapshot. Availability and latency depend on the PPF Annuaire API.
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated by the Spring Security filter chain. The authenticated user principal is extracted. |
| 2 | Input validation | idInstance is checked to be non-blank. A blank value throws a validation error and returns 400. |
| 3 | PPF availability check | If PPF integration is disabled in the Docnova configuration, the service returns null immediately and maps the response to 404 or 503, depending on environment configuration. |
| 4 | External PPF call | Docnova builds the URL /ligne-annuaire/id-instance:{idInstance} and makes an authenticated GET request to the PPF Annuaire API using a cached Bearer token stored in Redis. If the PPF returns 401, Docnova invalidates the cached token, re-authenticates, and retries the request once. |
| 5 | PPF 404 handling | If the PPF returns 404, meaning the instance was not found, Docnova returns null, and the response maps to 404. |
| 6 | Response | Returns HTTP 200 OK with the full AnnuaireLigneAnnuaireResponse JSON object mapped from the PPF response. |
Endpoint Information
| Property | Value |
|---|---|
| URL | /annuaire/FR/directory-line/instance/{idInstance} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
| Integration Type | Live PPF Proxy |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/annuaire/FR/directory-line/instance/{idInstance}' \
--header 'Accept: */*' \
--header 'R-Auth: <jwt-token>'
This endpoint has no query parameters and no request body. The only inputs are the
idInstancepath variable and the authentication token.
Request Parameters
Header Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| R-Auth | string (JWT) | Yes | User session JWT token. Sent without a Bearer prefix. Signed with HS512; sub carries the encrypted user ID, claim carries authorization data, and userType holds CLIENT or ADMIN. |
| Accept | string | No | */* or application/json. Defaults to JSON if omitted. |
Path Parameters
| Parameter | Type | Required | Format / Example | Description |
|---|---|---|---|---|
| idInstance | string (numeric) | Yes | 1013330 | The PPF-assigned unique numeric instance identifier of the directory line entry to retrieve. Assigned by the PPF when a ligne d'annuaire is created or updated. Each historical version of a directory line has a distinct idInstance. Must be non-blank; numeric string format is expected. No UUID format is required. |
Responses
200 - Successful Response
Returns HTTP 200 OK with an AnnuaireLigneAnnuaireResponse object. The structure is nested: top-level addressing fields are accompanied by embedded plateforme, uniteLegale, etablissement, historisation, and codeRoutage objects.
{
"identifiantAdressage": "123456789",
"matriculePlateforme": "0001",
"identifiantRoutage": "0009:0001",
"siren": "123456789",
"siret": "12345678900014",
"suffixeAdressage": null,
"dateFinEffet": null,
"dateFinEffective": null,
"historisation": {
"idInstance": 1013330,
"dateDebutEffet": "2026-01-01",
"dateDefinition": "2025-12-20T09:00:00Z",
"creePar": "DOCNOVA_PA",
"masque": false
},
"plateforme": {
"typePlateforme": "PA",
"matriculePlateforme": "0001",
"raisonSocialePlateforme": "Melasoft SAS",
"nomCommercialPlateforme": "Docnova",
"contactOuUrlPlateforme": "https://docnova.ai",
"statutPlateforme": "ACTIF"
},
"uniteLegale": {
"siren": "123456789",
"raisonSociale": "ACME FRANCE SAS",
"typeEntite": "PM",
"etatAdministratif": "A",
"diffusible": "O"
},
"etablissement": {
"siret": "12345678900014",
"siren": "123456789",
"denomination": "ACME FRANCE SAS - SIEGE",
"typeEtablissement": "SIEGE",
"diffusible": "O",
"etatAdministratif": "A",
"adresse": {
"ligneAdresse1": "10 RUE DE LA PAIX",
"ligneAdresse2": null,
"ligneAdresse3": null,
"codePostal": "75001",
"localite": "PARIS",
"codePays": "FR",
"libellePays": "France",
"subDivisionPays": null
},
"donneesB2gComplementaires": null
},
"codeRoutage": null
}
Response Body — Top-Level Fields
| Field | Type | Nullable | Description |
|---|---|---|---|
| identifiantAdressage | string | Yes | The primary addressing identifier of the company in the PPF Annuaire. Contains the SIREN (9 digits) when maille is SIREN, SIRET (14 digits) when maille is SIRET, or the routing code value for CODE_ROUTAGE. |
| matriculePlateforme | string | Yes | PPF registration code of the Plateforme Agréée that handles this company's e-invoices. Used as the network address of the PA in Peppol routing. |
| identifiantRoutage | string | Yes | Full routing identifier in the format {schemeId}:{value}, for example 0009:0001. Used by the PPF to route incoming e-invoices to the correct PA endpoint. |
| siren | string (9) | Yes | The 9-digit SIREN of the company this directory line belongs to. |
| siret | string (14) | Yes | The 14-digit SIRET of the specific establishment, if this entry is registered at SIRET granularity. null for SIREN-level entries. |
| suffixeAdressage | string | Yes | Suffix appended to the SIRET for sub-unit identification. Populated only when the annuaire maille is SUFFIXE. |
| dateFinEffet | LocalDate | Yes | The planned end date of this directory line's validity. null if the entry is open-ended and still active. |
| dateFinEffective | LocalDate | Yes | The actual effective end date as confirmed by the PPF. May differ from dateFinEffet if the closure was processed at a different time. |
| historisation | object | Yes | Version and audit metadata assigned by the PPF to this specific instance. See historisation below. |
| plateforme | object | Yes | Full detail of the Plateforme Agréée associated with this directory line. See plateforme below. |
| uniteLegale | object | Yes | Legal entity (SIREN-level) details of the company. See uniteLegale below. |
| etablissement | object | Yes | Establishment (SIRET-level) details including address and B2G configuration. See etablissement below. |
| codeRoutage | object | Yes | Routing code detail block. Populated only when the annuaire maille is CODE_ROUTAGE. null for SIREN, SIRET, and SUFFIXE entries. See codeRoutage below. |
historisation — Version & Audit Metadata
| Field | Type | Nullable | Description |
|---|---|---|---|
| idInstance | integer | No | The PPF-assigned unique instance number of this directory line version. Matches the idInstance supplied in the request path. |
| dateDebutEffet | LocalDate | Yes | The date from which this directory line version became effective in the PPF. |
| dateDefinition | OffsetDateTime | Yes | The exact date-time when this instance was defined, created, or updated in the PPF Annuaire. ISO 8601 with timezone offset. |
| creePar | string | Yes | Identifier of the actor, PA matricule or PPF internal identifier, that created this instance. |
| masque | boolean | Yes | If true, this directory line has been hidden or masked in the PPF Annuaire. A masked entry is not visible to other PAs for routing purposes. |
plateforme — Associated Plateforme Agréée
| Field | Type | Nullable | Description |
|---|---|---|---|
| typePlateforme | string | Yes | Platform type code. Typically PA (Plateforme Agréée) or PPF (Portail Public de Facturation itself). |
| matriculePlateforme | string | Yes | The PPF-assigned registration number of the platform. Used as the routing endpoint identifier in e-invoice transmission. |
| raisonSocialePlateforme | string | Yes | Legal company name of the platform operator. |
| nomCommercialPlateforme | string | Yes | Commercial or brand name of the platform, for example Docnova. |
| contactOuUrlPlateforme | string | Yes | Contact email address or URL of the platform for support or integration queries. |
| statutPlateforme | string | Yes | Administrative status of the platform in the PPF registry. Common values: ACTIF (active), SUSPENDU (suspended), FERME (closed). |
uniteLegale — Legal Entity (SIREN Level)
| Field | Type | Nullable | Description |
|---|---|---|---|
| siren | string (9) | Yes | 9-digit SIREN of the legal entity. |
| raisonSociale | string | Yes | Legal company name registered with INSEE. |
| typeEntite | string | Yes | Entity type: PM (Personne Morale / legal person) or PP (Personne Physique / natural person). |
| etatAdministratif | string | Yes | Administrative status from INSEE: A (Actif / active) or C (Cessé / ceased). |
| diffusible | string | Yes | INSEE diffusion flag: O (diffusible / public) or N (non-diffusible / private). Non-diffusible entities have restricted access in public directories. |
etablissement — Establishment (SIRET Level)
| Field | Type | Nullable | Description |
|---|---|---|---|
| siret | string (14) | Yes | 14-digit SIRET of the establishment. |
| siren | string (9) | Yes | Parent SIREN of the establishment. |
| denomination | string | Yes | Establishment name or designation. May include branch suffix, for example - SIEGE. |
| typeEtablissement | string | Yes | Type of establishment: SIEGE (registered head office) or SECONDAIRE (secondary establishment). |
| diffusible | string | Yes | INSEE diffusion flag: O or N. |
| etatAdministratif | string | Yes | Administrative status: A (active) or F (fermé / closed). |
| adresse | object | Yes | Postal address of the establishment. See etablissement.adresse fields below. |
| donneesB2gComplementaires | object | Yes | B2G (Business-to-Government) supplementary data. null for purely B2B companies. See donneesB2gComplementaires below. |
etablissement.adresse — Postal Address
| Field | Type | Nullable | Description |
|---|---|---|---|
| ligneAdresse1 | string | Yes | First address line, including street number and name. |
| ligneAdresse2 | string | Yes | Second address line, for example building, floor, or additional location information. |
| ligneAdresse3 | string | Yes | Third address line for additional details. |
| codePostal | string | Yes | French postal code, 5 digits. |
| localite | string | Yes | City or locality name. |
| codePays | string (2) | Yes | ISO 3166-1 alpha-2 country code, for example FR. |
| libellePays | string | Yes | Full country name in French. |
| subDivisionPays | string | Yes | Country subdivision code (ISO 3166-2). Rare; mostly null for French addresses. |
etablissement.donneesB2gComplementaires — B2G Supplementary Data
| Field | Type | Nullable | Description |
|---|---|---|---|
| gestionEngagementJuridique | boolean | Yes | Whether legal commitment management is enabled for this entity in the B2G context. |
| gestionStatutMiseEnPaiement | boolean | Yes | Whether payment status management is active. |
| gestionCodeService | boolean | Yes | Whether service code management is enabled. |
| moaUniquement | boolean | Yes | If true, this entity operates as buyer (MOA — Maître d'Ouvrage) only in B2G flows. |
| gestionEngagementJuridiqueOuService | boolean | Yes | Combined flag indicating whether legal commitment or service code management is enabled. |
| moa | boolean | Yes | Whether this entity is designated as MOA (project owner / buyer) in the B2G procurement flow. |
codeRoutage — Routing Code Detail (CODE_ROUTAGE Maille Only)
| Field | Type | Nullable | Description |
|---|---|---|---|
| identifiantRoutage | string | Yes | The routing code identifier assigned to this sub-unit. |
| typeIdentifiantRoutage | string | Yes | Type of the routing identifier, also known as the scheme. |
| libelleCodeRoutage | string | Yes | Human-readable label for the routing code. |
| gestionEngagementJuridique | boolean | Yes | B2G legal commitment flag at routing code level. |
| etatAdministratif | string | Yes | Administrative status of this routing code: A (active) or F (closed). |
| adresse | object | Yes | Postal address associated with this routing code. Same structure as etablissement.adresse. |
Enum Values
FrancePpfMaille — Annuaire Addressability Granularity
Determines which of the nested objects is populated and which top-level identifier is used.
| Value | identifiantAdressage Contains | Populated Nested Object | Description |
|---|---|---|---|
| SIREN | 9-digit SIREN | uniteLegale | Company is registered at SIREN level. All invoices addressed to this company, regardless of establishment, are routed to the same PA. |
| SIRET | 14-digit SIRET | etablissement | Company is registered at establishment level. Different SIRET numbers may route to different PAs. |
| SUFFIXE | SIRET + suffix | etablissement + suffixeAdressage | Sub-unit of an establishment identified by an additional suffix. Used for large organizations with complex internal routing. |
| CODE_ROUTAGE | routing code value | codeRoutage | Custom routing code; used by large corporate groups where neither SIREN nor SIRET granularity is sufficient. |
All error responses share the following structure:
{
"errorMessage": "<human-readable message>",
"errorType": "<error type key>",
"errorTitle": "<HTTP status name>",
"status": 404,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/1013330"
}
400 - Bad Request
Returned when the idInstance path variable is present but empty or blank.
{
"errorMessage": "idInstance must not be blank",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/"
}
Condition: The idInstance path variable is present but empty or blank, for example /instance/ or /instance/ .
Server behavior: FranceAnnuaireApiService.validateNotBlank() throws IllegalArgumentException; RestExceptionHandler maps it to 400.
401 - Unauthorized
Returned when the R-Auth header is missing, malformed, or the JWT token is expired.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/1013330"
}
Condition: The R-Auth header is missing, malformed, or the JWT exp claim has passed.
Server behavior: Spring Security filter chain rejects the request before the controller is reached.
404 - Not Found
Returned when the PPF Annuaire API returns 404.
{
"errorMessage": "Not Found",
"errorType": "NOT_FOUND",
"errorTitle": "NOT_FOUND",
"status": 404,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/1013330"
}
Condition: The PPF Annuaire API returned 404, meaning no directory line exists for the given idInstance, or the instance number has never been assigned by the PPF.
Server behavior: FranceAnnuaireApiService.doGetAttempt() receives a 404 from PPF and returns null; the controller's toResponse(null) maps to a 404 HTTP response.
500 - Internal Server Error
Returned when an unexpected exception occurs while communicating with the PPF Annuaire API.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/1013330"
}
Condition: An unexpected exception occurred while communicating with the PPF Annuaire API, such as network timeout, malformed PPF response, or an unhandled HTTP error status from the PPF.
Server behavior: The try/catch in doGetAttempt() catches the exception and rethrows it as a RuntimeException; RestExceptionHandler maps it to 500.
503 - Service Unavailable
Returned when the PPF Annuaire integration is disabled in the Docnova server configuration.
{
"errorMessage": "PPF integration is currently unavailable",
"errorType": "SERVER_ERROR",
"errorTitle": "SERVICE_UNAVAILABLE",
"status": 503,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/annuaire/FR/directory-line/instance/1013330"
}
Condition: The PPF Annuaire integration is disabled in the Docnova server configuration (config.isEnabled() = false). This typically happens in maintenance or staging environments where the PPF connection is intentionally turned off.
Server behavior: The service returns null immediately without calling PPF; response mapping returns 404 or 503, depending on environment configuration.
19. Reporting Create Report POST
Purpose of Use: This endpoint manually creates a France Flux 10 e-reporting report occurrence — a B2C or B2B/international transaction e-report, or a payment (collection) e-report — for cases where the caller's own system holds the business data directly and needs to register a report occurrence without going through Docnova's invoice pipeline. Docnova normally generates these reports automatically from invoices/payments processed through the platform; this endpoint is the manual alternative.
This endpoint is used for the following purposes:
- B2C sales e-reporting: Submitting a
TRANSACTION_B2Coccurrence for a domestic sale to an individual customer that never went through Docnova as an invoice. - B2B international invoice e-reporting: Submitting a
TRANSACTION_B2Boccurrence for an invoice issued to a non-French B2B counterparty. - Payment (collection) e-reporting: Submitting a
PAYMENT_B2B/PAYMENT_B2Coccurrence for the collection of an invoice already reported elsewhere. - Historical/migration loading: Bulk-registering past e-reporting occurrences during onboarding.
Important: One request body shape (FranceReportRequest) is shared by all four report families — not every field is valid for every family. Sending invoiceId on any item, or a structure outside the four supported families (the internal TRANSACTION_COMBINED/PAYMENT_COMBINED batch types are never valid here), rejects the whole request.
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated by the Spring Security filter chain. The authenticated user's uid is extracted via @AuthenticationPrincipal JwtUser. |
| 2 | Company resolution | companyId (or apiKey, if companyId is omitted) resolves the target company. If neither is supplied, the request is rejected. |
| 3 | Structure & cardinality validation | structure is checked against the four supported manual families; item count is checked against the family's rule (exactly 1 for TRANSACTION_B2B/PAYMENT_B2B/PAYMENT_B2C, 1..N for TRANSACTION_B2C). |
| 4 | Declarant role validation | declarantRoleCode is checked per family — required explicit SE/BY for TRANSACTION_B2B; defaults to SE for the others, anything else rejected. |
| 5 | VAT breakdown & field validation | Each item's vatBreakdown is checked for correct grouping and family-specific field restrictions (e.g. taxCategoryCode rejected for TRANSACTION_B2C). |
| 6 | Duplicate check | The request is checked against existing invoices/reports in the system for the same invoice number + issue date. |
| 7 | Persistence | A new report record is created in DRAFT status and saved. |
| 8 | Response | Returns HTTP 200 OK with the full FranceReportResponse JSON object. |
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/report |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location --request POST 'https://api-fr-stage.docnova.ai/reporting/FR/report' \
--header 'Accept: */*' \
--header 'Content-Type: application/json' \
--header 'R-Auth: <jwt-token>' \
--data '{
"structure": "TRANSACTION_B2C",
"companyId": "<company-id>",
"items": [
{
"invoiceNumber": "<invoice-number>",
"invoiceIssueDate": "2026-04-08",
"currency": "EUR",
"category": "GOODS",
"vatBreakdown": [
{ "taxRate": 20, "taxableAmount": 500.00, "taxAmount": 100.00 }
]
}
]
}'
Request Parameters
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| structure | string (enum) | Yes | One of TRANSACTION_B2B, TRANSACTION_B2C, PAYMENT_B2B, PAYMENT_B2C. TRANSACTION_COMBINED/PAYMENT_COMBINED are internal batch types and are rejected if sent. |
| companyId | string (UUID) | Required unless apiKey sent | Target company. |
| apiKey | string | Required unless companyId sent | Alternative way to identify the target company. |
| declarantRoleCode | string (enum) | See description | SE (Seller) or BY (Buyer/self-billing). Required explicitly for TRANSACTION_B2B — no default. Defaults to SE for TRANSACTION_B2C/PAYMENT_B2B/PAYMENT_B2C; any other value is rejected. |
| items | array | Yes, non-empty | See item fields below. Cardinality: exactly 1 for TRANSACTION_B2B/PAYMENT_B2B/PAYMENT_B2C; 1..N for TRANSACTION_B2C (category slices of one invoice). |
Item Fields (items[])
| Field | Tx B2B | Tx B2C | Pay B2B | Pay B2C | Description |
|---|---|---|---|---|---|
| invoiceId | 🚫 | 🚫 | 🚫 | 🚫 | Must never be sent — rejects the whole request if present on any item. |
| invoiceNumber | Required | Required | Required | Optional | Occurrence's invoice number. |
| invoiceIssueDate | Required | Required | Required | Required | Invoice issue date (payment reference date for Payment). |
| currency | Required | Required | Required | Required | Any ISO 4217 for Transactions; EUR only for Payments. |
| category | not used | Required | n/a | n/a | GOODS/SERVICE/NON_TAXABLE/MARGIN_SCHEME. MIXED is never accepted — split into separate items first. |
| paymentDate | n/a | n/a | Required | Required | Collection date. |
| counterpartyCompanyId / counterpartyVatId | Optional | 🚫 must be absent | Optional | 🚫 must be absent | Counterparty business identifiers. |
| vatAmount | Server-derived for EUR; caller-required for non-EUR | Server-derived for EUR; caller-required for non-EUR | n/a | n/a | Canonical EUR VAT amount — Docnova does not convert currency for a non-EUR occurrence. |
| vatBreakdown | Required, non-empty | Required, non-empty | Required, non-empty | Required, non-empty | See VAT breakdown fields below. |
taxableAmountand (for Payments)collectedAmount/collectedAmountExclVat/collectedVatAmountare always server-derived fromvatBreakdown— do not send them, they are silently overwritten.
VAT Breakdown Fields (items[].vatBreakdown[])
| Field | Tx B2B | Tx B2C | Payments | Description |
|---|---|---|---|---|
| taxRate | Required* | Required* | Required* | Plain percentage, must be a valid French VAT rate. *Not required only when the item's taxableAmount is exactly zero. |
| taxableAmount / taxAmount | Optional (recommended) | Optional (recommended) | Optional (recommended) | Feeds the server-derived totals — omitting it understates them. |
| taxCategoryCode / vatExemptionReasonCode / vatExemptionReason | Optional | 🚫 rejected | do not send (ignored) | B2B-only reverse-charge/exemption concept. |
Duplicate VAT rate buckets within one item are rejected, not merged: TRANSACTION_B2B groups by rate and normalized taxCategoryCode/vatExemptionReasonCode; every other family groups by rate alone.
Responses
200 - Successful Response
Returns HTTP 200 OK with the newly created FranceReportResponse (status DRAFT).
{
"reportId": "<report-id>",
"status": "DRAFT",
"reportType": "TRANSACTION_B2C",
"source": "ERP",
"invoiceNumber": "<invoice-number>",
"occurrenceDate": "2026-04-08",
"currency": "EUR",
"itemCount": 1,
"totalAmount": 500.00,
"createdTime": "2026-04-08T09:12:00",
"ppfAckStatus": null,
"ppfErrorMessage": null,
"ppfErrorCode": null
}
See the Reporting Search Status documentation for the full response field reference — ppfAckStatus/ppfErrorCode/ppfErrorMessage remain null until the occurrence is later included in a submitted batch.
400 - Bad Request: Missing Items
Returned when items is missing or empty.
{
"errorMessage": "Report items must contain at least one item",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
400 - Bad Request: Unsupported Structure
{
"errorMessage": "Manual report creation is not supported for this report structure.",
"errorType": "MANUAL_REPORT_STRUCTURE_NOT_SUPPORTED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: structure is missing, or is one of the internal batch types TRANSACTION_COMBINED/PAYMENT_COMBINED, or any other unsupported value.
400 - Bad Request: invoiceId Not Allowed
{
"errorMessage": "invoiceId must not be provided when creating a manual report. Reports for invoices already registered in Docnova must be handled through the existing invoice.",
"errorType": "MANUAL_REPORT_INVOICE_ID_NOT_ALLOWED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: invoiceId was set on an item. This field exists on the shared DTO only for internal/automatic flows — never send it manually.
400 - Bad Request: Wrong Item Count
{
"errorMessage": "A manual TRANSACTION_B2B report request must contain exactly one item — TRANSACTION_B2B is one occurrence per invoice.",
"errorType": "MANUAL_TRANSACTION_B2B_MUST_HAVE_SINGLE_ITEM",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: items does not contain exactly one entry for TRANSACTION_B2B — analogous MANUAL_PAYMENT_B2B_MUST_HAVE_SINGLE_ITEM / MANUAL_PAYMENT_B2C_MUST_HAVE_SINGLE_ITEM error types apply the same rule to PAYMENT_B2B/PAYMENT_B2C. Only TRANSACTION_B2C may carry more than one item.
400 - Bad Request: VAT Breakdown Not Grouped
{
"errorMessage": "The submitted VAT breakdown is not correctly grouped for TRANSACTION_B2C: duplicate rate=20 - this family groups by VAT rate only, merge same-rate entries into one before submitting.",
"errorType": "MANUAL_REPORT_VAT_BREAKDOWN_NOT_GROUPED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: Two or more vatBreakdown entries on the same item resolve to the same grouping key — the request must already be grouped, duplicates are rejected rather than merged automatically.
400 - Bad Request: B2C VAT Breakdown Field Not Allowed
{
"errorMessage": "TRANSACTION_B2C vatBreakdown entries must not set taxCategoryCode, vatExemptionReasonCode or vatExemptionReason — these fields have no B2C XML representation (only taxRate/taxableAmount/taxAmount are used); they are reserved for TRANSACTION_B2B.",
"errorType": "MANUAL_TRANSACTION_B2C_VAT_BREAKDOWN_FIELD_NOT_ALLOWED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
400 - Bad Request: Payment Currency Must Be EUR
{
"errorMessage": "Manual payment reports must be in EUR: invoice=<invoice-number>, currency=GBP",
"errorType": "MANUAL_PAYMENT_CURRENCY_MUST_BE_EUR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: PAYMENT_B2B/PAYMENT_B2C currency (from currency and/or paymentCurrency) does not resolve to EUR, or the two fields disagree with each other.
401 - Unauthorized
Returned when the R-Auth header is missing, malformed, or the JWT token is expired.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
409 - Conflict: Duplicate Report
{
"errorMessage": "This transaction already exists in the system and cannot be entered manually. An invoice with invoice number '<invoice-number>' and issue date '2026-04-05' already exists in the system. A manual report cannot be created for this invoice.",
"errorType": "MANUAL_REPORT_NOT_ALLOWED_EXISTING_SYSTEM_TRANSACTION",
"errorTitle": "CONFLICT",
"status": 409,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
Condition: An invoice with the same invoice number and issue date already exists in Docnova (either as a real invoice, or as a previously-created report for the same occurrence) — a manual report cannot duplicate it. The analogous MANUAL_PAYMENT_REPORT_NOT_ALLOWED_EXISTING_INVOICE error is used when the duplicate check is specifically against payment reporting for an invoice already present in the system.
500 - Internal Server Error
Returned when an unexpected runtime exception occurs while processing the request — for example, if the target company's France module is not enabled/configured, or a database/mapping failure occurs.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report"
}
20. Reporting Edit Report PUT
Purpose of Use: Replaces the content of an existing manually-created report occurrence. Used to correct a mistake in a report still in DRAFT, or to resubmit a CORRECTABLE report that PPF rejected at content level. For Payment reports, this is also usable on MERGED reports (unless a transmission for them is currently in flight) — Payment does not share Transaction's "locked once merged" rule.
Typical use cases:
- Fixing a typo or wrong amount in a
DRAFTreport before it is picked up by the next batch. - Resubmitting a
CORRECTABLEoccurrence after PPF rejected the batch it was part of. - Correcting a
MERGEDpayment report before its next transmission attempt.
Important: This is a full replacement, not a patch — the entire items array is replaced. For a multi-item TRANSACTION_B2C occurrence, resend every item, not just the one that changed.
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated; uid extracted. |
| 2 | Company resolution & authorization | The report's owning company is resolved from reportId; the caller must hold ADMIN on that company or the request is rejected. |
| 3 | Provenance check | The target report must have been created manually and be one of the four manual-supported families — editing a Docnova-generated (automatic) report through this endpoint is rejected. |
| 4 | Same validation as Create | Structure/cardinality/declarant-role/VAT-breakdown checks all reapply, identically to POST /reporting/FR/report. |
| 5 | Editable-status check | Transaction family: only DRAFT/CORRECTABLE may be edited. Payment family: DRAFT/CORRECTABLE/MERGED may be edited, unless the report's current transmission is still in flight (awaiting PPF acknowledgment). |
| 6 | Persistence | The entire items array is replaced on the existing record; for Transaction, a CORRECTABLE report returns to DRAFT. |
| 7 | Response | Returns HTTP 200 OK with the updated FranceReportResponse. |
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/report/{reportId} |
| Method | PUT |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) — caller must additionally be ADMIN on the report's owning company |
Example Request
curl --location --request PUT 'https://api-fr-stage.docnova.ai/reporting/FR/report/<report-id>' \
--header 'Accept: */*' \
--header 'Content-Type: application/json' \
--header 'R-Auth: <jwt-token>' \
--data '{
"structure": "TRANSACTION_B2C",
"companyId": "<company-id>",
"items": [
{
"invoiceNumber": "<invoice-number>",
"invoiceIssueDate": "2026-04-08",
"currency": "EUR",
"category": "GOODS",
"vatBreakdown": [
{ "taxRate": 20, "taxableAmount": 550.00, "taxAmount": 110.00 }
]
}
]
}'
Request Parameters
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| reportId | UUID | Yes | The Docnova system UUID of the report to edit. Obtained from a prior Create response, or from GET /reporting/FR/list. |
Body Parameters
Same shape as POST /reporting/FR/report — see the Reporting Create Report documentation for the full structure/companyId/declarantRoleCode/items/VAT-breakdown field reference. All the same per-family validation rules apply identically on edit.
Responses
200 - Successful Response
Returns HTTP 200 OK with the updated FranceReportResponse — same shape as Create's response.
400 - Bad Request
{
"errorMessage": "Report not found: <report-id>",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
Condition: No report exists in Docnova for the given reportId.
400 - Bad Request: Not Manually Created
{
"errorMessage": "This report was not created manually and cannot be edited or deleted through the manual report endpoints.",
"errorType": "MANUAL_REPORT_ACTION_NOT_ALLOWED_FOR_AUTO_REPORT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
Condition: The target report was generated automatically by Docnova (not through this manual API) — only manually-created reports can be edited here.
400 - Bad Request: Transmission In Flight
{
"errorMessage": "This report's transmission is still in flight (awaiting PPF acknowledgment) and cannot be edited or deleted yet.",
"errorType": "MANUAL_REPORT_TRANSMISSION_IN_FLIGHT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
Condition: A MERGED Payment report whose containing transmission has already been dispatched to PPF and is still awaiting acknowledgment — wait for the current transmission to resolve before editing.
For a
TRANSACTION_B2B/TRANSACTION_B2Creport in a non-editable status (notDRAFTorCORRECTABLE), the request is rejected with the message "Only DRAFT or CORRECTABLE reports can be edited", surfaced the same way as the other 400 errors above.
The same body-validation errors documented under Reporting Create Report (unsupported structure, invoiceId present, wrong item count, VAT breakdown grouping/field errors, non-EUR payment currency) apply identically here.
401 - Unauthorized
Returned both when the R-Auth header is missing/expired, and when the caller is authenticated but is not ADMIN on the report's owning company.
{
"errorMessage": "User is not authorized for this operation",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
This endpoint returns
401, not403, for both "not authenticated" and "authenticated but insufficient permission" cases. Distinguish the two byerrorMessage/errorTyperather than by HTTP status alone.
500 - Internal Server Error
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
21. Reporting Delete Report DELETE
Purpose of Use: Permanently deletes (or, where the underlying data has already been transmitted, clears to an empty correction marker) a manually-created report occurrence. Used to remove a report that was created in error, before it has progressed too far in its lifecycle to be safely deleted outright.
Important — Transaction vs Payment deletion behavior differs:
- Transaction (
TRANSACTION_B2B/TRANSACTION_B2C): only deletable whileDRAFTorCORRECTABLE. AMERGEDtransaction report can never be deleted through this endpoint. - Payment (
PAYMENT_B2B/PAYMENT_B2C): aDRAFTreport is hard-deleted. AMERGEDreport can still be "deleted" — provided its transmission is not currently in flight — but is not physically removed: it is cleared to an empty correction marker (content fields reset, flagged as a pending correction) rather than hard-deleted, since the underlying PPF submission history must be preserved.
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated; uid extracted. |
| 2 | Company resolution & authorization | The report's owning company is resolved from reportId; the caller must hold ADMIN on that company. |
| 3 | Provenance check | The target report must be manually-created and one of the four manual-supported families. |
| 4 | Status/family-specific deletion rule | See "Important" above — Transaction requires DRAFT/CORRECTABLE; Payment allows MERGED (converted to a correction marker) but blocks if a transmission is in flight. |
| 5 | Response | Returns HTTP 204 No Content on success. |
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/report/{reportId} |
| Method | DELETE |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) — caller must additionally be ADMIN on the report's owning company |
Example Request
curl --location --request DELETE 'https://api-fr-stage.docnova.ai/reporting/FR/report/<report-id>' \
--header 'Accept: */*' \
--header 'R-Auth: <jwt-token>'
This endpoint has no query parameters and no request body. The only input is the
reportIdpath variable and the authentication token.
Request Parameters
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| reportId | UUID | Yes | The Docnova system UUID of the report to delete. |
Responses
204 - Successful Response
Returns HTTP 204 No Content, empty body. The report has been deleted (Transaction) or cleared to a correction marker (Payment, if it was MERGED).
400 - Bad Request
{
"errorMessage": "Report not found",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
400 - Bad Request: Not Deletable
{
"errorMessage": "Transaction reports that are merged into an in-flight or already-submitted transmission cannot be deleted.",
"errorType": "MANUAL_TRANSACTION_REPORT_NOT_DELETABLE",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
Condition: A TRANSACTION_B2B/TRANSACTION_B2C report is not currently in a deletable status (DRAFT/CORRECTABLE).
400 - Bad Request: Transmission In Flight
{
"errorMessage": "This report's transmission is still in flight (awaiting PPF acknowledgment) and cannot be edited or deleted yet.",
"errorType": "MANUAL_REPORT_TRANSMISSION_IN_FLIGHT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
Condition: A MERGED Payment report whose containing transmission is currently awaiting PPF acknowledgment.
400 - Bad Request: Not Manually Created
{
"errorMessage": "This report was not created manually and cannot be edited or deleted through the manual report endpoints.",
"errorType": "MANUAL_REPORT_ACTION_NOT_ALLOWED_FOR_AUTO_REPORT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
401 - Unauthorized
Returned both when the R-Auth header is missing/expired, and when the caller is authenticated but is not ADMIN on the report's owning company.
{
"errorMessage": "User is not authorized for this operation",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
500 - Internal Server Error
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/report/<report-id>"
}
22. Reporting Get XML GET
Purpose of Use: Downloads the raw XML content that was (or would be) submitted to PPF for a single report occurrence, returned directly as application/xml rather than wrapped in a JSON envelope. Used for legal archival of the exact document transmitted, or to inspect the generated XML for troubleshooting.
This endpoint is used for the following purposes:
- Compliance archival: Storing the exact XML transmitted to PPF for a given report, for legal retention requirements.
- Pre-submission preview: Inspecting what the generated XML will look like for a
DRAFTreport before it is submitted. - Rejection diagnosis: Reviewing the exact XML that was sent, when investigating a content-level PPF rejection.
Important — XML source depends on report state:
| Report State | XML Source |
|---|---|
| Report has its own stored XML | Returned as-is from storage — the exact document already transmitted. |
| MERGED into a batch, no own stored XML | Inherited from the parent batch's stored XML. |
| Neither of the above (e.g. still DRAFT) | Generated on the fly as a preview — reflects the current item content, not yet a submitted document. |
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated; uid extracted. |
| 2 | Company resolution & authorization | The report's owning company is resolved from reportId; the caller must hold ADMIN on that company. |
| 3 | XML resolution | See the "Important" table above — stored XML, inherited batch XML, or a generated preview, in that priority order. |
| 4 | Response | Returns HTTP 200 OK with the raw XML string as the response body (Content-Type: application/xml), not a JSON wrapper. |
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/xml/{reportId} |
| Method | GET |
| Content-Type | application/xml |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) — caller must additionally be ADMIN on the report's owning company |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/reporting/FR/xml/<report-id>' \
--header 'Accept: application/xml' \
--header 'R-Auth: <jwt-token>'
This endpoint has no query parameters and no request body. The only input is the
reportIdpath variable and the authentication token.
Request Parameters
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| reportId | UUID | Yes | The Docnova system UUID of the report whose XML you want to retrieve. |
Responses
200 - Successful Response
Returns HTTP 200 OK with the raw XML document as the response body (Content-Type: application/xml) — not JSON.
<?xml version="1.0" encoding="UTF-8"?>
<TransactionReport>
...
</TransactionReport>
400 - Bad Request
{
"errorMessage": "Report not found",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/xml/<report-id>"
}
401 - Unauthorized
Returned both when the R-Auth header is missing/expired, and when the caller is authenticated but is not ADMIN on the report's owning company.
{
"errorMessage": "User is not authorized for this operation",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/xml/<report-id>"
}
500 - Internal Server Error
Returned when an unexpected error occurs — for example if the report is MERGED but its parent batch record cannot be found, or S3 retrieval of a stored XML fails.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/xml/<report-id>"
}
23. Reporting Search Status GET
Purpose of Use: This endpoint fetches the full detail and current status snapshot of a single France PPF report record identified by its Docnova-assigned reportId. It is the primary single-record status lookup used by the Docnova frontend to display the detail view of a specific report, and can be called programmatically to poll for status changes after a report has been submitted.
Under the French e-invoicing mandate, mandatory from 01/09/2026, every B2B/B2C transaction data and payment report sent to the PPF (Portail Public de Facturation) passes through a multi-stage lifecycle. The PPF asynchronously returns an acknowledgement (accusé de réception) — either Ok, Error, Pending, or Processing. This endpoint exposes the most recently persisted version of that acknowledgement alongside the full report record.
This endpoint is used for the following purposes:
- Single-report detail view: The frontend calls this endpoint after a user clicks on a specific report in the reporting list to show its full detail, including PPF flow ID, rejection reason, and submission timeline.
- Status verification after submission: Integrations can poll this endpoint after a report submission to determine whether the PPF has accepted or rejected it without fetching the full list.
- PPF error diagnosis: When a report is
REJECTED, the response includesppfErrorCodeandppfErrorMessagepopulated from the PPF acknowledgement detail, allowing developers and support teams to understand the exact rejection reason. - Deadline monitoring: The
submissionDeadlinefield is returned, enabling client applications to display urgency indicators for reports not yet submitted.
Important: This endpoint reads the cached status stored in the Docnova database. It does not actively call the PPF API on each request. The PPF acknowledgement status is refreshed by a background scheduler (pollSingleReportStatus) that periodically queries the PPF and updates the stored record. To see the very latest PPF status, the background polling must have run since the last PPF state change.
Server-Side Flow
| Step | Process | Description |
|---|---|---|
| 1 | Authentication | The R-Auth JWT is validated by the Spring Security filter chain. The authenticated user's uid is extracted via @AuthenticationPrincipal JwtUser. |
| 2 | Report lookup | The service calls reportRepository.findById(reportId). If no record exists for this UUID, IllegalArgumentException("Report not found") is thrown and mapped to 400. |
| 3 | DTO mapping | The found FranceReportEntity is mapped to FranceReportResponse via toResponse(). All persisted fields, including PPF acknowledgement data, are included. |
| 4 | Response | Returns HTTP 200 OK with the full FranceReportResponse JSON object. |
🛰️ Background PPF polling (separate process): A scheduler (
pollSingleReportStatus) periodically calls the PPF's flow status API, maps the PPF acknowledgement (Ok → ACCEPTED,Error → REJECTED) and persists the updated status back to the database. This endpoint reads that persisted state.
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/status/{reportId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/reporting/FR/status/{reportId}' \
--header 'Accept: */*' \
--header 'R-Auth: <jwt-token>'
This endpoint has no query parameters and no request body. The only input is the
reportIdpath variable and the authentication token.
Request Parameters
Path Parameters
| Parameter | Type | Required | Format / Example | Description |
|---|---|---|---|---|
| reportId | UUID | Yes | 0034cdf6-3032-4fe1-b276-21a83191aeee | The Docnova system UUID of the specific France report record to retrieve. Obtained from the reportId field of the GET /reporting/FR/list response. |
Responses
200 - Successful Response
Returns HTTP 200 OK with a single FranceReportResponse JSON object.
{
"reportId": "0034cdf6-3032-4fe1-b276-...",
"status": "ACCEPTED",
"reportType": "TRANSACTION_B2C",
"source": "PORTAL",
"category": "SERVICE",
"senderSiren": "123456789",
"ppfFlowId": "FRR-10.3-20260609-00042",
"trackingId": "TRK-9988776655",
"invoiceId": "aaaabbbb-cccc-dddd-eeee-...",
"invoiceNumber": "INV-2026-00451",
"itemCount": 3,
"totalAmount": 4850.00,
"submittedTime": "2026-06-09T10:15:00",
"createdTime": "2026-06-09T10:14:32",
"submissionDeadline": "2026-06-19T23:59:59",
"ppfAckStatus": "Ok",
"ppfErrorMessage": null,
"ppfErrorCode": null,
"lastStatusCheckTime": "2026-06-09T10:16:00"
}
{
"reportId": "0034cdf6-3032-4fe1-b276-...",
"status": "REJECTED",
"ppfAckStatus": "Error",
"ppfErrorMessage": "Le SIREN déclarant n'est pas enregistré dans l'annuaire PPF",
"ppfErrorCode": "501",
"lastStatusCheckTime": "2026-06-09T10:16:00"
}
Response Body — Report Status Fields
| Field | Type | Nullable | Description |
|---|---|---|---|
| reportId | UUID | No | Unique identifier of this report record in the Docnova system. Matches the reportId passed in the path. |
| status | FranceReportStatus | No | Current Docnova-side lifecycle status of the report. Derived from PPF acknowledgement — transitions to ACCEPTED when ppfAckStatus = Ok, and to REJECTED when ppfAckStatus = Error. |
| reportType | FranceReportType | Yes | Specific report type: B2C or B2B, transaction or payment declaration. |
| source | InvoiceSource | Yes | Origin channel of the underlying invoice document, for example PORTAL, ERP, or PPF. |
| category | FranceCategory | Yes | Business nature of the reported transaction: SERVICE, GOODS, MIXED, or NON_TAXABLE. |
| senderSiren | string | Yes | 9-digit SIREN of the invoice sender, also known as the declarant company. |
| ppfFlowId | string | Yes | The PPF-assigned flow identifier returned when the report was submitted, for example FRR-10.3-.... null before submission. Used internally by the background scheduler to poll PPF status. |
| trackingId | string | Yes | Internal Docnova tracking reference for this submission attempt. |
| invoiceId | UUID | Yes | Docnova UUID of the underlying invoice document this report is based on. |
| invoiceNumber | string | Yes | Human-readable invoice reference number. |
| itemCount | integer | Yes | Number of line items included in this report. |
| totalAmount | BigDecimal | Yes | Total monetary amount reported, in the currency of the underlying invoice. |
| submittedTime | LocalDateTime | Yes | Timestamp when the report was successfully dispatched to the PPF. null if not yet submitted. |
| createdTime | LocalDateTime | No | Timestamp when the report record was created in the Docnova system. |
| submissionDeadline | LocalDateTime | Yes | The PPF-mandated deadline by which this report must be submitted. Calculated from the company's vatRegime and the reporting period. null if not yet calculated. |
| ppfAckStatus | string | Yes | Raw acknowledgement status string returned by the PPF. Possible values: Ok, Error, Pending, Processing. null if no PPF response received yet. |
| ppfErrorMessage | string | Yes | Human-readable rejection reason from the PPF acknowledgement detail. Populated only when ppfAckStatus = Error. Contains the PPF's reasonMessage from the first detail entry. |
| ppfErrorCode | string | Yes | Machine-readable error code from the PPF. Populated when ppfAckStatus = Error. Contains the reasonCode from the PPF detail, or defaults to 501 (IRRECEVABLE) if no detail was returned. |
| lastStatusCheckTime | LocalDateTime | Yes | Timestamp of the most recent background PPF status polling attempt for this report. Used to assess staleness of the ppfAckStatus value. |
PPF Acknowledgement Status Values
The ppfAckStatus field reflects the raw value returned by the PPF acknowledgement.status field. The background scheduler maps these values to the Docnova status field.
| PPF Ack Status | Meaning | Docnova Status Mapping |
|---|---|---|
| Ok | The PPF has fully accepted and processed the report. No errors found. | ACCEPTED |
| Error | The PPF rejected the report. ppfErrorCode and ppfErrorMessage contain the rejection details from PPF acknowledgement detail entries. | REJECTED |
| Pending | The PPF has received the report but has not yet started processing it. Status will be polled again by the background scheduler. | No Docnova status change |
| Processing | The PPF is currently validating the report. Status will be polled again by the background scheduler. | No Docnova status change |
⚠️ PPF error codes: When
ppfAckStatus = Error, theppfErrorCodefield contains a Chorus Pro / PPF status code. The most common values are500(RECEVABLE— accepted) and501(IRRECEVABLE— rejected). If the PPF returns an error without detail entries, the code defaults to501.
Enum Values
FranceReportStatus — Report Lifecycle Status
| Value | Description |
|---|---|
| DRAFT | Report created but not yet sent for validation. Initial state. |
| VALIDATING | Report is undergoing format and business rule validation before submission. |
| SUBMITTED | Report dispatched to the PPF; awaiting acknowledgement (ppfAckStatus is Pending or Processing). |
| ACCEPTED | PPF returned ppfAckStatus = Ok. Report successfully processed. |
| REJECTED | PPF returned ppfAckStatus = Error. See ppfErrorCode and ppfErrorMessage for details. |
| ERROR | A Docnova system-level failure prevented submission. Not a PPF rejection. |
| REPORTED | Report acknowledged and included in a PPF period summary. |
| MERGED | Report was merged with another period report. |
FranceReportType — Specific Report Type
| Value | Group | Flow Prefix | Description |
|---|---|---|---|
| TRANSACTION_B2C | E_REPORTING | FRR-10.3 | B2C transaction e-report, domestic sales to non-business customers. |
| TRANSACTION_B2B | E_REPORTING | FRR-10.1 | B2B international transaction e-report. |
| PAYMENT_B2B | PAYMENT | FRR-10.2 | B2B payment declaration report. |
| PAYMENT_B2C | PAYMENT | FRR-10.4 | B2C payment declaration report. |
FranceCategory — Transaction Business Category
| Value | Description |
|---|---|
| SERVICE | Service-based items only. |
| GOODS | Physical goods only. |
| MIXED | Both goods and services. |
| NON_TAXABLE | Outside the scope of French TVA. |
All error responses share the following structure:
{
"errorMessage": "<human-readable message>",
"errorType": "<error type key>",
"errorTitle": "<HTTP status name>",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/status/0034cdf6-3032-4fe1-b276-21a83191aeee"
}
400 - Bad Request
Returned when no report record exists in the Docnova database for the given reportId UUID.
{
"errorMessage": "Report not found",
"errorType": "BAD_REQUEST",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/status/0034cdf6-3032-4fe1-b276-21a83191aeee"
}
Condition: No report record exists in the Docnova database for the given reportId UUID. The ID may be incorrect, belong to a different company, or have been deleted.
Server behavior: reportRepository.findById() returns empty → service throws IllegalArgumentException("Report not found") → RestExceptionHandler maps to 400.
400 - Bad Request: Invalid UUID Format
Returned when the reportId path variable is not a valid UUID string.
{
"errorMessage": "Invalid request parameters",
"errorType": "VALIDATION_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/status/invalid-id"
}
Condition: The reportId path variable is not a valid UUID string, for example missing hyphens, wrong length, or non-hex characters.
Server behavior: Spring's path variable type conversion to UUID fails → BindException is thrown and caught by RestExceptionHandler.
401 - Unauthorized
Returned when the R-Auth header is missing, malformed, or the JWT token is expired.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/status/0034cdf6-3032-4fe1-b276-21a83191aeee"
}
Condition: The R-Auth header is missing, malformed, or the JWT exp claim has passed.
Server behavior: Spring Security filter chain rejects the request before it reaches the controller.
500 - Internal Server Error
Returned when an unexpected runtime exception occurs while processing the request.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-06-20T17:26:56.155059",
"path": "/reporting/FR/status/0034cdf6-3032-4fe1-b276-21a83191aeee"
}
Condition: Unexpected runtime exception, such as database connectivity failure, JPA query error, or entity-to-DTO mapping failure.
Server behavior: RuntimeException or Exception handler fires; error is logged server-side with stack trace.
24. Reporting Search Reports GET
Purpose of Use: This endpoint lists e-reporting and payment notification records created under France's mandatory tax reporting system in a paginated and filterable format. Under French tax law, businesses are required to submit two types of mandatory reports to the PPF (Plateforme Publique de Facturation):
- E-Reporting: Periodic submission of tax data for B2C and international B2B transactions
- Payment Reporting: Reporting of invoice payments from prior periods to the PPF
This endpoint allows querying both report groups through a single list interface. Rich filter options allow narrowing results by company, SIREN number, date range, report type, status, source channel, or PPF acknowledgement status. Results follow the standard Spring Data Page structure, making it possible to control page size and sorting for large datasets.
Typical use cases:
- Listing all French tax reports for a specific company on a dashboard
- Identifying failed or rejected reports using
status=REJECTEDorstatus=ERROR - Tracking
PAYMENT_B2Ctype reports submitted within a specific date range - Monitoring pending reports by filtering on
ppfAckStatus - Isolating reports for transactions from a specific sales channel using
source=EBAY
Endpoint Information
| Property | Value |
|---|---|
| URL | /reporting/FR/list |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/reporting/FR/list?companyId={companyId}&pageNumber=0&pageSize=20&dateFrom=2026-06-09&dateTo=2026-06-17&reportGroup=E_REPORTING' \
--header 'accept: */*' \
--header 'accept-language: en-US,en;q=0.9,tr;q=0.8,tk;q=0.7' \
--header 'content-type: application/json' \
--header 'origin: https://app-fr-stage.docnova.ai' \
--header 'priority: u=1, i' \
--header 'r-auth: '<JWT_TOKEN>' \
--header 'referer: https://app-fr-stage.docnova.ai/invoice-reporting' \
--header 'sec-ch-ua: "Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "Windows"' \
--header 'sec-fetch-dest: empty' \
--header 'sec-fetch-mode: cors' \
--header 'sec-fetch-site: same-site' \
--header 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36'
Request Parameters
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | string (UUID) | Yes | The unique identifier (UUID) of the company whose reports are being queried. |
| reportType | string (enum) | No | Report type filter. Narrows results to a specific transaction or payment type. |
| reportGroup | string (enum) | No | Report group filter. If reportType is not specified, returns all types within this group. |
| source | string (enum) | No | The source platform or channel through which the invoice/transaction was created. |
| status | string (enum) | No | Processing status filter for the report. |
| ppfAckStatus | string | No | The acknowledgement/notification status returned by PPF. Free-text, case-sensitive match. |
| category | string (enum) | No | Invoice/transaction category filter. |
| dateFrom | string (date) | No | Start date filter (inclusive). ISO 8601 format: YYYY-MM-DD. Matches from start of day. |
| dateTo | string (date) | No | End date filter (inclusive). ISO 8601 format: YYYY-MM-DD. Matches up to start of the following day. |
| siren | string | No | The 9-digit SIREN number of the sending company. Performs a LIKE search on both the senderSiren field and the raw request JSON. |
| pageNumber | integer | No | Page number to retrieve (0-based). Default: 0. |
| pageSize | integer | No | Number of records per page. Default: 20. |
| sort.sorted | boolean | No | Indicates whether sorting is applied. Managed via Spring Pageable. |
| sort.unsorted | boolean | No | Indicates no sorting is applied. |
| offset | integer | No | Pagination offset for the starting position. |
| paged | boolean | No | Whether a paged response is requested. Default: true. |
| unpaged | boolean | No | Whether all records should be returned without pagination. Default: false. |
Parameter Value Tables
reportType Possible Values
| Value | Group | PPF Flow Code | Description |
|---|---|---|---|
| TRANSACTION_B2C | E_REPORTING | FRR-10.3 | E-reporting of B2C individual customer transaction data. |
| TRANSACTION_B2B | E_REPORTING | FRR-10.1 | E-reporting of international B2B transaction data. |
| PAYMENT_B2B | PAYMENT | FRR-10.2 | Payment notification for B2B invoices. |
| PAYMENT_B2C | PAYMENT | FRR-10.4 | Payment notification for B2C invoices. |
reportGroup Possible Values
| Value | Description |
|---|---|
| PAYMENT | Payment notifications group. Includes PAYMENT_B2B and PAYMENT_B2C. |
| E_REPORTING | Electronic reporting group. Includes TRANSACTION_B2C and TRANSACTION_B2B. |
status Possible Values
| Value | Description |
|---|---|
| DRAFT | Draft. Not yet submitted and still editable. |
| VALIDATING | Validating. Being checked by the system before transmission to PPF. |
| SUBMITTED | Submitted. Transmitted to PPF and awaiting acknowledgement. |
| ACCEPTED | Accepted. Successfully processed by PPF. |
| REJECTED | Rejected. Refused by PPF and correction is required. |
| ERROR | Error. Transmission failed due to a technical error. |
| REPORTED | Reported. Processing completed. |
| MERGED | Merged. Combined into another report. |
category Possible Values
| Value | Description |
|---|---|
| SERVICE | Service invoice. |
| GOODS | Goods or product invoice. |
| MIXED | Mixed invoice containing both goods and services. |
| NON_TAXABLE | Transaction not subject to VAT. |
source Selected Values
| Value | Description |
|---|---|
| PORTAL | Created via web portal. |
| ERP | ERP system integration. |
| PEPPOL | Received via the PEPPOL network. |
| EBAY | eBay sales channel. |
| SHOPIFY | Shopify e-commerce platform. |
| AMAZON_SP | Amazon Seller Platform. |
| SFTP | SFTP file transfer. |
| PPF | Directly from the PPF platform. |
| Received via email. | |
| MOBILE | Mobile application. |
| STRIPE | Stripe payment system. |
| TEMU | Temu sales channel. |
For the full list, refer to the InvoiceSource enum. Other values include:
PORTAL_OCR, MOBILE_OCR, EMAIL_OCR, SERVICE, HARVEST, HUBSPOT, ANAF, LAZADA, KSEF, RS_API, ETA, ERACUN, KSEF_OFFLINE, LHDNM, NEMHANDEL.
Responses
200 - Successful Response
{
"content": [
{
"reportId": "3fa85f64-5717-4562-b3fc-...",
"status": "ACCEPTED",
"reportType": "PAYMENT_B2C",
"source": "EBAY",
"category": "NON_TAXABLE",
"senderSiren": "271688503",
"ppfFlowId": "FRR-10.4-20240101-001",
"trackingId": "TRK-2024-00123",
"invoiceId": "8a1e4c2d-1234-4abc-9def-...",
"invoiceNumber": "INV-2024-00456",
"itemCount": 12,
"totalAmount": 1540.50,
"submittedTime": "2024-06-01T10:30:00",
"createdTime": "2024-05-31T08:15:00",
"submissionDeadline": "2024-06-10T23:59:59",
"ppfAckStatus": "Ok",
"ppfErrorMessage": null,
"ppfErrorCode": null,
"lastStatusCheckTime": "2024-06-01T11:00:00"
}
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 20,
"paged": true,
"unpaged": false
},
"totalPages": 5,
"totalElements": 87,
"last": false,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"size": 20,
"number": 0,
"first": true,
"numberOfElements": 20,
"empty": false
}
content[] — Report Record Fields
| Field | Type | Description |
|---|---|---|
| reportId | string (UUID) | Unique identifier of the report. Used as a reference in subsequent report operations. |
| status | string (enum) | Current processing status of the report. Uses FranceReportStatus. |
| reportType | string (enum) | Report type. Uses FranceReportType. Indicates which PPF flow this report belongs to. |
| source | string (enum) | Source platform or channel through which the invoice/transaction was created. Uses InvoiceSource. |
| category | string (enum) | Invoice category. Uses FranceCategory. |
| senderSiren | string | 9-digit SIREN number of the sending company. |
| ppfFlowId | string | Flow identifier assigned by PPF. Used for tracking and debugging. |
| trackingId | string | Internal system tracking identifier. |
| invoiceId | string (UUID) | UUID of the invoice associated with this report. |
| invoiceNumber | string | Human-readable invoice number. |
| itemCount | integer | Number of transactions or line items covered by this report. |
| totalAmount | number (decimal) | Total monetary amount of the report. |
| submittedTime | string (datetime) | Date and time the report was transmitted to PPF. ISO 8601 format. |
| createdTime | string (datetime) | Date and time the report was created in the system. ISO 8601 format. |
| submissionDeadline | string (datetime) | Latest date and time by which the report must be submitted. ISO 8601 format. |
| ppfAckStatus | string | Acknowledgement status text returned by PPF, for example Ok, Error, or Pending. |
| ppfErrorMessage | string | null | Error message returned by PPF upon rejection. |
| ppfErrorCode | string | null | Error code returned by PPF. |
| lastStatusCheckTime | string (datetime) | Date and time of the most recent PPF status check. ISO 8601 format. |
400 - Bad Request
Returned when an invalid value is sent for an enum-type parameter, such as status, reportType, or category.
{
"error": "BAD_REQUEST",
"message": "Failed to convert value of type 'String' to required type 'FranceReportStatus'; nested exception is: No enum constant FranceReportStatus.INVALID_VALUE",
"code": "INVALID_PARAMETER"
}
Description: Sending a value outside the defined enum set, such as status=INVALID_VALUE or reportType=UNKNOWN, causes a Spring type conversion failure. Providing dateFrom or dateTo in a format other than YYYY-MM-DD also triggers this error.
400 - Bad Request: Missing Required companyId
Returned when the mandatory companyId query parameter is absent.
{
"error": "BAD_REQUEST",
"message": "Required request parameter 'companyId' for method parameter type UUID is not present",
"code": "MISSING_PARAMETER"
}
Description: companyId is the only mandatory parameter for this endpoint and must be in UUID format. A missing value or an improperly formatted UUID, such as companyId=abc123, triggers this error.
401 - Unauthorized
Returned when the JWT token in the R-Auth header cannot be verified.
{
"error": "UNAUTHORIZED",
"message": "Invalid or expired authentication token",
"code": "AUTH_TOKEN_INVALID"
}
Description: The token has expired, its signature is invalid, or the header is missing entirely. Token TTL is 50 minutes.
403 - Forbidden
Returned when the authenticated user does not have access rights to reports belonging to the specified companyId.
{
"error": "FORBIDDEN",
"message": "Access denied to company reports",
"code": "ACCESS_DENIED"
}
Description: The authorization layer rejects the request when a user attempts to query reports using a companyId that does not belong to them.
500 - Internal Server Error
Returned when an unexpected error occurs during the database query or data transformation.
{
"error": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred while processing your request",
"code": "GENERAL_ERROR"
}
Description: Thrown when an unexpected error occurs in the JPA specification filter or the toResponse() data conversion method.
25. CDV/CDAR Lifecycle Overview
Purpose of Use: Four read/write endpoints for tracking and driving a French invoice through its CDV (Compte-rendu de Dépôt Vérifié) status lifecycle once it has been submitted via send-document-async / send-document-async-json.
A French invoice does not have one status. It has a snapshot showing where things stand right now, and a history showing every CDAR status event recorded so far, inbound or outbound.
These two are separate tables in the backend and separate endpoints here:
| Endpoint | Returns |
|---|---|
GET /cdar/last-cdv/{companyId}/{invoiceId} | One object, current status |
GET /cdar/history/{invoiceId}?companyId= | Array, every status event, oldest first |
POST /cdar/submit?statusName= | Success or failure envelope |
GET /cdar/detail/{invoiceCdvHistoryId} | One object, full detail plus raw CDAR XML |
Path parameter to have on hand: invoiceId in all four endpoints is Docnova's internal InvoiceEntity UUID, not the business invoice number, e.g. <INVOICE_NUMBER>.
The buyer and seller each hold their own separate InvoiceEntity for the same business invoice, so this UUID is different on each side.
Resolve it via get-document-status-by-tracking after submission, or via /invoice/search-documents.
Which one do I need?
| Question you're answering | Call this | Where you'd use it |
|---|---|---|
| "What's this invoice's CDV status right now?" | last-cdv | Status badge in an invoice list, one lightweight call per invoice. |
| "How did it get there, what happened, and in what order?" | history | Timeline or audit trail on an invoice detail page. This returns every event, so reserve it for detail views. |
CDV/CDAR Status Code Reference
Full FranceProcessConditionCode enum as implemented. Includes statuses produced automatically by the platform, 200 to 203, alongside the manual ones from section 28, so both endpoints can be read against one table.
| Name | Code | Label | Category | Terminal | Produced via |
|---|---|---|---|---|---|
| DEPOSEE | 200 | Déposée | Mandatory | — | Automatic, invoice send |
| EMISE | 201 | Émise par la plateforme | Optional | — | Automatic, invoice send |
| RECUE | 202 | Reçue de la plateforme | Recommended | — | Automatic, inbound processing |
| MISE_A_DISPOSITION | 203 | Mise à disposition | Recommended | — | Automatic, inbound processing |
| REJETEE | 213 | Rejetée | Mandatory | Yes | Automatic, validation failure |
| PRISE_EN_CHARGE | 204 | Prise en charge | Recommended | — | /cdar/submit, recipient |
| APPROUVEE | 205 | Approuvée | Recommended | — | /cdar/submit, recipient |
| APPROUVEE_PARTIELLEMENT | 206 | Approuvée partiellement | Recommended | — | /cdar/submit, recipient |
| EN_LITIGE | 207 | En litige | Optional | — | /cdar/submit, recipient |
| SUSPENDUE | 208 | Suspendue | Optional | — | /cdar/submit, recipient |
| COMPLETEE | 209 | Complétée | Optional | — | /cdar/submit, sender |
| REFUSEE | 210 | Refusée | Mandatory | Yes | /cdar/submit, recipient |
| PAIEMENT_TRANSMIS | 211 | Paiement transmis | Recommended | — | /cdar/submit, recipient |
| ENCAISSEE | 212 | Encaissée | Mandatory | Yes | /cdar/submit, sender |
| VISEE | 214 | Visée | Optional | — | /cdar/submit, sender |
| ANNULEE | 220 | Annulée | Optional | Yes | Automatic, on confirmation of a corrective document |
Category (Mandatory / Recommended / Optional) is the StatusCategory value from the backend enum, not a restatement of the CDV specification text.
"Reaches PPF" in the tables below reflects the platform routing rule in code: only DEPOSEE, REJETEE, REFUSEE and ENCAISSEE are ever forwarded to PPF. Every other status is exchanged with the counterparty, PA, only.
Four terminal statuses. Once REFUSEE (210), ENCAISSEE (212), REJETEE (213) or ANNULEE (220) has been recorded, the lifecycle is closed and no further CDAR can be produced for that invoice.
ANNULEE is not submittable. It appears in this table because it can show up in last-cdv and history, but the platform produces it itself when a corrective document for the invoice is confirmed. POST /cdar/submit?statusName=ANNULEE returns CDAR_MANUEL_TRIGGER_FAILED.
24-hour PPF submission deadline: Per the specification, the four statuses that reach PPF — DEPOSEE (200), REFUSEE (210), ENCAISSEE (212) and REJETEE (213) — must reach the tax authority within 24 hours of being produced.
26. Get Current CDV Status GET
Purpose of Use: Returns the single current state snapshot for one invoice: latest CDV status, PPF transmission tracking, and lifecycle state. Use this for a status badge or summary view. Use history for the full timeline.
Rendering a status badge in an invoice list, one lightweight call per invoice, no need to fetch the full history.
For example, right after submitting invoice <INVOICE_NUMBER>, this endpoint returned currentCdvStatus: "EMISE", ppfAckStatus: "Pending". Enough on its own to show something like Delivered to platform, pending PPF acknowledgement in a list row, without touching history at all.
Endpoint Information
| Property | Value |
|---|---|
| URL | /cdar/last-cdv/{companyId}/{invoiceId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/cdar/last-cdv/{companyId}/{invoiceId}' \
--header 'R-Auth: <AUTH_TOKEN>'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Docnova company ID for the side viewing the invoice, buyer or seller. |
| invoiceId | UUID | Yes | Docnova InvoiceEntity ID, scoped to companyId. |
Responses
200 - Successful Response
{
"id": "<ID>",
"invoiceNumber": "<INVOICE_NUMBER>",
"invoiceTypeCode": "380",
"invoiceDate": "<INVOICE_DATE>",
"currentCdvStatus": "DEPOSEE",
"invoiceStatus": "FR_DEPOSITED",
"source": "PORTAL",
"platform": "PPF",
"direction": "OUTBOUND",
"lifecycleStatus": "SUBMITTED",
"ppfFlowId": "<PPF_FLOW_ID>",
"trackingId": "<TRACKING_ID>",
"senderSiren": "<SENDER_SIREN>",
"recipientSiren": "<RECIPIENT_SIREN>",
"ppfAckStatus": "Pending",
"ppfErrorMessage": null,
"createdTime": "<CREATED_TIME>",
"submittedTime": "<SUBMITTED_TIME>",
"lastCdvReceivedTime": "<LAST_CDV_RECEIVED_TIME>"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| id | UUID | ID of the CDV snapshot row itself. |
| invoiceNumber | string | Business invoice number. |
| invoiceTypeCode | string | UBL invoice type code, e.g. 380. Derived from the linked invoice; absent if not linked. |
| invoiceDate | datetime | Invoice issue date, from the linked invoice. |
| currentCdvStatus | enum | Current CDV status code name. See the status reference in section 25. |
| invoiceStatus | enum | Docnova's internal invoice lifecycle status, derived from currentCdvStatus for most statuses, e.g. DEPOSEE to FR_DEPOSITED. |
| source | enum | Channel the invoice originated from: PORTAL, ERP, SFTP, PEPPOL, etc. |
| platform | enum | PA or PPF, which platform the last recorded CDAR variant targeted. |
| direction | enum | OUTBOUND if this company produced it, or INBOUND if this company received it. |
| lifecycleStatus | enum | Transmission state of the CDAR itself: GENERATED, SUBMITTED, ERROR, etc. |
ppfFlowId/trackingId | string | Identifiers from the PPF SFTP transmission, when applicable. |
senderSiren/recipientSiren | string | SIREN of invoice supplier / customer. |
| ppfAckStatus | string | Free-text PPF acknowledgement state, e.g. Pending, Error. |
| ppfErrorMessage | string | Populated only when the PPF transmission failed. |
createdTime/submittedTime/lastCdvReceivedTime | datetime | Snapshot bookkeeping timestamps. |
Field behavior
| Field | Possible Values | What Determines It |
|---|---|---|
| currentCdvStatus | DEPOSEE, EMISE, RECUE, MISE_A_DISPOSITION, PRISE_EN_CHARGE, APPROUVEE, APPROUVEE_PARTIELLEMENT, EN_LITIGE, SUSPENDUE, COMPLETEE, REFUSEE, PAIEMENT_TRANSMIS, ENCAISSEE, REJETEE, VISEE, ANNULEE | The status of the most recent CDAR event recorded for this invoice, whichever side produced it. See the status reference in section 25 for what each code means. |
| invoiceStatus | FR_DEPOSITED, FR_PLATFORM_ISSUED, FR_RECEIVED, FR_AVAILABLE, FR_PROCESSING, FR_APPROVED, FR_PARTIALLY_APPROVED, FR_DISPUTED, FR_SUSPENDED, FR_REFUSED, FR_PAYMENT_SENT, FR_COLLECTED, FR_REJECTED, FR_CANCELLED | Mirrors currentCdvStatus for every status except COMPLETEE and VISEE, which have no mapped value. Reaching either of those leaves invoiceStatus unchanged from whatever it was before. |
| source | PORTAL, ERP, SFTP, PEPPOL | Starts out as the channel the invoice itself came in through. Portal UI becomes PORTAL, send-document-async-json becomes ERP. Switches to PEPPOL or SFTP the first time a status is actually delivered to the counterparty over one of those channels. |
| platform | PA, PPF | Which side received the most recent status. When a status is sent to both the counterparty and the tax authority, this always shows PPF. Read it as "did the tax authority see this", not "who received it". |
| direction | OUTBOUND, INBOUND | Whether the most recent event was one you produced, OUTBOUND, or one you received from the counterparty, INBOUND. Reflects only the latest event, so it can flip back and forth over the invoice's life. |
| lifecycleStatus | GENERATED, SUBMITTED, ERROR, REJECTED_BY_601, LOT_RECEIVED, LOT_REJECTED | Tracks whether this company's own CDAR has been delivered to the counterparty, not tied to whichever status currentCdvStatus currently shows. |
| ppfFlowId | free-form ID string | Tracking identifier for the file delivered to the tax authority. Use it to reference which specific submission a status came from. This reflects this company's own last delivery to the tax authority. |
| ppfAckStatus | Pending, Ok, Error, Failed, unknown | Tracks whether the tax authority has confirmed the DEPOSEE submission specifically. Pending means sent, no confirmation yet. Ok means confirmed accepted. Error means confirmed rejected. Failed means the delivery itself broke. unknown means no record found to check against yet. |
| ppfErrorMessage | free text or empty | Populated only when a tax-authority submission failed. |
| createdTime | datetime | When this invoice's CDV record was first opened. Set once, never changes again. |
| submittedTime | datetime or empty | When this company's own CDAR was successfully delivered to the counterparty. Stays empty for statuses that only ever go to the tax authority, e.g. DEPOSEE, EMISE. |
| lastCdvReceivedTime | datetime or empty | The last time a status arrived from the counterparty. Updates every time one arrives, not a one-time timestamp. |
currentCdvStatus → invoiceStatus mapping
| When this CDV status fires | invoiceStatus becomes | When it happens |
|---|---|---|
DEPOSEE (200) | FR_DEPOSITED | Peppol AP delivery succeeds, automatic. |
EMISE (201) | FR_PLATFORM_ISSUED | Immediately after 200, automatic. |
RECUE (202) | FR_RECEIVED | The counterparty's platform receives the invoice, automatic. |
MISE_A_DISPOSITION (203) | FR_AVAILABLE | Made available to the buyer, automatic. |
PRISE_EN_CHARGE (204) | FR_PROCESSING | Buyer calls /cdar/submit to say "I'm reviewing this". |
APPROUVEE (205) | FR_APPROVED | Buyer approves the invoice. |
APPROUVEE_PARTIELLEMENT (206) | FR_PARTIALLY_APPROVED | Buyer approves part of the invoice. |
EN_LITIGE (207) | FR_DISPUTED | Buyer disputes the invoice. |
SUSPENDUE (208) | FR_SUSPENDED | Buyer suspends processing, e.g. pending more documents. |
REFUSEE (210) | FR_REFUSED | Buyer fully refuses the invoice. Terminal. |
PAIEMENT_TRANSMIS (211) | FR_PAYMENT_SENT | Buyer reports that payment has been sent. |
ENCAISSEE (212) | FR_COLLECTED | Seller reports that payment has been collected. Terminal. |
REJETEE (213) | FR_REJECTED | Technical or business-rule rejection. Terminal. |
ANNULEE (220) | FR_CANCELLED | The platform cancels the invoice when a corrective document is confirmed. Terminal. |
COMPLETEE and VISEE are not in this list. They have no mapped invoiceStatus, so firing either one leaves the field unchanged.
Error Responses
| Status | errorType | Condition |
|---|---|---|
| 403 | AUTHORIZATION_FAILED | The R-Auth user has no role on companyId. |
| 404 | FR_INVOICE_CDV_NOT_FOUND | No CDV snapshot exists for this companyId + invoiceId pair. |
27. Get CDV Status History GET
Purpose of Use: Returns every CDAR status event recorded for the invoice, oldest first, ordered by receivedAt. This is the audit trail behind the snapshot returned by last-cdv. It includes both statuses this company produced, OUTBOUND, and statuses it received from the counterparty, INBOUND.
Rendering a timeline / audit trail on an invoice detail page, e.g. for the same invoice <INVOICE_NUMBER>, this endpoint returns two ordered events: "<EVENT_TIME> Déposée: submitted to PPF", then "<EVENT_TIME> Émise: platform confirmed the deposit." This is a full array, heavier than last-cdv's single object, so reserve it for detail views rather than list screens.
Endpoint Information
| Property | Value |
|---|---|
| URL | /cdar/history/{invoiceId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/cdar/history/<INVOICE_ID>?companyId=<COMPANY_ID>' \
--header 'R-Auth: <AUTH_TOKEN>'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| invoiceId | UUID | Yes | Docnova InvoiceEntity ID. |
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Company viewing the history. Results are scoped to both this ID and invoiceId together. |
Responses
200 - Successful Response
Empty array if the invoice exists but has no recorded CDAR events yet. This endpoint does not 404.
Example, seller side, invoice <INVOICE_NUMBER>:
[
{
"id": "<ID>",
"cdarHistoryStatus": "SUBMITTED",
"source": "ERP",
"previousStatus": null,
"newStatus": "DEPOSEE",
"platform": "PPF",
"direction": "OUTBOUND",
"cdarDocumentId": "<CDAR_DOCUMENT_ID>",
"statusCode": "10",
"statusLabel": "Déposée",
"issuerRoleCode": "WK",
"issuerName": "<ISSUER_NAME>",
"reasonCode": null,
"reasonText": null,
"errorMessage": null,
"responseCode": null,
"sftpFileName": "<SFTP_FILE_NAME>",
"cdarIssuedAt": "<CDAR_ISSUED_AT>",
"statusDepositedAt": null,
"receivedAt": "<RECEIVED_AT>",
"sentAt": "<SENT_AT>",
"changedBy": "PA_SFTP_SYSTEM"
},
{
"id": "<ID>",
"cdarHistoryStatus": "GENERATED",
"source": "ERP",
"previousStatus": null,
"newStatus": "EMISE",
"platform": "PPF",
"direction": "OUTBOUND",
"cdarDocumentId": "<CDAR_DOCUMENT_ID>",
"statusCode": null,
"statusLabel": "Émise par la plateforme",
"issuerRoleCode": "WK",
"issuerName": "<ISSUER_NAME>",
"reasonCode": null,
"reasonText": null,
"errorMessage": null,
"responseCode": null,
"sftpFileName": null,
"cdarIssuedAt": "<CDAR_ISSUED_AT>",
"statusDepositedAt": null,
"receivedAt": "<RECEIVED_AT>",
"sentAt": null,
"changedBy": "PA_SFTP_SYSTEM"
}
]
Response Fields per array item
| Field | Possible Values | What it means |
|---|---|---|
| id | UUID | ID of this history row. Pass to /cdar/detail to fetch the raw CDAR XML. |
| cdarHistoryStatus | GENERATED, SUBMITTED, RECEIVED, ERROR, REJECTED_BY_601, LOT_RECEIVED, LOT_REJECTED | Whether this specific event was actually delivered anywhere. GENERATED means recorded, not sent yet or ever. SUBMITTED means delivery succeeded. ERROR means delivery was attempted and failed, see errorMessage. RECEIVED is defined for inbound events, but not currently produced by the rows observed. A row created from an inbound CDAR reception shows GENERATED instead. REJECTED_BY_601 means the tax authority later flagged this exact event as invalid. LOT_RECEIVED / LOT_REJECTED is the tax authority's batch-level acknowledgement for it. |
| source | PORTAL, ERP, SFTP, PEPPOL | A snapshot of the invoice's own source value at the moment this specific event was recorded. It is not the channel this specific CDAR was delivered over, and not necessarily the same across every row of the same invoice's history. Early rows typically show the channel the invoice itself came in through, e.g. ERP for send-document-async-json. But once an earlier event for the same invoice is actually delivered to the counterparty over Peppol or SFTP, later rows can inherit that channel instead. Two rows in the same invoice history can legitimately show different values here. |
| previousStatus | always null | Present in the response shape but not currently populated. Do not rely on it to reconstruct what status came before this one. Use array order, oldest first, instead. |
| newStatus | same status list as currentCdvStatus, see the status code reference in section 25 | The CDV status this event represents. |
| platform | PA, PPF | Which recipient this specific row's CDAR variant targeted. A single status can produce one row per platform, linked internally. For statuses that only ever target the tax authority, expect PPF here even before the row has actually been transmitted. |
| direction | OUTBOUND, INBOUND | OUTBOUND if this company produced the CDAR. INBOUND if it was received from the counterparty. |
| cdarDocumentId | string | Unique CDAR document identifier, MDT-4. Different for every event, including twin PA/PPF rows for the same status. |
| statusCode | string or null | The MDT-88 status code, when this status has one. Some statuses, e.g. EMISE, have no MDT-88 equivalent by design. null is not a data quality problem. On rows created from an inbound CDAR reception, this can instead carry the raw CDV status number, e.g. 202, rather than the MDT-88 code. Do not compare this value across rows for what looks like the same status. |
| statusLabel | French label, e.g. "Déposée" | Always populated, the French label for newStatus. |
| issuerRoleCode | WK, SE, BY | WK means the platform is issuing on the company's behalf. SE means seller. BY means buyer. Automatic statuses 200 to 203 always show WK, the platform acting generically. Manual statuses submitted via /cdar/submit show the actual calling party's role instead: BY for buyer-initiated statuses, SE for seller-initiated ones. |
| issuerName | string | Display name of the CDAR issuer. |
reasonCode/reasonText | string or null | Populated for the statuses that carry a reason: 206, 207, 208 and 210. Empty on every other status. reasonText echoes back the reason value sent on the request. |
| errorMessage | string or null | Populated only when cdarHistoryStatus = ERROR. |
| responseCode | integer or null | Only ever set for a CDAR delivered to the counterparty over Peppol. Deliveries to the tax authority, PPF, leave this null even when they succeed. Do not treat null here as a failure signal on a platform: PPF row. |
| sftpFileName | string or null | The flux file name, populated only once this specific row has actually been transmitted. Stays null for events that are recorded but never sent. |
| cdarIssuedAt | datetime | When this event was recorded. Never changes afterwards. |
| statusDepositedAt | datetime or null | The official deposit time as declared by the counterparty. Populated only on INBOUND rows. Always null on rows this company produced itself. |
| receivedAt | datetime | Despite the name, this is set at the same moment as cdarIssuedAt for outbound rows. It marks when the row was recorded, not a separate received event. This is also the field the array is ordered by. |
| sentAt | datetime or null | When this row's CDAR was actually transmitted. Stays null until and unless that happens. |
| changedBy | fixed value, e.g. PA_SFTP_SYSTEM | A fixed system label stamped on every outbound row. Not tied to the invoice's actual source and not a real user or system identity. |
Some events are recorded but never actually sent: Not every row in this array was transmitted anywhere. Some statuses are generated and logged purely for the record, with no delivery step at all.
EMISE (201) is a concrete example: on a normal invoice it always shows cdarHistoryStatus: GENERATED, sftpFileName: null and sentAt: null permanently. This does not mean delivery failed. It means this status is never actually submitted to either the counterparty or the tax authority.
Do not read a permanently GENERATED row as a stuck or broken delivery unless you have confirmed the status is expected to go anywhere in the first place.
Known gap: Rows created from an inbound CDAR reception, most commonly the counterparty's automatically-produced RECUE or MISE_A_DISPOSITION events arriving on your side, do not always populate direction or platform.
If you see a history entry with a status but no platform / direction, treat it as informational only, not as proof the counterparty received nothing. Cross-check against last-cdv's currentCdvStatus before assuming a gap in the timeline.
Error Responses
| Status | errorType | Condition |
|---|---|---|
| 403 | AUTHORIZATION_FAILED | The R-Auth user has no role on companyId. |
28. Submit Manual CDV Status POST
Purpose of Use: Produces one of the CDV processing/closing statuses on behalf of the caller's company, persists it, and forwards it to the counterparty and, for two specific statuses, to PPF.
This is what a buyer calls to take charge of, approve, dispute, suspend or refuse an invoice, and what a seller calls to supply documents, mark it collected, or mark it checked.
Endpoint Information
| Property | Value |
|---|---|
| URL | /cdar/submit?statusName={statusName} |
| Method | POST |
| Content-Type | application/json |
| Query Parameter | statusName required, one of the enum names in Allowed statusName values, e.g. EN_LITIGE. The enum name, not the numeric code — APPROUVEE, not 205. Case-sensitive. |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Requests
Buyer disputes an invoice, EN_LITIGE / 207:
curl --location --request POST 'https://api-fr-stage.docnova.ai/cdar/submit?statusName=EN_LITIGE' \
--header 'Content-Type: application/json' \
--header 'R-Auth: <AUTH_TOKEN>' \
--data '{
"invoiceId": "<INVOICE_ID>",
"companyId": "<COMPANY_ID>",
"reasonCode": "TX_TVA_ERR",
"reason": "Incorrect VAT rate applied on line 1",
"requestedActionCode": "NIN",
"requestedAction": "Please issue a corrective invoice"
}'
Buyer suspends an invoice, SUSPENDUE / 208. This is the only status that requires characteristics:
curl --location --request POST 'https://api-fr-stage.docnova.ai/cdar/submit?statusName=SUSPENDUE' \
--header 'Content-Type: application/json' \
--header 'R-Auth: <AUTH_TOKEN>' \
--data '{
"invoiceId": "<INVOICE_ID>",
"companyId": "<COMPANY_ID>",
"reasonCode": "JUSTIF_ABS",
"reason": "Delivery note missing — cannot process until supplied",
"characteristics": [
{ "currencyId": "EUR" }
]
}'
Buyer takes charge, PRISE_EN_CHARGE / 204. No status-specific fields:
curl --location --request POST 'https://api-fr-stage.docnova.ai/cdar/submit?statusName=PRISE_EN_CHARGE' \
--header 'Content-Type: application/json' \
--header 'R-Auth: <AUTH_TOKEN>' \
--data '{
"invoiceId": "<INVOICE_ID>",
"companyId": "<COMPANY_ID>"
}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| invoiceId | UUID | Yes | Docnova InvoiceEntity ID, scoped to companyId. |
| companyId | UUID | Yes | Company producing this status. |
| reasonCode | string | 206, 207, 208, 210 | Must be a value from that status's list. Validated — see Reason codes below. |
| reason | string | 208, 210 · optional for 206, 207 | Free-text comment. Mandatory for Suspendue and Refusée: a reason code on its own is rejected. |
| requestedActionCode | string | 207 only, optional | Closed list of seven values — see below. |
| requestedAction | string | 207 only, optional | Human-readable requested action. |
| characteristics | array | 208 · optional for 207, 211, 212 | For 208, at least one entry must carry a non-empty currencyId. See item shape below. |
There is no reasonText field on this endpoint. Free-text explanation belongs in reason. Fields sent for a status that does not use them are ignored.
characteristics[] item shape
| Field | Type | Description |
|---|---|---|
| id | string | Reference to which specific part of the original invoice this characteristic describes, e.g. a line, an amount, or a business term. Free text. |
| typeCode | string | A short code identifying what kind of characteristic this is. Observed values: MPA used with PAIEMENT_TRANSMIS, MEN used with ENCAISSEE, DIV / DVA used with EN_LITIGE. |
| valueChangedIndicator | boolean | Whether this value differs from what was on the original invoice. |
| name | string | A human-readable label for what this characteristic represents. |
| location | string | Where in the original invoice this applies, an XPath-style reference. |
| valueAmount | string | The amount this characteristic carries. Required for ENCAISSEE, the amount collected. |
| currencyId | string | The currency of valueAmount. Required for SUSPENDUE on at least one entry. |
| valueDateTime | string | A date/time this characteristic carries, when relevant. |
| valuePercent | string | A percentage this characteristic carries. Required for ENCAISSEE, the VAT rate. |
For 208 (Suspendue) no typeCode is required. The only mandatory field is currencyId, and a single { "currencyId": "EUR" } entry satisfies it.
Allowed statusName values
Which values are accepted depends on whether the caller's company is the recipient (buyer, invoice was received) or the sender (seller, invoice was issued) of this specific invoice. This is inferred server-side from the invoice's own document type, not from the request.
If the caller is the recipient, buyer:
| statusName | Code | Label | What it does | Once per invoice? | Reaches PPF? |
|---|---|---|---|---|---|
| PRISE_EN_CHARGE | 204 | Prise en charge | Buyer confirms receipt of the invoice and starts reviewing it. | No | No, PA only |
| APPROUVEE | 205 | Approuvée | Buyer approves the invoice in full. | Yes | No, PA only |
| APPROUVEE_PARTIELLEMENT | 206 | Approuvée partiellement | Buyer approves only part of the invoice. Which part is not carried in the CDAR itself. Resolve the details outside this API. | No | No, PA only |
| EN_LITIGE | 207 | En litige | Buyer disputes the invoice and requests a specific corrective action from the seller, e.g. a corrective invoice. | No | No, PA only |
| SUSPENDUE | 208 | Suspendue | Buyer puts the invoice on hold, pending additional documents or information from the seller. | No | No, PA only |
| REFUSEE | 210 | Refusée | Buyer rejects the invoice outright. | Yes, Terminal | Yes, PA + PPF |
| PAIEMENT_TRANSMIS | 211 | Paiement transmis | Buyer confirms payment has been sent. | No | No, PA only |
If the caller is the sender, seller:
| statusName | Code | Label | What it does | Once per invoice? | Reaches PPF? |
|---|---|---|---|---|---|
| COMPLETEE | 209 | Complétée | Seller supplies the documents or information the buyer requested via a prior SUSPENDUE. | No | No, PA only |
| ENCAISSEE | 212 | Encaissée | Seller confirms payment has been collected. | Yes, Terminal | Yes, PA + PPF |
| VISEE | 214 | Visée | Seller marks the invoice as checked or validated. | No | No, PA only |
ANNULEE (220) is not submittable through this endpoint. The platform produces it automatically when a corrective document for the invoice is confirmed. A request with statusName=ANNULEE returns CDAR_MANUEL_TRIGGER_FAILED.
Terminal statuses lock the invoice: once REFUSEE (210), ENCAISSEE (212), REJETEE (213) or ANNULEE (220) has been recorded for an invoice, every subsequent call to this endpoint for that invoice fails with CDAR_TERMINAL_STATUS, including statuses that would otherwise be valid for the caller's role.
Transition rules
Statuses are not independent. Submitting one that cannot follow the invoice's current status returns CDAR_INVALID_TRANSITION: the lifecycle does not advance and nothing is transmitted.
| To submit | Current status must be one of |
|---|---|
| 204 Prise en charge | 203 |
| 205 Approuvée | 203, 204, 207, 208 |
| 206 Approuvée partiellement | 203, 204, 207, 208 |
| 207 En litige | 203, 204, 208 |
| 208 Suspendue | 203, 204 |
| 209 Complétée | 203, 204, 205, 206, 207, 208, 211 |
| 210 Refusée | 202, 203, 204, 207, 208 |
| 211 Paiement transmis | 205, 206 |
| 212 Encaissée | 203, 204, 205, 206, 207, 208, 211 |
| 214 Visée | 203, 204, 205, 206, 207, 208, 211 |
The buyer decision group
205, 206, 207, 208 and 210 are alternative decisions on the same invoice. How they interact is the part most integrations get wrong:
| After | Still available |
|---|---|
| 207 En litige | 205, 206, 210 — not 208 |
| 208 Suspendue | 205, 206, 207, 210 — all of them |
| 205 Approuvée | none of the five; 211 remains |
| 206 Approuvée partiellement | none of the five; 211 remains |
| 210 Refusée | none — terminal |
207 and 208 are transitional. A disputed or suspended invoice is meant to be resolved afterwards by approving, partially approving, or refusing it. If your interface disables those options once a dispute is raised, the invoice can never be closed.
205 and 206 are final decisions: after either, the only remaining buyer action is 211.
Status-specific request fields
| statusName | Fields used from the request body |
|---|---|
| APPROUVEE_PARTIELLEMENT | reasonCode required · reason optional |
| EN_LITIGE | reasonCode required · reason, requestedActionCode, requestedAction, characteristics optional |
| SUSPENDUE | reasonCode and reason required · characteristics required, at least one entry with currencyId |
| REFUSEE | reasonCode and reason required |
| PAIEMENT_TRANSMIS | characteristics optional, omitted entirely from the CDAR if empty |
| ENCAISSEE | characteristics, used to carry collected amount / VAT rate. Every MEN entry needs both valueAmount and valuePercent |
| All others | None of the status-specific fields are used |
Reason codes
Reason codes are validated. Rule BR-FR-CDV-15/MDT-113 requires a code whenever the status is 206, 207, 208 or 210, and rule BR-FR-CDV-CL-09/MDT-113_<status> then restricts which codes are valid per status.
The lists differ. A code accepted for a dispute is often rejected for a refusal. An invalid value returns 400.
206 — Approuvée partiellement · 13 codes
| Code | Label (FR) | Meaning |
|---|---|---|
| AUTRE | Autre | Other |
| CMD_ERR | N° de commande/engagement incorrect ou manquant | Purchase order number wrong, missing, or already invoiced |
| SIRET_ERR | SIRET erroné ou absent | Recipient SIRET wrong or missing |
| CODE_ROUTAGE_ERR | Code routage absent ou erroné | Routing code missing or wrong |
| REF_CT_ABSENT | Référence contractuelle manquante | A contractually required reference is missing |
| REF_ERR | Référence incorrecte | A reference is incorrect |
| PU_ERR | Prix unitaires incorrects | Unit price is not the expected one |
| REM_ERR | Remise erronée | Discount missing or not as expected |
| QTE_ERR | Quantité facturée incorrecte | Invoiced quantity is not as expected |
| ART_ERR | Article facturé incorrect | Wrong item invoiced |
| MODPAI_ERR | Modalités de paiement incorrectes | Payment terms incorrect |
| QUALITE_ERR | Qualité d'article livré incorrecte | A delivered item is defective |
| LIVR_INCOMP | Livraison incomplète / non effectuée | Delivery incomplete or not made |
207 — En litige · 26 codes
The widest list. It contains every code valid for 210, plus thirteen more.
| Code | Label (FR) | Meaning |
|---|---|---|
| AUTRE | Autre | Other |
| TX_TVA_ERR | Taux de TVA erroné | VAT rate is wrong |
| MONTANTTOTAL_ERR | Montant total erroné | An invoice total is wrong |
| CALCUL_ERR | Erreur de calcul de la facture | Calculation error — line totals or rounding |
| NON_CONFORME | Mention légale manquante | A mandatory legal statement is missing |
| DOUBLON | Facture en doublon | Duplicate invoice |
| DOUBLE_FACT | Données réglementaires F1 en doublon | Duplicate regulatory data |
| DEST_INC | Destinataire inconnu | Recipient not found in the directory |
| DEST_ERR | Erreur de destinataire | Wrong recipient |
| EMMET_INC | Émetteur inconnu | Sender unknown to the recipient |
| TRANSAC_INC | Transaction inconnue | No matching delivery or service |
| CONTRAT_TERM | Contrat terminé | Contract has ended |
| COORD_BANC_ERR | Erreur de coordonnées bancaires | Bank details are wrong |
| ADR_ERR | Adresse de facturation électronique erronée | Electronic invoicing address wrong or missing |
| SIRET_ERR | SIRET erroné ou absent | Recipient SIRET wrong or missing |
| CODE_ROUTAGE_ERR | Code routage absent ou erroné | Routing code missing or wrong |
| CMD_ERR | N° de commande/engagement incorrect ou manquant | Purchase order number wrong or missing |
| REF_CT_ABSENT | Référence contractuelle manquante | A contractually required reference is missing |
| REF_ERR | Référence incorrecte | A reference is incorrect |
| PU_ERR | Prix unitaires incorrects | Unit price is not the expected one |
| REM_ERR | Remise erronée | Discount missing or not as expected |
| QTE_ERR | Quantité facturée incorrecte | Invoiced quantity is not as expected |
| ART_ERR | Article facturé incorrect | Wrong item invoiced |
| MODPAI_ERR | Modalités de paiement incorrectes | Payment terms incorrect |
| QUALITE_ERR | Qualité d'article livré incorrecte | A delivered item is defective |
| LIVR_INCOMP | Livraison incomplète / non effectuée | Delivery incomplete or not made |
208 — Suspendue · 7 codes
| Code | Label (FR) | Meaning |
|---|---|---|
| JUSTIF_ABS | Justificatif absent ou insuffisant | Supporting documents missing or insufficient |
| COORD_BANC_ERR | Erreur de coordonnées bancaires | Bank details are wrong |
| CMD_ERR | N° de commande/engagement incorrect ou manquant | Purchase order number wrong or missing |
| SIRET_ERR | SIRET erroné ou absent | Recipient SIRET wrong or missing |
| CODE_ROUTAGE_ERR | Code routage absent ou erroné | Routing code missing or wrong |
| REF_CT_ABSENT | Référence contractuelle manquante | A contractually required reference is missing |
| REF_ERR | Référence incorrecte | A reference is incorrect |
210 — Refusée · 13 codes
| Code | Label (FR) | Meaning |
|---|---|---|
| TX_TVA_ERR | Taux de TVA erroné | VAT rate is wrong |
| MONTANTTOTAL_ERR | Montant total erroné | An invoice total is wrong |
| CALCUL_ERR | Erreur de calcul de la facture | Calculation error — line totals or rounding |
| NON_CONFORME | Mention légale manquante | A mandatory legal statement is missing |
| DOUBLON | Facture en doublon | Duplicate invoice |
| DOUBLE_FACT | Données réglementaires F1 en doublon | Duplicate regulatory data |
| DEST_ERR | Erreur de destinataire | Wrong recipient |
| EMMET_INC | Émetteur inconnu | Sender unknown to the recipient |
| TRANSAC_INC | Transaction inconnue | No matching delivery or service |
| CONTRAT_TERM | Contrat terminé | Contract has ended |
| ADR_ERR | Adresse de facturation électronique erronée | Electronic invoicing address wrong or missing |
| CMD_ERR | N° de commande/engagement incorrect ou manquant | Purchase order number wrong or missing |
| REF_CT_ABSENT | Référence contractuelle manquante | A contractually required reference is missing |
AUTRE is not valid for a refusal. There is no generic "other" option on 210, unlike every other status above. Neither are SIRET_ERR, CODE_ROUTAGE_ERR, COORD_BANC_ERR, REF_ERR, PU_ERR, REM_ERR, QTE_ERR, ART_ERR, MODPAI_ERR, QUALITE_ERR, LIVR_INCOMP or DEST_INC — for a refusal use DEST_ERR.
Building one shared list
Every code valid for 210 is also valid for 207. If your interface offers a single reason list for both statuses, restrict it to the 13 codes of 210 — that set is safe for both. Separate lists are only needed if you want the thirteen extra codes 207 allows.
For a missing mandatory legal statement, use NON_CONFORME: its official label is literally Mention légale manquante, and it is valid for both 207 and 210.
requestedActionCode — 207 only
A closed list of seven values (BR-FR-CDV-CL-10/MDT-121). Any other value returns 400.
| Code | Meaning |
|---|---|
| NOA | No action required |
| NIN | New invoice required |
| CNF | Credit note required, full |
| PIN | Accepted value — no published label |
| CNP | Accepted value — no published label |
| CNA | Accepted value — no published label |
| OTH | Accepted value — no published label |
Responses
200 - Successful Response
The status was accepted, persisted, and delivered.
{
"success": true,
"errorType": null,
"errors": null,
"errorMessage": null
}
200 - Delivery failure
The status is valid and has been recorded, but transmission to the counterparty or PPF failed. The status stands; the delivery is retried. This is the only case where success: false appears.
{
"success": false,
"errorType": "CDAR_SEND_FAILED",
"errors": null,
"errorMessage": "…"
}
400 - Rejected
Everything else — unknown status, wrong role, invalid transition, terminal invoice, duplicate, missing reason, missing characteristic, schematron failure — returns HTTP 400 with a different envelope. There is no success field here, so do not key your error handling on it alone.
{
"errorMessage": "Validation failed!",
"errorType": "VALIDATION_FAILED",
"errorTitle": "BAD_REQUEST",
"errorId": "<ERROR_ID>",
"status": 400,
"validationErrors": [
{
"code": "BR-FR-CDV-CL-09_MDT-113_210",
"field": "…/ProcessConditionCode[1]",
"message": "Le code motif de statut (MDT-113) : \"SIRET_ERR\", n'est pas dans la liste des codes autorisés pour le statut REFUSÉE (210) : \"TX_TVA_ERR\", \"MONTANTTOTAL_ERR\", …"
}
]
}
Read validationErrors[]. It names the rule that failed and, for reason-code errors, lists the codes that would have been accepted. Logging only errorMessage leaves you with "Validation failed!", which tells you nothing.
A failed submission leaves the lifecycle untouched. The invoice keeps its previous status and nothing is transmitted, so you can correct the payload and retry.
Error Responses
| errorType | Trigger |
|---|---|
CDAR_UNKNOWN_STATUS | statusName is not a recognized status code name. |
CDAR_MANUEL_TRIGGER_FAILED | statusName is recognized but not allowed for this endpoint at all, e.g. ANNULEE, or not allowed for the caller's role, recipient vs sender, on this invoice. |
CDAR_INVALID_TRANSITION | The status cannot follow the invoice's current status. See Transition rules. |
CDAR_TERMINAL_STATUS | A terminal status already exists for this invoice. |
CDAR_DUPLICATE_STATUS | This status has already been produced for this invoice. Applies to APPROUVEE, REFUSEE and ENCAISSEE. |
CDAR_REASON_REQUIRED | reasonCode missing for 206, 207, 208 or 210; or reason missing for 208 or 210. |
CDAR_SUSPENDUE_CHARACTERISTIC_CURRENCY_REQUIRED | 208 submitted with no characteristics entry carrying a currencyId. |
CDAR_ENCAISSEE_CHARACTERISTIC_MISSING_AMOUNTS | A MEN characteristic on 212 is missing valueAmount or valuePercent. |
VALIDATION_FAILED | The XSD or the FNFE schematron rejected the generated document. See validationErrors[]. |
INVOICE_NOT_FOUND | No invoice matches invoiceId + companyId. |
29. Get CDAR Detail (Raw XML) GET
Purpose of Use: Drills into a single row returned by /cdar/history. It is the same event, but with the extra bookkeeping fields history omits and, when available, the original CDAR XML document that was generated or received for that event.
Use this when you need the actual document, e.g. for your own compliance archive, not just its parsed fields.
Endpoint Information
| Property | Value |
|---|---|
| URL | /cdar/detail/{invoiceCdvHistoryId} |
| Method | GET |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://api-fr-stage.docnova.ai/ Production Environment URLhttps://api-fr.docnova.ai/ |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-fr-stage.docnova.ai/cdar/detail/<CDV_HISTORY_ID>?companyId=<COMPANY_ID>' \
--header 'R-Auth: <AUTH_TOKEN>'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| invoiceCdvHistoryId | UUID | Yes | The id of one item from a /cdar/history response. |
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Must match the row's owning company. |
Responses
200 - Successful Response
{
"id": "<ID>",
"invoiceNumber": "<INVOICE_NUMBER>",
"invoiceIssueDate": "<INVOICE_ISSUE_DATE>",
"vendeurSiret": "<SUPPLIER_SIRET>",
"cdarId": "<CDAR_ID>",
"cdarDocumentId": "<CDAR_DOCUMENT_ID>",
"cdarDocumentName": null,
"cdarHistoryStatus": "SUBMITTED",
"processConditionCode": "DEPOSEE",
"processCondition": "Déposée",
"newStatus": "DEPOSEE",
"statusCode": "200",
"statusLabel": "Déposée",
"direction": "OUTBOUND",
"platform": "PPF",
"source": "PORTAL",
"issuerRoleCode": "WK",
"issuerGlobalId": "<ISSUER_GLOBAL_ID>",
"issuerName": "<ISSUER_NAME>",
"senderGlobalId": null,
"sftpFileName": null,
"reasonCode": null,
"reasonText": null,
"errorMessage": null,
"responseCode": 200,
"responseMessage": null,
"changedBy": "PA_SFTP_SYSTEM",
"cdarIssuedAt": "<CDAR_ISSUED_AT>",
"statusDepositedAt": "<STATUS_DEPOSITED_AT>",
"receivedAt": "<RECEIVED_AT>",
"sentAt": "<SENT_AT>",
"createdAt": "<CREATED_AT>",
"updatedAt": "<UPDATED_AT>",
"xmlBase64": "<BASE64_ENCODED_CDAR_XML>"
}
Response Fields
| Field | Type | Description |
|---|---|---|
| id | UUID | Same value as the id used to request this detail. |
| invoiceNumber | string | Business invoice number. |
| invoiceIssueDate | string | Invoice issue date as YYYYMMDD, a plain string, not a parsed date. |
| vendeurSiret | string | Supplier SIRET, read from the linked invoice. |
| cdarId | string | CDAR document unique ID, MDT-4. |
cdarDocumentId/cdarDocumentName | string | Document identifier and, for SFTP-delivered CDARs, its inner file name. |
| cdarHistoryStatus | enum | Transmission state of this CDAR: GENERATED, SUBMITTED, RECEIVED, ERROR, REJECTED_BY_601, LOT_RECEIVED, LOT_REJECTED. |
| processConditionCode | enum | Set when this row came from an outbound, this-company-produced CDAR. See the status reference in section 25. |
| processCondition | string | French label paired with processConditionCode. |
| newStatus | enum | Set on both outbound and inbound rows. The more reliable of the two status fields to key logic off of. |
statusCode/statusLabel | string | Raw status code and label as carried in the CDAR XML itself. |
| direction | enum | OUTBOUND or INBOUND. |
| platform | enum | PA or PPF, which recipient this row's variant targeted. |
| source | enum | Origin channel of the underlying invoice: PORTAL, ERP, SFTP, PEPPOL, etc. |
issuerRoleCode/issuerGlobalId/issuerName | string | Who issued this CDAR: role WK / SE / BY, SIREN or PA code, and display name. |
| senderGlobalId | string | Sending PA's global ID, populated on PPF-targeted variants. |
| sftpFileName | string | Flux file name, when sent over SFTP. |
reasonCode/reasonText | string | Populated for the statuses that carry a reason: 206, 207, 208 and 210. reasonText echoes back the reason value sent on the request. |
| errorMessage | string | Populated when cdarHistoryStatus = ERROR. |
responseCode/responseMessage | integer / string | Result of the transmission attempt. |
| changedBy | string | System actor that recorded the row. |
cdarIssuedAt/statusDepositedAt/receivedAt/sentAt/createdAt/updatedAt | datetime | Full timestamps set for this event. |
| xmlBase64 | string | Base64-encoded raw CDAR XML, fetched from S3. null if no XML has been stored for this row yet. |
Error Responses
| Status | errorType | Condition |
|---|---|---|
| 403 | AUTHORIZATION_FAILED | The R-Auth user has no role on companyId. |
| 404 | FR_CDAR_HISTORY_NOT_FOUND | No history row matches invoiceCdvHistoryId + companyId. |