Malaysia E-Invoice PINT MY - MyInvois
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://app-stage.docnova.ai/ Production Environment URLhttps://api.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. |
1. Introduction
InvoisPro is a cloud based e invoicing management portal developed by Melasoft, fully aligned with Malaysia’s e invoicing requirements and designed to support integration with the Inland Revenue Board of Malaysia (LHDN) framework.
This API documentation is intended to help your ERP systems integrate smoothly with Malaysia’s e invoicing process.
Our portal abstracts complex invoice data structures and transmission workflows, providing developers with an easy to use, secure, and scalable interface. By using the InvoisPro API, you can submit invoices asynchronously, track real time processing statuses, manage incoming invoices, and automatically process technical responses and validation results back into your ERP system.
Our compliance oriented architecture supports the legal validity of every document, ensures data integrity, and provides an end to end traceable audit trail.
InvoisPro also manages the submission of invoices to LHDNM as part of the compliance flow. After validation checks are completed, invoices are transmitted asynchronously to LHDNM and the acceptance or rejection result is returned with detailed status information for automatic processing in your ERP system.
2. Authentication POST
Purpose of Use: This endpoint allows users to authenticate without a password, using only an API key and email address combination. It is designed for system integrations, automation flows, and third-party service connections where password-based login is impractical or insecure.
On success, it returns a short-lived JWT (JSON Web Token) for use in subsequent API requests, authorization, and session management. When the token expires, it can be renewed via /auth/refresh.
Endpoint Information
| Property | Value |
|---|---|
| URL | /auth/login |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authorization | Not required (public endpoint) |
Example Request
curl --location 'https://api-stage.docnova.ai/auth/login' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: {{API_KEY}}' \
--data-raw '{
"apiKey": "{{API_KEY}}",
"email": "{{USER_EMAIL}}"
}'
Request Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| apiKey | string | Yes | 32-character API key registered in the system. Must be active, not deleted, and not expired |
| string | Optional | Registered email address of the user to be authenticated against the API key |
Parameter Value Reference
| Field Name | Accepted Format | Example |
|---|---|---|
| apiKey | 32-character, alphanumeric, case-sensitive | ZkPa6n3ia4RNGBVKBH6Jt0OECwFGfwDH |
| RFC 5321 compliant email address | user@example.com |
Responses
Response Fields
| Field Name | Type | Description |
|---|---|---|
| jwt | string | HS256-signed JWT access token. Use in subsequent requests as Authorization: Bearer {{jwt}} |
| expirationDate | datetime | Date and time the JWT becomes invalid (ISO 8601, UTC). Token must be refreshed or re-issued after this time |
200 - Login Succesful
Full Response (AccountInfo)
{
"id": "495ff784-7c46-43c2-9074-...",
"superAdmin": true,
"companies": [
{
"id": "2adc7f51-28e4-426a-aa44-...",
"name": "01malaysaia TEST",
"taxNumber": "C24212888020",
"website": null,
"address": "Musterstraße 12, 10115 MELAKA, MALAYSIA",
"city": "Kuala Lumpur",
"state": "03",
"country": "MY",
"portalType": "MY",
"postalCode": "34445",
"phoneNumber": "55544433",
"credit": 626,
"iconUrl": "test/2adc7f51-28e4-426a-aa44-3b8e00707865/COMPANY_LOGO/25a4aef907933a251d0d78b9f0373d6c2dbdf40985986795b7e66ba2542fa96c.jpg",
"email": "testdemo35@yopmail.com",
"userCount": 10,
"vatNumber": "201501035702",
"faxNumber": "",
"mailLanguage": "EN",
"subscriptionType": "BXVHINZ6X3A3ZLWGMB+XmItEayWCC5oMnbTYwiXa4Nc=",
"cif": null,
"sftp": false,
"isSubCompany": false,
"participants": [
{
"id": "a0bf2105-d9b7-4ab1-bb60-...",
"fullParticipantId": "iso6523-actorid-upis::0230:0230:07201501035702-t",
"scheme": "iso6523-actorid-upis::",
"icd": "0230",
"identifier": "07201501035702-t",
"existInOurService": true,
"status": "KYC_ERROR",
"deleteRequestExists": false
},
{
"id": "a2fb922e-7939-4d28-846f-...",
"fullParticipantId": "iso6523-actorid-upis::0230:05201501035702-t",
"scheme": "iso6523-actorid-upis::",
"icd": "0230",
"identifier": "05201501035702-t",
"existInOurService": true,
"status": "APPROVED",
"deleteRequestExists": false
}
],
"featureAllowed": false,
"subCompanies": [],
"stripeObj": {
"stripeCustomerId": "cus_TM3MpffQRQyzm3",
"type": "FREE",
"renewalDate": "2026-03-14T13:03:00.075001",
"melaAiTokenCount": 4,
"googleAiTokenCount": null,
"docnovaCount": 0,
"renewal": true
},
"authorities": "jiVqy+CQIN13g2t/9bTDzanfl3S8b7T0RlP3t7/BB00=",
"compAuthTypes": "7SiBjCYJO5nw49sVSadYarRSf85BBy0jmpTELIRidxY=",
"currencyCode": "MYR",
"remainingDocumentPercentage": 0.0,
"remainingPromotionDays": null,
"trialUsed": false,
"defaultParticipantId": {
"id": "a2fb922e-7939-4d28-846f-...",
"fullParticipantId": "iso6523-actorid-upis::0230:05201501035702-t",
"scheme": "iso6523-actorid-upis::",
"icd": "0230",
"identifier": "05201501035702-t",
"existInOurService": true,
"status": "APPROVED",
"deleteRequestExists": false
}
}
}
],
"stripeObj": {
"stripeCustomerId": "cus_Th0jcCZCA7BC5m",
"type": "PREMIUM",
"renewalDate": "2026-03-04T13:59:36.374",
"melaAiTokenCount": 0,
"googleAiTokenCount": null,
"docnovaCount": 19,
"renewal": false
},
"authorities": "kg0H4Mff10god2oNgVtpHCf03ubIuWXOrjMRtbgw+AI=",
"compAuthTypes": "xodJ2k+/KR1J3E8oAt4DbBXX7bFkENqgK20E88fk3LaT4EFCAsqwska/SH3OrwjbIKujTbPFeYwIVMvsJ7rlOzaTep2UyQNY1WULmfp7+jme5k0AdnCslHnIeYQtaYb9",
"currencyCode": "EUR",
"remainingDocumentPercentage": 2.25,
"remainingPromotionDays": null,
"trialUsed": true,
"defaultParticipantId": {
"id": "948cc10b-be87-49b8-ad29-...",
"fullParticipantId": "iso6523-actorid-upis::9930:de855454549-t",
"scheme": "iso6523-actorid-upis::",
"icd": "9930",
"identifier": "de855454549-t",
"existInOurService": true,
"status": "APPROVED",
"deleteRequestExists": false
}
Basic Response
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expirationDate": "2026-02-24T12:00:00.000+00:00"
}
Response Fields
Account Information Fields
| Field Name | Type | Description |
|---|---|---|
| id | string(UUID) | Unique identifier of the authenticated user |
| superAdmin | boolean | Whether the user has platform-wide super admin privileges |
| companies | array[Company] | List of all companies the user is authorized to access. See Company Object |
| jwt | string | JWT access token to be used in Authorization: Bearer {{jwt}} header for all subsequent API requests |
| expirationDate | string(ISO 8601) | Expiry date and time of the JWT access token |
| user | object(User) | Profile information of the authenticated user. See User Object |
| mfaEnabled | boolean | Whether Multi-Factor Authentication (MFA) is enabled for the user |
| secretImageUri | string | null | QR code URI during initial MFA setup. null if MFA is not active |
| lastCompanyId | string(UUID) | ID of the company the user was last active in |
| requiresRecaptchaV2 | boolean | null | Whether the user must pass reCAPTCHA v2 verification on next login |
| message | string | null | Optional server message. Returns null in standard flows |
| active | boolean | Whether the user account is in an active state |
| isAppLogin | boolean | Indicates whether the login was performed via a mobile application |
| mfaType | string | null | MFA method in use. Possible values: TOTP, SMS. Returns null if MFA is disabled |
| refreshToken | string | Long-lived token used to obtain a new JWT after expiry without re-authentication |
| refreshTokenExpiration | string(ISO 8601) | Expiry date and time of the refresh token |
Company Information Fields
| Field Name | Type | Description |
|---|---|---|
| id | string (UUID) | Unique identifier of the company |
| name | string | Registered name of the company on the platform |
| taxNumber | string | Company tax number |
| website | string | null | Company website URL |
| address | string | Registered street address of the company |
| city | string | City where the company is located |
| state | string | null | State or region code. May be null depending on country |
| country | string | Two-letter ISO 3166-1 alpha-2 country code (e.g. DE, BE, TR) |
| portalType | string (enum) | The invoice portal type associated with the company. See portalType Values |
| postalCode | string | Postal/ZIP code |
| phoneNumber | string | null | Phone number |
| credit | integer | Current credit balance assigned to the company |
| iconUrl | string | null | Relative storage path of the company logo. null if no logo has been uploaded |
| string | null | Contact email address of the company | |
| userCount | integer | Total number of users registered under the company |
| vatNumber | string | null | VAT number |
| faxNumber | string | null | Fax number |
| mailLanguage | string | Language code for outgoing email notifications (e.g. EN, TR, DE) |
| subscriptionType | string | Encrypted subscription type value. Do not use directly; refer to stripeObj.type instead |
| cif | string | null | Spanish company identifier (CIF). null for other countries |
| sftp | boolean | Whether SFTP integration is active for the company |
| isSubCompany | boolean | Whether this company is a sub-company under a parent company |
| participants | array[Participant] | Peppol participant IDs registered for the company. See Participant Object |
| featureAllowed | boolean | Whether custom additional features are enabled for the company |
| subCompanies | array[Company] | List of sub-companies linked to this company. Same structure as the parent |
| stripeObj | object (StripeObj) | Stripe subscription and billing information. See StripeObj Object |
| authorities | string | Encrypted company authority data. For internal use only |
| compAuthTypes | string | Encrypted company transaction types (INVOICE, ORDER, CATALOGUE, etc.). For internal use only |
| currencyCode | string | Default currency code for the company (ISO 4217, e.g. EUR, TRY, PLN, MYR) |
| remainingDocumentPercentage | number (double) | Percentage of remaining document quota in the subscription plan (0.0 - 100.0) |
| remainingPromotionDays | integer | null | Number of days remaining in a promotion period. null if no promotion is active |
| trialUsed | boolean | Whether the company has already used its free trial |
| defaultParticipantId | object (Participant) | null | The default Peppol participant ID object for the company. null if none registered |
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 |
| RECHNUNG | German e-invoicing portal (XRechnung) |
| BE | Belgian e-invoicing portal |
| PL | Polish e-invoicing portal (KSeF) |
| FR | French e-invoicing portal (Chorus Pro) |
| MY | Malaysian e-Invoicing portal (MyInvois) |
| PINT MY | Malaysian e-Invoicing portal (PINT MY) |
| DEFAULT | Standard / no country-specific portal assigned |
mailLanguage Values
| Value | Description |
|---|---|
| MS | Malay |
| DE | German |
| EN | English |
| TR | Turkish |
| RO | Romanian |
| PL | Polish |
| FR | French |
| IT | Italian |
| ES | Spanish |
| NL | Dutch |
StripeObj Object
| Field Name | Type | Description |
|---|---|---|
| stripeCustomerId | string | Customer record ID on the Stripe platform |
| type | string (enum) | Active subscription plan. See Subscription Types |
| renewalDate | string (ISO 8601) | Date when the current subscription period will renew or expire |
| melaAiTokenCount | integer | MelaAI OCR token balance assigned to the company |
| googleAiTokenCount | integer | null | Google Document AI token balance. null if not supported |
| docnovaCount | integer | DocNova AI OCR processing quota (page/document based) |
| renewal | boolean | Whether automatic renewal is enabled for the subscription at the end of the period |
Participant Object
| Field Name | Type | Description |
|---|---|---|
| id | string (UUID) | Unique identifier of the participant record |
| fullParticipantId | string | null | Full Peppol participant ID. Format: {scheme}::{icd}:{identifier} |
| scheme | string | Peppol identification scheme. Typically iso6523-actorid-upis:: |
| icd | string | null | International Code Designator. Varies by country (e.g. 9930 DE, 9925 BE, 0208 BE) |
| identifier | string | null | Unique identifier value assigned to the participant |
| existinOurService | boolean | Whether the participant ID is registered within the DocNova service |
| status | string (enum) | Current status of the participant registration. See Participant Status Values |
| deleteRequestExists | boolean | Whether a pending deletion request exists for this participant |
Participant Status Values
| Value | Description |
|---|---|
| APPROVED | Participant registration is approved and active |
| REJECTED | Participant registration has been rejected |
| KYC_PENDING | Identity verification (KYC) process is pending |
User Object
| Field Name | Type | Description |
|---|---|---|
| id | string (UUID) | null | User ID. May be null in some flows; use the root-level id field instead |
| string | Registered email address of the user | |
| firstName | string | User's first name |
| lastName | string | User's last name |
| phoneNumber | string | null | User's phone number |
| creationTime | string (ISO 8601) | null | Account creation timestamp |
| photoUrl | string | null | Relative storage path of the user's profile photo |
| mailLang | string | User's preferred language code for email communications |
| isSuperAdmin | boolean | null | Super admin flag. Use root-level superAdmin for reliability |
| lastLoginTime | string (ISO 8601) | null | Timestamp of the last successful login |
| authorities | string | null | User-level authority data. For internal use only |
| adminAuthorities | string | Encrypted admin authority information. For internal use only |
| featureAllowed | boolean | Whether custom additional features are enabled for the user |
400 - Bad Request
{
"errorMessage": "...",
"errorType": "...",
"status": 400,
"errorTitle": "BAD_REQUEST",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login",
"errorId": "correlation-uuid"
}
400 - Bad Request — API Key Not Found
Trigger: The provided apiKey value does not exist in the database.
{
"errorMessage": "API key not found!",
"errorType": "ILLEGAL_STATE",
"status": 400,
"errorTitle": "BAD_REQUEST",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
400 - Bad Request — API Key Inactive or Deleted
Trigger: The apiKey exists in the database but is marked as active = false or deleted = true.
{
"errorMessage": "Provided api key is out of use! Please login with your credentials and try again.",
"errorType": "ILLEGAL_STATE",
"status": 400,
"errorTitle": "BAD_REQUEST",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
400 - Bad Request — API Key Expired
Trigger: The API key's expireDate is earlier than the current date and time.
{
"errorMessage": "Provided api key has expired! Please login with your credentials and try again.",
"errorType": "ILLEGAL_STATE",
"status": 400,
"errorTitle": "BAD_REQUEST",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
401 - Unauthorized
Trigger: When the API key is USER type but its registered owner does not match the provided email; or the login service returns an unexpected null response.
{
"errorMessage": "Invalid login attempt!",
"errorType": "NOT_AUTHORITY",
"status": 401,
"errorTitle": "UNAUTHORIZED",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
401 - Unauthorized — Missing or Invalid R-Auth Header
Trigger: The R-Auth header is absent, empty, or contains an invalid value. This error is raised by the security filter before the request reaches the business layer.
{
"errorMessage": "Not authorized for this action",
"errorType": "NOT_AUTHORITY",
"status": 401,
"errorTitle": "UNAUTHORIZED",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
404 - Not Found
Trigger: The provided email address does not match any active registered user.
{
"errorMessage": "User not found!",
"errorType": "NOT_FOUND_USER",
"status": 404,
"errorTitle": "NOT_FOUND",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
500 - Internal Server Error
Trigger: Unforeseeable technical failures such as database connection errors or service layer crashes.
{
"errorMessage": "An unexpected error occurred",
"errorType": "SERVER_ERROR",
"status": 500,
"errorTitle": "INTERNAL_SERVER_ERROR",
"timestamp": "2026-02-24T10:00:00",
"path": "/auth/login"
}
3. Search Processing History POST
Purpose of Use: This endpoint is used to query document processing records belonging to a company with multi-criteria filters and paginated results. It provides access to the processing history of invoices and documents received or sent through various channels such as PEPPOL, ERP, portal, or email.
What does it do?
- Lists incoming/outgoing invoice processing records for a given company.
- Narrows results using filters such as date range, filename, source system, processing status, and direction.
- Supports batch processing monitoring and troubleshooting via status values like PENDING, PROCESSING, COMPLETED, and FAILED.
- Enables retrospective tracking of whether documents received via the PEPPOL network have been processed, completed, or encountered errors.
- Provides efficient access to large datasets through a paginated and sortable response structure.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/document-process/search |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.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 --request POST 'https://api-test.docnova.ai/invoice/document-process/search?pageNumber=0&pageSize=20&paged=true&sort.sorted=true&sort.unsorted=false' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'r-auth: <YOUR_JWT_TOKEN>' \
--data '{
"companyId": "<YOUR_COMPANY_ID>",
"createdAt": {
"from": "2025-01-01",
"to": "2025-12-31"
},
"direction": "INCOMING",
"source": "PEPPOL",
"status": "COMPLETED"
}'
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | uuid | Yes | Unique identifier (UUID v4) of the company to query. |
| direction | string | No | Document direction. Valid values: INCOMING, OUTGOING. |
| source | string | No | Source system from which the document originated. See valid values below. |
| filename | string | No | Filter by exact filename. Partial matching is not supported. |
| status | string | No | Document processing status. See valid values below. |
| createdAt | object | No | Creation date range. Contains from and to sub-fields. |
| createdAt.from | date | No | Range start date. Format: YYYY-MM-DD. Must be today or in the past. |
| createdAt.to | date | No | Range end date. Format: YYYY-MM-DD. Must be today or in the past. |
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 |
Field Values Reference
direction — Document Direction
| Value | Description |
|---|---|
| INCOMING | Incoming documents (received invoices) |
| OUTGOING | Outgoing documents (sent invoices) |
source — Source System
| Value | Description |
|---|---|
| PEPPOL | Documents received/sent via the PEPPOL network |
| ERP | Documents transmitted via ERP integration |
| PORTAL | Documents uploaded through the web portal |
| PORTAL_OCR | Documents processed via OCR on the portal |
| Documents received via email | |
| EMAIL_OCR | Documents processed via OCR from email attachments |
| SFTP | Documents transferred via SFTP server |
| KSEF | Poland KSeF system |
| ANAF | Romania ANAF e-Invoice system |
| RS_API | Serbia RS API integration |
| LHDNM | Malaysia LHDN MyInvois system |
| NEMHANDEL | Denmark NemHandel system |
| ETA | Egypt ETA e-Invoice system |
| ERACUN | Croatia eRačun system |
| SHOPIFY | Shopify integration |
| AMAZON_SP | Amazon Selling Partner API integration |
| EBAY | eBay integration |
| HUBSPOT | HubSpot CRM integration |
| LAZADA | Lazada marketplace integration |
| STRIPE | Stripe payment system integration |
| HARVEST | Harvest time/invoice management system |
| SERVICE | Internal service operations |
status — Processing Status
| 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) |
| PDF document |
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 |
| PENDING | Document is queued and waiting to be processed |
| PROCESSING | Document is currently being processed |
| COMPLETED | Document was successfully processed |
| FAILED | An error occurred during processing; retry may be attempted |
| SENDING_FAILED | Document was processed but delivery to the target system failed |
| PERMANENT_FAILED | Permanent failure; document was marked as failed without further retries |
Responses
200 - Successful Response
{
"content": [
{
"trackingId": "1c608e78-e4f4-4460-85ae-...",
"companyId": "b3c91ae5-1234-4f00-9abc-...",
"direction": "INCOMING",
"documentType": "INVOICE",
"waybillType": null,
"source": "PEPPOL",
"target": "LHDNM",
"status": "COMPLETED",
"filename": "invoice_2025_001.xml",
"invoiceNumber": "INV-2025-001",
"documentId": "a1b2c3d4-5678-90ab-cdef-...",
"sendingResult": "Accepted",
"errorType": null,
"errors": null,
"additionalData": null,
"createdAt": "2025-01-15T10:30:00",
"statusUpdatedAt": "2025-01-15T10:31:05",
"completedAt": "2025-01-15T10:31:05"
}
],
"totalElements": 1,
"totalPages": 1,
"size": 20,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false
},
"first": true,
"last": true,
"empty": false
}
Response Fields
Pagination Fields (Page)
| Field | Type | Description |
|---|---|---|
| content | array | List of matching document processing records |
| totalElements | integer | Total number of records matching the applied filters |
| totalPages | integer | Total number of pages |
| size | integer | Number of records on this page |
| number | integer | Current page number (zero-based) |
| first | boolean | Whether this is the first page |
| last | boolean | Whether this is the last page |
| empty | boolean | Whether the page contains no records |
| sort.sorted | boolean | Whether results are sorted |
| sort.unsorted | boolean | Whether results are unsorted |
Record Fields (content[])
| Field | Type | Description |
|---|---|---|
| trackingId | uuid | Unique tracking identifier for the document processing record |
| companyId | uuid | UUID of the company this record belongs to |
| direction | string | Document direction: INCOMING or OUTGOING |
| documentType | string | Document format (e.g., PEPPOL_BIS, KSEF, XRECHNUNG, MY_INVOIS, etc.) |
| waybillType | string | Waybill type, if applicable |
| source | string | Source system from which the document originated |
| target | string | Target system to which the document is sent |
| status | string | Current processing status |
| filename | string | Filename of the processed document |
| invoiceNumber | string | Invoice number |
| documentId | uuid | Reference UUID of the processed document |
| sendingResult | string | Sending result (SUCCESS on success, error description on failure) |
| errorType | string | Error type identifier (see error codes table). null if no error. |
| errors | object | Validation or processing error details. Format varies based on errorType. Can be an array of strings. |
| additionalData | object | Country-specific metadata (e.g., KSeF reference number, ANAF submission ID). Varies by country. |
| createdAt | datetime | Record creation timestamp (ISO 8601, UTC) |
| statusUpdatedAt | datetime | Last status update timestamp (ISO 8601, UTC) |
| completedAt | datetime | Processing completion timestamp (ISO 8601, UTC). null if not yet completed. |
400 - Bad Request
Occurs when the request body or query parameters contain invalid or missing values.
{
"timestamp": "2025-06-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "companyId must not be null",
"path": "/invoice/document-process/search"
}
Possible Scenarios:
| Scenario | Returned Message |
|---|---|
| companyId field is missing or null | companyId must not be null |
| createdAt from or to is a future date | must be a date in the past or in the present |
| Invalid direction value provided | No enum constant... DocumentProcessDirection.XXX |
| Invalid status value provided | No enum constant... DocumentProcessStatus.XXX |
| Invalid source value provided | No enum constant... InvoiceSource.XXX |
| companyId is not a valid UUID format | Invalid UUID string |
401 - Unauthorized
Occurs when the r-auth header is missing, the JWT has expired, or the signature is invalid.
{
"timestamp": "2025-06-15T10:30:00",
"status": 401,
"error": "Unauthorized",
"message": "JWT token is missing or invalid",
"path": "/invoice/document-process/search"
}
Possible Scenarios:
| Scenario | Description |
|---|---|
| r-auth header not sent | Token header was not included in the request |
| JWT has expired (exp claim in the past) | Token is no longer valid and must be refreshed |
| JWT signature is invalid or malformed | Token was tampered with or signed using the wrong secret |
403 - Forbidden
Occurs when the token is valid but the user does not have an authorized role for the given companyId.
{
"timestamp": "2025-06-15T10:30:00",
"status": 403,
"error": "Forbidden",
"message": "Access denied for company: 2adc7f51-28e4-426a-aa44-...",
"path": "/invoice/document-process/search"
}
Access to this endpoint requires at least one of the following roles:
| Required Role | Description |
|---|---|
| ADMIN | Full administrator access |
| INCOMING_INVOICE_DISPLAY | View incoming invoice records |
| OUTGOING_INVOICE_DISPLAY | View outgoing invoice records |
404 - Not Found
Returned when the company identified by the given companyId does not exist in the system.
{
"timestamp": "2025-06-15T10:30:00",
"status": 404,
"error": "Not Found",
"message": "Company not found: 2adc7f51-28e4-426a-aa44-...",
"path": "/invoice/document-process/search"
}
4. 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 |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-stage.docnova.ai/invoice/document-status/1c608e78-e4f4-4460-...' \
--header 'Accept: */*' \
--header 'r-auth: eyJhbGciOiJIUzUxMiJ9...'
Request Parameters
Path Parameter
| Field Name | Type | Required | Format | Description |
|---|---|---|---|---|
| trackingId | UUID | Yes | XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX | The tracking ID returned by the async document submission. Unique identifier for the document processing record |
Response Fields
| Field Name | Type | Nullable | Description |
|---|---|---|---|
| trackingId | UUID | No | Unique tracking identifier of the document process |
| companyId | UUID | No | Identifier of the company that initiated the process |
| direction | DocumentType (enum) | Yes | Document direction: incoming or outgoing |
| documentType | DataType (enum) | Yes | Document format / type (e.g. PEPPOL_BIS, XRECHNUNG) |
| waybillType | WaybillDataType (enum) | Yes | Waybill type; null when the document is an invoice |
| source | InvoiceSource (enum) | Yes | Origin of the document (e.g. ERP, PORTAL) |
| target | InvoiceSource (enum) | Yes | Target system of the document |
| status | DocumentProcessStatus (enum) | No | Current processing status |
| filename | String | Yes | Name of the uploaded file |
| invoiceNumber | String | Yes | Document / invoice number |
| documentId | UUID | Yes | Identifier of the document record created in the system |
| sendingResult | String | Yes | Raw result / API response from the sending operation |
| errorType | ErrorType (enum) | Yes | Categorical error code if an error occurred (e.g. INVOICE_PROCESS_NOT_FOUND) |
| errors | Object | Yes | Error details. List<ValidationError> for validation errors, List<String> or String otherwise |
| additionalData | Object | Yes | Country-specific additional metadata (structure varies by country and document type) |
| createdAt | LocalDateTime | No | Timestamp when the record was first created in the system (ISO 8601) |
| statusUpdatedAt | LocalDateTime | Yes | Timestamp of the most recent status update (ISO 8601) |
| completedAt | LocalDateTime | Yes | Timestamp when the process completed. Populated only when status is COMPLETED (ISO 8601) |
Responses
200 - Successful Response
{
"trackingId": "1c608e78-e4f4-4460-85ae-...",
"companyId": "b3c91ae5-1234-4f00-9abc-...",
"direction": "OUTGOING",
"documentType": "MY_PINT",
"waybillType": null,
"source": "ERP",
"target": null,
"status": "COMPLETED",
"filename": "invoice_2024_001.xml",
"invoiceNumber": "INV-2024-001",
"documentId": "a1b2c3d4-5678-90ab-cdef-...",
"sendingResult": "Accepted",
"errorType": null,
"errors": null,
"additionalData": null,
"createdAt": "2024-11-15T10:30:00",
"statusUpdatedAt": "2024-11-15T10:31:05",
"completedAt": "2024-11-15T10:31:05"
}
Enum Value Reference Tables
DocumentProcessStatus — Processing Status
| Value | Description |
|---|---|
| PENDING | Document queued; processing has not yet started |
| PROCESSING | Document is actively being processed |
| FAILED | Processing failed; may be retried |
| SENDING_FAILED | Submission to the target country system failed |
| PERMANENT_FAILED | Permanent failure; document will not be reprocessed |
| COMPLETED | Document successfully processed and delivered |
DocumentType — Document Direction
| Value | Description |
|---|---|
| INCOMING | Incoming document (received from counterparty) |
| OUTGOING | Outgoing document (sent from own system) |
DataType — Document Format
| Value | Description |
|---|---|
| PEPPOL_BIS | Peppol BIS 3.0 invoice standard |
| RO_EFACTURA | Romania e-Invoice format |
| XRECHNUNG | Germany XRechnung standard |
| MY_INVOIS | Malaysia MyInvois platform |
| MY_PINT | Malaysia PINT standard |
| DK_OIOUBL | Denmark OIOUBL format |
| EG_INVOICE | Egypt e-Invoice (ETA) format |
| HR_INVOICE | Croatia eRačun format |
| UAE_PINT | UAE PINT standard |
| ZUGFERD | ZUGFeRD hybrid invoice format |
| FACTUR_X | France Factur-X format |
| XRECHNUNG_CII | XRechnung CII profile |
| CII | UN/CEFACT CII format |
| CID | CID invoice format |
| Unstructured PDF (image/paper Invoice) | |
| KZ_ESF_V2 | Kazakhstan ESF v2 format |
| KSEF | Poland KSeF online mode |
| KSEF_OFFLINE | Poland KSeF offline mode |
InvoiceSource — Source / Target System
| Value | Description |
|---|---|
| PORTAL | Docnova web portal |
| PORTAL_OCR | Document received via portal OCR |
| ERP | ERP system integration (this endpoint) |
| Email integration | |
| EMAIL_OCR | Document processed via email OCR |
| PEPPOL | Peppol network |
| SFTP | SFTP file transfer |
| KSEF | Poland KSeF system |
| ANAF | Romania ANAF system |
| LHDNM | Malaysia LHDNM (MyInvois) system |
| NEMHANDEL | Denmark NemHandel system |
| ETA | Egypt ETA system |
| ERACUN | Croatia eRačun system |
| RS_API | Serbia SEF API system |
| HARVEST | Harvest integration |
| SHOPIFY | Shopify integration |
| AMAZON_SP | Amazon SP-API integration |
| EBAY | eBay integration |
| HUBSPOT | HubSpot integration |
| LAZADA | Lazada integration |
| SERVICE | Internal system service |
| STRIPE | Stripe payment integration |
WaybillDataType — Waybill Type
| Value | Description |
|---|---|
| RS_WAYBILL_DESPATCH | Serbia despatch advice |
| RS_WAYBILL_RECEIPT | Serbia receipt advice |
| RS_APPLICATION_RESPONSE | Serbia application response document |
| RO_ETRANSPORT | Romania e-Transport waybill |
400 - Bad Request
When returned: The trackingId path parameter does not conform to UUID format (Spring MVC conversion failure).
{
"errorMessage": "Failed to convert value of type 'String' to required type 'UUID'",
"errorType": "RUNTIME_ERROR",
"status": 400,
"timestamp": "2024-11-15T10:30:00",
"path": "/invoice/document-status/invalid-id"
}
Note: When UUID format is invalid, Spring MVC throws a RuntimeException which is caught by the global RestExceptionHandler and returned in ExceptionResponse format.
Possible causes:
- trackingId is not in UUID format (e.g. "abc123", "invalid-id")
- An empty string was passed as trackingId
401 - Unauthorized
When returned: The r-auth header is missing, invalid, or the token has expired.
{
"errorMessage": "Unauthorized",
"errorType": "UNAUTHORIZED",
"status": 401,
"timestamp": "2024-11-15T10:30:00",
"path": "/invoice/document-status/1c608e78-e4f4-4460-85ae-f5d5664f1f82"
}
Possible causes:
- The r-auth header was not included in the request
- The token has expired (exp claim is in the past)
- The token signature is invalid or has been tampered with
- The token format is malformed (JWT cannot be parsed)
404 - Not Found
When returned: No record matching the given trackingId exists in the database. Internal error code: INVOICE_PROCESS_NOT_FOUND.
Note: This endpoint returns an empty body with 404 for this error case. The exception is caught at the controller level and does not use the standard ExceptionResponse structure.
Possible causes:
- An incorrect or environment-mismatched trackingId was sent
- The processing record has not yet been created in the system (polling too quickly after submission)
- The trackingId belongs to a different company
500 - Internal Server Error
When returned: An unexpected server error, database connectivity issue, or unhandled exception occurs.
Note: This endpoint also returns an empty body with 500 for this error case (caught at the controller level).
Possible causes:
- Database access error
- Unexpected JPA/Hibernate-level exception
- Transient system failure
5. Generate Pdf POST
Purpose of Use: This endpoint accepts UBL (Universal Business Language) XML-based invoice data and produces a human-readable, visually formatted PDF invoice document. The client sends invoice data as a Base64-encoded XML string; the API parses this data, applies country-specific and invoice-type-specific template logic, and returns a binary PDF output.
The endpoint requires authentication; a valid JWT token must be provided in the R-Auth header.
Endpoint Information
| Property | Value |
|---|---|
| URL | https://api-stage.docnova.ai/invoice/generate/pdf |
| Method | POST |
Example Request
curl --location 'https://api-stage.docnova.ai/invoice/generate/pdf' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: <JWT_TOKEN>' \
--data '{
"base64XML": "<BASE64_ENCODED_UBL_XML>",
"country": "MY",
"type": "MY_PINT",
"vatNumber": "<SUPPLIER_VAT_NUMBER>"
}'
Headers Parameters
| Header Name | Type | Required | Description |
|---|---|---|---|
| Content-Type | string | Yes | Must be application/json |
| Accept | string | No | Accepted response format. / is recommended |
| R-Auth | string | Yes | Authentication token in JWT format. No Bearer prefix is used |
Request Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| base64XML | string | Yes | Base64-encoded UBL XML invoice content. The XML must conform to the standard specified by the type field |
| type | string (enum) | Yes | Type code specifying the invoice format. See the table below for supported values |
| country | string (enum) | No | ISO 3166-1 alpha-2 country code. Used for company matching in SAP-ERP integrations |
| vatNumber | string | No | Supplier company's tax/VAT number. Used for company matching in SAP-ERP integrations |
typeField — Supported Values
| Value | Format Group | Description |
|---|---|---|
| PEPPOL_BIS | UBL | Pan-European PEPPOL BIS 3 invoice standard |
| XRECHNUNG | UBL | Germany-specific XRechnung UBL format |
| MY_INVOIS | UBL | Malaysia MyInvois (LHDN) invoice standard |
| MY_PINT | UBL | Malaysia PINT invoice standard (PEPPOL-based) |
| DK_OIOUBL | UBL | Denmark OIOUBL invoice standard |
| EG_INVOICE | UBL | Egypt e-invoice standard |
| HR_INVOICE | UBL | Croatia eRačun invoice standard |
| UAE_PINT | UBL | United Arab Emirates PINT invoice standard |
| RO_EFACTURA | UBL | Romania eFACTURA invoice standard |
| ZUGFERD | ZUGFeRD | ZUGFeRD hybrid invoice format |
| FACTUR_X | ZUGFeRD | France Factur-X invoice format |
| XRECHNUNG_CII | ZUGFeRD | Germany XRechnung CII format |
| CII | ZUGFeRD | UN/CEFACT Cross Industry Invoice format |
| CID | ZUGFeRD | CID invoice format |
| ZUGFeRD | Unstructured invoice (paper/scan/image) | |
| KZ_ESF_V2 | KZ | Kazakhstan ESF v2 invoice standard |
| KSEF | KSeF | Poland KSeF e-invoice standard |
| KSEF_OFFLINE | KSeF | Poland KSeF offline invoice standard |
countryField — Example Values
| Value | Country |
|---|---|
| MY | Malaysia |
| DE | Germany |
| FR | France |
| BE | Belgium |
| AT | Austria |
| DK | Denmark |
| HR | Croatia |
| EG | Egypt |
| AE | United Arab Emirates |
| RO | Romania |
| PL | Poland |
| KZ | Kazakhstan |
For all valid country codes, refer to the ISO 3166-1 alpha-2 standard.
Responses
200 - Successful Response
HTTP Status: 200 OK
Content-Type: application/octet-stream
| Field | Type | Description |
|---|---|---|
| (response body) | binary (byte[]) | Binary content of the generated PDF file. Can be written directly to disk or encoded in Base64 |
The response body is not a JSON object — it consists of raw binary PDF data. The client should save this data as a file with a .pdf extension.
400 - Bad Request
Trigger: All error responses return the following JSON structure:
{
"errorMessage": "PDF convert error: Malformed XML at line 3",
"errorType": "PDF_CONVERT_ERROR",
"errorTitle": "BAD_REQUEST",
"errorId": "f3a2b1c0-9e8d-4f7a-b6c5-...",
"status": 400,
"timestamp": "2026-02-25T11:04:23.456",
"path": "/invoice/generate/pdf",
"details": null,
"validationErrors": null
}
400 - Bad Request — NULL_DATA_XML
Trigger: When the base64XML field is sent as null or empty.
{
"errorMessage": "Data XML cannot be NULL!",
"errorType": "NULL_DATA_XML",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Verify that the base64XML field contains a valid, non-empty Base64 string.
400 - Bad Request — INVOICE_NULL_DATA_TYPE
Trigger: When the type field is sent as null.
{
"errorMessage": "Invoice type cannot be null!",
"errorType": "INVOICE_NULL_DATA_TYPE",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Populate the type field with one of the supported values (e.g. MY_PINT, PEPPOL_BIS).
400 - Bad Request — INVALID_PDF_TYPE
Trigger: When an unsupported or invalid value is sent in the type field.
{
"errorMessage": "Invalid PDF type",
"errorType": "INVALID_PDF_TYPE",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Check that the type field is one of the valid values in the DataType enum list.
400 - Bad Request — PDF_CONVERT_ERROR
Trigger: When the XML content is valid but an error occurs during the PDF conversion process. The error message includes the underlying exception.
{
"errorMessage": "PDF convert error: Unexpected end of XML document",
"errorType": "PDF_CONVERT_ERROR",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Verify that the Base64 encoding is not corrupted and that the decoded XML is complete and conforms to the selected type standard.
400 - Bad Request — INVALID_ARGUMENT
Trigger: When one of the request parameters contains an invalid value. The error message includes the name of the relevant argument.
{
"errorMessage": "Invalid argument! Argument: country",
"errorType": "INVALID_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Verify that the specified field contains a valid value. For country, use an ISO 3166-1 alpha-2 code.
401 - Unauthorized
Trigger: 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",
"status": 401,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Refresh the R-Auth header with a valid, non-expired JWT token.
422 - Unprocessable Entity
Trigger: When the XML structure is technically valid and can be parsed, but the invoice data violates business rules and the PDF cannot be generated.
{
"errorMessage": "PDF convert error: Required invoice field 'AccountingSupplierParty' is missing",
"errorType": "PDF_CONVERT_ERROR",
"errorTitle": "UNPROCESSABLE_ENTITY",
"status": 422,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Verify that all required UBL fields in the XML content are fully populated.
500 - Internal Server Error
Trigger: When an unexpected error occurs at the file system or I/O layer while creating or reading the PDF file.
{
"errorMessage": "File operation failed",
"errorType": "IO_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: This may be a transient server issue. Share the errorId value with the support team to open a ticket.
500 - Internal Server Error
Trigger: When an unexpected runtime or system error occurs on the server side.
{
"errorMessage": "Internal server error",
"errorType": "SERVER_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Note the errorId value and forward it to the support team.
500 - Internal Server Error — RUNTIME_ERROR
Trigger: When an unforeseen runtime exception occurs.
{
"errorMessage": "An unexpected error occurred",
"errorType": "RUNTIME_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-02-25T11:04:23.000",
"path": "/invoice/generate/pdf"
}
Resolution: Review the request parameters; if the issue persists, contact the support team with the errorId.
6. Retrieve Doc by ID and Type GET
Purpose of Use: This endpoint retrieves a previously uploaded and processed invoice document by its unique document UUID and the desired output format.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/get-document/{documentId}/{documentTypes} |
| Method | GET |
| Authorization | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-stage.docnova.ai/invoice/get-document/{documentId}/XML' \
--header 'Accept: */*' \
--header 'r-auth: {jwt_token}'
Request Parameters
Request Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| documentId | UUID | Yes | System-assigned unique identifier of the document to retrieve |
| format | String (Enum) | Yes | Output format of the document. Multiple formats can be requested comma-separated (e.g., XML, PDF) |
format — Possible Values
| Value | Description |
|---|---|
| XML | PEPPOL invoice XML conforming to UBL 2.1 standard |
| Human-readable PDF document | |
| HTML | Browser-renderable HTML output |
| JSON | Structured JSON format (for API consumption) |
| SIGN | Digitally signed document output |
| GPDF | Signed/approved PDF document |
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
| Accept | string | No | Accepted response media type. Default: / |
| r-auth | string (JWT) | Yes | Authentication token signed with HS512 algorithm |
JWT Token Structure (r-auth)
| Claim | Type | Description |
|---|---|---|
| iss | string | Identifier of the service that issued the token |
| sub | string | Encrypted user identifier |
| claim | string | Encrypted authorization claims |
| userType | string (enum) | User type: CLIENT or ADMIN |
| exp | long (Unix) | Token expiration time (Unix timestamp) |
Responses
200 - Successful Response
{
"documents": [
{
"file_type": "XML",
"data": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"...>"
}
]
}
Response Fields
DocumentResponse
| Field | Type | Description |
|---|---|---|
| documents | Array<Document> | List of documents for each requested format |
Document
| Field | Type | Description |
|---|---|---|
| file_type | string [enum] | Document format: XML, PDF, HTML, JSON, SIGN, GPDF |
| data | string | Document content. Raw text for XML/HTML formats; Base64-encoded data for PDF/SIGN |
400 - Bad Request
Cause: documentId is not a valid UUID format, or format is an unsupported value.
{
"errorMessage": "Invalid document format type: 'DOCX'",
"errorType": "INVALID_FORMAT_TYPE",
"errorTitle": "BAD_REQUEST",
"errorId": "a1b2c3d4-e5f6-7890-abcd-...",
"status": 400,
"details": {
"providedFormat": "DOCX",
"supportedFormats": ["XML", "PDF", "HTML", "JSON", "SIGN", "GPDF"]
},
"validationErrors": [],
"timestamp": "2026-02-26T10:30:00",
"path": "/invoice/get-document/91e9b1d3-8f2c-4ee5-af43-.../DOCX"
}
Returned when an unsupported format value is provided, or when the documentId is not in valid UUID format (e.g., abc-123).
401 - Unauthorized
Cause: r-auth header is missing, token has expired, or signature is invalid.
{
"errorMessage": "JWT token is invalid or expired",
"errorType": "INVALID_TOKEN",
"errorTitle": "UNAUTHORIZED",
"errorId": "b2c3d4e5-f6a7-8901-bcde-...",
"status": 401,
"details": {
"reason": "Token has expired"
},
"validationErrors": [],
"timestamp": "2026-02-26T10:30:00",
"path": "/invoice/get-document/91e9b1d3-8f2c-4ee5-af43-.../XML"
}
Returned when the r-auth header is absent, when the exp claim is in the past, or when the signature cannot be verified.
404 - Not Found
Cause: No document with the specified UUID exists in the system.
{
"errorMessage": "Document not found: 91e9b1d3-8f2c-4ee5-af43-...",
"errorType": "DOCUMENT_NOT_FOUND",
"errorTitle": "NOT_FOUND",
"errorId": "c3d4e5f6-a7b8-9012-cdef-...",
"status": 404,
"details": {
"documentId": "91e9b1d3-8f2c-4ee5-af43-..."
},
"validationErrors": [],
"timestamp": "2026-02-26T10:30:00",
"path": "/invoice/get-document/91e9b1d3-8f2c-4ee5-af43-.../XML"
}
Returned when a valid UUID is provided but no record with that ID exists in the database.
422 - Unprocessable Entity
Cause: Document exists but cannot be converted to the requested format (e.g., OCR processing not yet complete).
{
"errorMessage": "Document not yet processed; XML format could not be generated",
"errorType": "DOCUMENT_NOT_READY",
"errorTitle": "UNPROCESSABLE_ENTITY",
"errorId": "d4e5f6a7-b8c9-0123-defa-...",
"status": 422,
"details": {
"documentId": "91e9b1d3-8f2c-4ee5-af43-...",
"currentStatus": "OCR_WAITING"
},
"validationErrors": [],
"timestamp": "2026-02-26T10:30:00",
"path": "/invoice/get-document/91e9b1d3-8f2c-4ee5-af43-.../XML"
}
Returned when the document is registered but its content cannot be produced because it is in a state such as OCR_WAITING or OCR_FAILED.
500 - Internal Server Error
Cause: Unexpected server-side error; XML compilation failure, file read error, or database access issue.
{
"errorMessage": "Unexpected error occurred while generating document",
"errorType": "INTERNAL_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"errorId": "e5f6a7b8-c9d0-1234-efab-...",
"status": 500,
"details": {},
"validationErrors": [],
"timestamp": "2026-02-26T10:30:00",
"path": "/invoice/get-document/91e9b1d3-8f2c-4ee5-af43-.../XML"
}
Returned when XML serialization fails, S3 file cannot be accessed, or an unexpected runtime exception occurs. The errorId can be used to trace the incident in server logs.
7. Search Document with filter POST
Purpose of Use: This endpoint enables paginated, filtered listing of a company's outgoing or incoming documents (invoices, etc.). It supports filtering by document direction (documentType), electronic format (type), processing state (status), and date range. The response includes the matching document list, the total record count across all pages, and the tax-exclusive / tax-inclusive aggregate totals for the filtered result set. It serves as the central query point for document management workflows, primarily used by ERP systems and portal integrations.
Endpoint Information
| Property | Value |
|---|---|
| HTTP Method | POST |
| URL | /invoice/search-documents |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authentication | JWT Token (R-Auth header) |
| Authorization | ADMIN, INCOMING_INVOICE_DISPLAY, or OUTGOING_INVOICE_DISPLAY |
Example Request
curl --location 'api-stage.docnova.ai/invoice/search-documents' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'R-Auth: eyJhbGciOiJIUzUxMiJ9...' \
--data '{
"companyId": "25dd887c-0906-46a3-b333-...",
"documentType": "OUTGOING",
"endDate": "2026-02-26",
"page": 1,
"status": "SAVED_AS_UBL",
"size": 20,
"startDate": "2026-01-25",
"type": "MY_PINT"
}'
Request Body
{
"companyId": "25dd887c-0906-46a3-b333-99b59fa173cf",
"documentType": "OUTGOING",
"endDate": "2026-02-26",
"page": 1,
"status": "SAVED_AS_UBL",
"size": 20,
"startDate": "2026-01-25",
"type": "MY_PINT"
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Unique identifier of the company to search within |
| documentType | enum | No | Document direction: outgoing or incoming |
| status | enum | No | Current processing state of the document |
| type | enum | No | Electronic format type of the document |
| startDate | date | No | Search start date (YYYY-MM-DD) |
| endDate | date | No | Search end date (YYYY-MM-DD) |
| page | integer | No | Page number (starts at 1). Default: 1 |
| size | integer | No | Number of records per page. Default: 50 |
| tin | string | No | Supplier/customer tax identification number |
| uit | string | No | Unique invoice tracking identifier |
| referenceDocument | string | No | Full-text search across invoice number, supplier/customer name, or VAT number |
Parameter Value Reference Tables
documentType Values
| Value | Description |
|---|---|
| INCOMING | Incoming documents (received from a supplier) |
| OUTGOING | Outgoing documents (issued to a customer) |
type — Document Format Types
| Value | Description |
|---|---|
| PEPPOL_BIS | Peppol BIS UBL format |
| RO_EFACTURA | Romania e-Invoice format |
| XRECHNUNG | Germany XRechnung (UBL) |
| MY_INVOIS | Malaysia MyInvois format |
| MY_PINT | Malaysia PINT (Peppol network) format |
| DK_OIOUBL | Denmark OIO UBL format |
| EG_INVOICE | Egypt e-Invoice format |
| HR_INVOICE | Croatia eRačun format |
| UAE_PINT | UAE PINT format |
| ZUGFERD | Germany ZUGFeRD hybrid PDF+XML |
| FACTUR_X | France Factur-X format |
| XRECHNUNG_CII | XRechnung CII variant |
| CII | Cross-Industry Invoice (UN/CEFACT) |
| CID | Cross-Industry Document |
| Unstructured PDF / OCR document | |
| KZ_ESF_V2 | Kazakhstan ESF format |
| KSEF | Poland KSeF online format |
| KSEF_OFFLINE | Poland KSeF offline format |
status — Document Status Values
| Value | Description | Category |
|---|---|---|
| CREATED | Document has been created | General |
| SAVED_AS_UBL | Saved in UBL format | General |
| SAVED_AS_ZUGFERD | Saved in ZUGFeRD format | General |
| SAVED_AS_FACTUR_X | Saved in Factur-X format | General |
| SAVED_AS_CII | Saved in CII format | General |
| SAVED_AS_CID | Saved in CID format | General |
| SAVED_AS_KSEF | Saved in KSeF format | General |
| SAVED_AS_PDF | Saved as PDF | General |
| SENT_TO_ACCESS_POINT | Sent to access point | General |
| PENDING | Awaiting processing | General |
| CANCELED | Canceled | General |
| DELETED | Soft-deleted | General |
| SENT_VIA_EMAIL | Sent via email | General |
| COMPLETED_BY_MELA_AI | Completed by Mela AI | General |
| OCR_WAITING | Awaiting OCR processing | OCR |
| OCR_PARSED | OCR parsed successfully | OCR |
| OCR_FAILED | OCR processing failed | OCR |
| OCR_PARSED_PENDING_PAYMENT | OCR done, awaiting payment | OCR |
| OCR_WAITING_TOKEN | Awaiting OCR token | OCR |
| LHDNM_SUBMITTED | Submitted to Malaysia LHDNM | Malaysia |
| LHDNM_VALID | Validated by Malaysia LHDNM | Malaysia |
| LHDNM_INVALID | Rejected as invalid by LHDNM | Malaysia |
| LHDNM_CANCELLED | Cancelled in LHDNM | Malaysia |
| LHDNM_REJECTED | Rejected by LHDNM | Malaysia |
| LHDNM_ERROR | LHDNM processing error | Malaysia |
| ETA_SUBMITTED | Submitted to Egypt ETA | Egypt |
| KSEF_PENDING | Pending in Poland KSeF | Poland |
| KSEF_ACCEPTED | Accepted by Poland KSeF | Poland |
| KSEF_REJECTED | Rejected by Poland KSeF | Poland |
| ERACUN_SENT | Sent to Croatia eRačun | Croatia |
| ERACUN_APPROVED | Approved by Croatia eRačun | Croatia |
| ERACUN_REJECTED | Rejected by Croatia eRačun | Croatia |
| SENT_TO_ANAF | Sent to Romania ANAF | Romania |
| PORTAL_OKAY | Approved by portal | Romania |
| PORTAL_ERROR | Portal processing error | Romania |
| SENT_TO_NEMHANDEL | Sent to Denmark Nemhandel | Denmark |
| SENT_TO_PEPPOL | Sent to Peppol network | Peppol |
| SUCCESS | Successfully delivered | Peppol |
| TRANSPORT_ERROR | Peppol transport error | Peppol |
| INVALID_PARAMETERS | Invalid parameter error | Peppol |
| CREDIT_BLOCKED | Credit limit exceeded, document blocked | System |
Responses
200 - Successful Response
{
{
"totalCount": 42,
"netTotal": 850000.00,
"Total": 1003000.00,
"invoiceList": [
{
"id": "b3f1e2d4-...",
"companyId": "25dd887c-...",
"invoiceNumber": "INV-2026-001",
"documentType": "OUTGOING",
"type": "MY_PINT",
"status": "SAVED_AS_UBL",
"customerName": "ABC Sdn Bhd",
"supplierName": "XYZ Corp",
"taxExclusiveAmount": 20238.10,
"taxInclusiveAmount": 23874.00,
"payableAmount": 23874.00,
"currency": "MYR",
"issueDate": "2026-01-30",
"dueDate": "2026-02-28",
"createdTime": "2026-01-30T08:22:11",
"source": "ERP",
"paymentDetails": {
"paymentStatus": "SENT",
"paidAmount": 0.0,
"totalAmount": 23874.00,
"remainingAmount": 23874.00,
"paymentDate": null
}
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| id | string (UUID) | Unique system identifier of the document |
| companyId | string (UUID) | Identifier of the company the document belongs to |
| userId | string (UUID) | Identifier of the user who created the document |
| invoiceNumber | string | Document/invoice reference number |
| documentType | enum | Document direction: INCOMING / OUTGOING |
| type | enum | Document format (e.g. MY_PINT, ZUGFERD) |
| status | enum | Current processing status of the document |
| customerName | string | Customer name (populated for OUTGOING documents) |
| customerId | string | Customer system identifier |
| customerVat | string | Customer VAT number |
| customerEndpoint | string | Customer Peppol participant ID |
| customerCountryCode | string | Customer country code (ISO 3166-1) |
| supplierName | string | Supplier name (populated for INCOMING documents) |
| supplierId | string | Supplier system identifier |
| supplierVat | string | Supplier VAT number |
| supplierEndpoint | string | Supplier Peppol participant ID |
| supplierCountryCode | string | Supplier country code (ISO 3166-1) |
| taxExclusiveAmount | double | Net amount (excluding tax) |
| taxInclusiveAmount | double | Gross amount (including tax) |
| lineExtensionAmount | double | Line extension amount (before allowances) |
| allowanceTotalAmount | double | Total discount/allowance amount |
| payableAmount | double | Net amount payable |
| currency | string | Currency code (ISO 4217, e.g. MYR, EUR) |
| typeCode | string | Invoice type code (e.g. 380 = commercial invoice, 381 = credit note) |
| issueDate | date | Document issue date (YYYY-MM-DD) |
| dueDate | date | Payment due date (YYYY-MM-DD) |
| deliveryDate | date | Delivery date (YYYY-MM-DD) |
| createdTime | datetime | System creation timestamp (UTC) |
| localCreatedTime | datetime | Creation timestamp in the company's local time zone |
| lastUpdatedTime | datetime | Last update timestamp (UTC) |
| localLastUpdatedTime | datetime | Last update timestamp in local time |
| statusTime | datetime | Timestamp when the current status was set (UTC) |
| localStatusTime | datetime | Status transition timestamp in local time |
| source | enum | Channel through which the document entered the system |
| sendViaPeppol | boolean | Whether the document was delivered via the Peppol network |
| fileName | string | Original uploaded file name |
| errorMessage | string | Error description if processing failed |
| ocrParser | enum | OCR engine used: DOCNOVA_AI / GOOGLE_DOCUMENT_AI |
| profileType | enum | UBL profile type for ZUGFeRD/KSeF documents |
| isActive | boolean | Whether the document is in an active state |
| paymentDetails | object | Nested payment detail object |
| countrySpecificData | object | Country-specific supplementary data |
| idIncarcare | string | Romania ANAF upload identifier |
| idDescarcare | string | Romania ANAF download identifier |
paymentDetails Object
| Field | Type | Description |
|---|---|---|
| paymentStatus | enum | Payment state: SENT, PAID, PARTIAL_PAID, LATE |
| paidAmount | double | Amount already paid |
| totalAmount | double | Total payable amount |
| remainingAmount | double | Remaining unpaid amount |
| paymentDate | date | Date of payment (YYYY-MM-DD) |
400 - Bad Request
Cause: The companyId field was sent with a non-UUID value or left null.
{
"message": "Company ID cannot be NULL!",
"errorClientMessage": "COMPANY_ID_NULL"
}
400 - Bad Request — Invalid Enum Value (status, documentType, type)
Cause: A value outside the defined enum set was supplied for status, documentType, or type.
{
"message": "Invalid argument! Argument: INVALID_VALUE",
"errorClientMessage": "INVALID_ARGUMENT"
}
400 - Bad Request — Invalid Date Format
Cause: startDate or endDate was provided in a format other than YYYY-MM-DD.
{
"message": "Invalid date format: ",
"errorClientMessage": "INVALID_DATE_FORMAT"
}
400 - Bad Request — End Date Before Start Date
Cause: The endDate value is earlier than the startDate value.
{
"message": "End date cannot be before start date!",
"errorClientMessage": "END_DATE_BEFORE_START_DATE"
}
401 - Unauthorized
Cause: The R-Auth header is missing, the JWT token has expired, or the signature is invalid.
{
"message": "Authentication is required. Please complete the authentication process.",
"errorClientMessage": "AUTHENTICATION_REQUIRED"
}
403 - Forbidden
Cause: The user account does not hold the required display authority for the requested documentType (OUTGOING/INCOMING).
{
"message": "User is not authorized for this operation",
"errorClientMessage": "AUTHORIZATION_FAILED"
}
404 - Not Found
Cause: No company registered in the system matches the provided companyId.
{
"message": "Company not found!",
"errorClientMessage": "COMPANY_NOT_FOUND"
}
500 - Internal Server Error
Cause: An unexpected system-level error occurred (database connectivity, processing queue, etc.).
{
"message": "An internal error occurred",
"errorClientMessage": "INTERNAL_ERROR"
}
8. Send Document Async POST
Purpose of Use: This API endpoint is used to asynchronously transmit invoices originating from an ERP system or an external source to the recipient party over the Peppol network.
The client submits a Base64-encoded UBL XML invoice document (e.g., MY_PINT — Malaysia Peppol International) to this endpoint, causing the document to be queued for processing. Rather than processing the request immediately, the server enqueues it and returns a trackingId in the response, allowing the client to track the document's status via a dedicated status inquiry endpoint.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/send-document-async |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authorization | JWT Token (R-Auth header) or API Key |
Example Request
curl --location 'https://api-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_UBL_XML}",
"compId": "{COMPANY_UUID}",
"invoiceSource": "ERP",
"invoiceType": "MY_PINT",
"receiverEmails": [
"{RECEIVER_EMAIL}"
]
}'
Request Parameters
| Field Name | Type | Required | Description |
|---|---|---|---|
| apiKey | string | Yes | Company-specific API key used for authentication and authorization |
| base64Document | string | Yes | Base64-encoded content of the invoice document. Must be in UBL XML format. The applicable schema standard varies based on the invoiceType value |
| compId | string (UUID) | Yes | Unique identifier of the sending company. Must be in UUID v4 format |
| invoiceType | string (enum) | Yes | Specifies which standard the invoice document should be interpreted against. See the values table below |
| invoiceSource | string (enum) | Yes | Indicates the system or channel from which the invoice originates. See the values table below |
| receiverEmails | array<string> | No | Email addresses to receive a notification upon processing completion. Multiple addresses may be provided |
| base64Pdf | string | No | Base64-encoded content of the PDF version of the invoice. Can be sent as an optional attachment |
| mailTemplateId | string | No | Identifier of a custom email template to use for notification emails |
| businessType | string (enum) | No | Business model type. The system uses a default value when not specified |
invoiceType Possible Values
| Value | Country / Standard | Description |
|---|---|---|
| PEPPOL_BIS | Universal (Europe) | Standard Peppol BIS Billing 3.0 format |
| MY_PINT | Malaysia | Malaysia Peppol International (PINT) format |
| MY_INVOIS | Malaysia | Malaysia MyInvois (LHDNM) format |
| XRECHNUNG | Germany | German e-invoice standard (UBL-based) |
| XRECHNUNG_CII | Germany | German e-invoice standard (CII-based) |
| RO_EFACTURA | Romania | Romanian e-Factura format |
| DK_OIOUBL | Denmark | Danish OIOUBL format |
| EG_INVOICE | Egypt | Egyptian e-invoice format (ETA) |
| HR_INVOICE | Croatia | Croatian e-invoice format (ERAČUN) |
| UAE_PINT | UAE | UAE Peppol International format |
| ZUGFERD | Germany | ZUGFeRD hybrid PDF/XML format |
| FACTUR_X | France | Factur-X hybrid PDF/XML format |
| CII | Generic | UN/CEFACT CII XML format |
| CID | Generic | CID document format |
| Generic | PDF document format | |
| KZ_ESF_V2 | Kazakhstan | Kazakhstan ESF v2 format |
| KSEF | Poland | Polish KSeF e-invoice format (online) |
| KSEF_OFFLINE | Poland | Polish KSeF e-invoice format (offline) |
invoiceSource Possible Values
| Value | Description |
|---|---|
| ERP | Invoice originating from an ERP system integration |
| PORTAL | Manual upload via web portal |
| PORTAL_OCR | Document recognized via OCR through the portal |
| Invoice received via email | |
| EMAIL_OCR | Document recognized via OCR from an email attachment |
| PEPPOL | Document received from the Peppol network |
| LHDNM | Document received from the Malaysian LHDNM (MyInvois) platform |
| NEMHANDEL | Document received from the Danish NemHandel platform |
| SERVICE | API service integration |
| SFTP | Document transferred via SFTP |
| SHOPIFY | Shopify e-commerce integration |
| AMAZON_SP | Amazon Selling Partner API integration |
| EBAY | eBay integration |
| HUBSPOT | HubSpot CRM integration |
| LAZADA | Lazada e-commerce integration |
| STRIPE | Stripe payment platform integration |
| ANAF | Document received from the Romanian ANAF platform |
| KSEF | Document received from the Polish KSeF platform |
| RS_API | RS API integration |
| ETA | Document received from the Egyptian ETA platform |
| ERACUN | Document received from the Croatian ERAČUN platform |
| HARVEST | Harvest integration |
Responses
200 - Successful Response
{
"trackingId": "3fa85f64-5717-4562-b3fc-...",
"status": "PENDING",
"message": "Document queued successfully."
}
Response Fields
| Field Name | Type | Description |
|---|---|---|
| trackingId | string (UUID) | Unique tracking identifier generated for the queued document. Used for status queries |
| status | string (enum) | Current processing status of the document. See the values table below |
| message | string | Human-readable description of the processing outcome |
status Possible Values
| Value | Description |
|---|---|
| PENDING | Document has been queued; processing has not yet started |
| PROCESSING | Document is actively being processed |
| COMPLETED | Document has been successfully transmitted |
| FAILED | Processing failed; a retry may be scheduled |
| SENDING_FAILED | Transmission to the Peppol/LHDNM network failed |
| PERMANENT_FAILED | Permanent failure; no further retries will be attempted |
*The following error codes are specific to this endpoint. An example response and detailed description are provided for each.
400 - Bad Request
Triggers:
- Missing required fields (apiKey, base64Document, compId, invoiceType, invoiceSource)
- compId field not in UUID format
- base64Document content is not a valid Base64 string
- An address in the receiverEmails array does not conform to email format
{
"httpStatus": 400,
"message": "Validation failed for request body",
"errorClientMessage": "One or more required fields are missing or have invalid format.",
"validationErrors": [
{
"field": "compId",
"message": "must be a valid UUID"
},
{
"field": "base64Document",
"message": "must not be blank"
}
]
}
401 - Unauthorized
Triggers:
- r-auth header is missing
- JWT token has expired
- JWT token signature is invalid
- apiKey value does not belong to a registered company in the system
{
"httpStatus": 401,
"message": "Unauthorized",
"errorClientMessage": "Authentication failed. Please verify your token and API key."
}
404 - Not Found
Triggers:
- No company found in the system matching the provided compId
{
"httpStatus": 404,
"message": "Company not found",
"errorClientMessage": "No company found with the provided compId."
}
409 - Conflict
Triggers:
- The system detects a duplicate submission; the same document has been previously processed
- Invoice number or document ID collision
{
"httpStatus": 409,
"message": "Document already exists",
"errorClientMessage": "A document with the same identifier has already been submitted."
}
422 - Unprocessable Entity
Triggers:
- The XML generated from decoding the base64Document does not conform to the XSD schema of the specified invoiceType standard (e.g., urn:peppol:pint:billing-1@my-1 for MY_PINT)
- Mandatory fields within the UBL document (such as invoice number, date, party details, tax totals) are missing
- The invoiceType value does not match the CustomizationID element inside the document
- The provided invoiceType value is not covered under the license or subscription plan associated with the compId
{
"httpStatus": 422,
"message": "Document validation failed",
"errorClientMessage": "The submitted document does not comply with the MY_PINT schema.",
"details": "cbc:DueDate is required for invoice type MY_PINT. Validation error at line 42."
}
500 - Internal Server Error
Triggers:
- An unexpected server error while the document is being queued
- Failure in connecting to the message queue (e.g., Kafka or RabbitMQ)
- An internal service or database error
{
"httpStatus": 500,
"message": "An unexpected error occurred",
"errorClientMessage": "Internal server error. Please try again later or contact support."
}
9. Send To LHDNM POST
Purpose of Use: This endpoint is used to electronically submit Malaysian company invoices to LHDNM (Lembaga Hasil Dalam Negeri Malaysia — Inland Revenue Board of Malaysia). Under Malaysian tax legislation, businesses exceeding a certain revenue threshold are required to submit their invoices to LHDNM through the MyInvois system. Through this endpoint, invoices that have been previously uploaded to the system are prepared in XML format with a digital signature and submitted in batch to the LHDNM API. Invoice statuses are then updated based on the response received.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/MY/send-to-lhdnm/{companyId} |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authorization | JWT Token (R-Auth header) or API Key |
Example Request
curl --location 'https://api-stage.docnova.ai/invoice/MY/send-to-lhdnm/25dd887c-0906-46a3-b333-...' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'r-auth: {JWT_TOKEN}' \
--data '{
"invoiceIds": [
"2d5d9bba-1b2c-4211-8b6c-..."
]
}'
Authentication
| Header | Type | Required | Description |
|---|---|---|---|
| r-auth | string (JWT) | Yes | JWT token signed with HS512 algorithm. Contains userId, companyId, authorities, and correlationId. |
| Content-Type | string | Yes | Must always be application/json. |
Authority Requirements: The authorities field in the token must contain at least one of ADMIN or LHDNM_SUBMIT. Otherwise a 401 Unauthorized is returned.
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Unique identifier of the company for which invoices will be submitted to LHDNM. |
Request Fields
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
| invoiceIds | array<UUID> | Yes | Min: 1, Max: 100 | List of unique identifiers of invoices to be submitted to LHDNM. |
Responses
200 - Successful Response
{
"submissionUid": "SUB-001-2024",
"acceptedDocuments": [
{
"uuid": "LHDNM-UUID-001",
"invoiceCodeNumber": "INV-2024-001"
}
],
"rejectedDocuments": [
{
"invoiceCodeNumber": "INV-2024-002",
"error": {
"propertyName": "TotalTaxAmount",
"propertyPath": "Invoice/TaxTotal/TaxAmount",
"errorCode": "CF001",
"error": "Tax amount mismatch",
"errorMS": "Jumlah cukai tidak sepadan",
"target": "TaxTotal",
"innerError": []
}
}
]
}
Response Fields — SubmitResponse
| Field | Type | Description |
|---|---|---|
| submissionUid | string | Batch submission reference number assigned by LHDNM. |
| acceptedDocuments | array<AcceptedDocument> | List of invoices accepted by LHDNM. |
| rejectedDocuments | array<RejectedDocument> | List of invoices rejected by LHDNM. |
AcceptedDocument Fields
| Field | Type | Description |
|---|---|---|
| uuid | string | Unique identifier assigned by LHDNM to the accepted invoice. |
| invoiceCodeNumber | string | The invoice code/number of the accepted invoice in the system. |
RejectedDocument Fields
| Field | Type | Description |
|---|---|---|
| invoiceCodeNumber | string | The invoice code/number of the rejected invoice in the system. |
| error | Error | Error details returned from LHDNM. |
400 - Bad Request
{
"errorMessage": "Error message",
"errorType": "ERROR_TYPE",
"errorTitle": "BAD_REQUEST",
"errorId": "correlation-id-...",
"status": 400,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
400 - Bad Request
Scenario 1 — invoiceIds exceeds 100 items
{
"errorMessage": "The number of invoice IDs exceeds the maximum limit of 100. Please reduce the number of IDs and try again.",
"errorType": "ILLEGAL_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
A maximum of 100 invoice IDs can be sent per request. The request is rejected when this limit is exceeded.
Scenario 2 — Duplicate invoice numbers
{
"errorMessage": "Duplicate invoice number found: INV-2024-001",
"errorType": "ILLEGAL_ARGUMENT",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
When multiple invoice IDs sharing the same invoice number are submitted, an error is returned specifying the first duplicate number found.
Scenario 3 — Digital signing failed
{
"errorMessage": "Failed to sign the invoice: {invoiceId}",
"errorType": "ILLEGAL_STATE",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
An error occurred while signing the invoice's XML document with the company's digital certificate. Certificate validity and configuration should be verified.
Scenario 4 — LHDNM validation failure
{
"errorMessage": "Validation failed! [CF001] Tax amount mismatch",
"errorType": "VALIDATION_FAILED",
"errorTitle": "BAD_REQUEST",
"status": 400,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
LHDNM rejected all submitted invoices due to business rule violations. Detailed error information is included in the errorMessage field along with the LHDNM error code.
401 - Unauthorized
Cause: JWT token is missing, invalid, or does not contain required authorities.
{
"errorMessage": "Access denied. Required authority: ADMIN or LHDNM_SUBMIT",
"errorType": "UNAUTHORIZED",
"errorTitle": "UNAUTHORIZED",
"status": 401,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
A valid JWT token must be sent in the r-auth header, and this token must contain at least one of the ADMIN or LHDNM_SUBMIT authorities.
404 - Not Found
Scenario 1 — invoiceIds field empty or null
{
"errorMessage": "No invoice IDs provided in the request. Please check and try again.",
"errorType": "NOT_FOUND",
"errorTitle": "NOT_FOUND",
"status": 404,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
The invoiceIds field in the request body was either not sent at all or was sent as an empty list.
Scenario 2 — No invoice records found for submitted IDs
{
"errorMessage": "No invoices found for the provided IDs. Please check and try again.",
"errorType": "NOT_FOUND",
"errorTitle": "NOT_FOUND",
"status": 404,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
None of the IDs in the provided invoiceIds list were found in the invoice records belonging to the specified companyId.
Scenario 3 — XML data not found in storage
{
"errorMessage": "No XML data found for the provided invoice IDs. Please check and try again.",
"errorType": "NOT_FOUND",
"errorTitle": "NOT_FOUND",
"status": 404,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
While invoice records exist, the signed XML documents required for LHDNM submission could not be found in the storage system.
500 - Internal Server Error
Cause: XML parsing error or unexpected system failure.
{
"errorMessage": "Error parsing XML to invoice object: {details}",
"errorType": "INTERNAL_ERROR",
"errorTitle": "INTERNAL_SERVER_ERROR",
"status": 500,
"timestamp": "2026-02-26T10:00:00",
"path": "/invoice/MY/send-to-lhdnm/{companyId}"
}
Returned during XML conversion errors or other unexpected system failures. A retry is recommended; if the issue persists, contact the support team with the errorId correlation ID.
10. Cancel Invoice PUT
Purpose of Use: This endpoint is used to cancel or reject an e-invoice that has been submitted to the LHDNM (Lembaga Hasil Dalam Negeri Malaysia) system within the scope of the Malaysia (MY) e-Invoicing integration.
It serves two primary scenarios:
- Cancel: Cancels an outgoing invoice (sent by the company) by an authorized user.
- Reject: Rejects an incoming invoice (received by the company) by an authorized user.
The request passes through authority verification, invoice source control, current status validation, and invoice direction validation before being forwarded to the official LHDNM API. Upon success, the invoice status is updated to LHDNM_CANCELLED or LHDNM_REJECTED in the local database.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/{country}/status/update/{invoiceId} |
| Method | PUT |
Example Request
curl --location 'https://api-test.docnova.ai/invoice/MY/status/update/63a2e945-5b0c-4c05-9689-8686620216a4' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'r-auth: <JWT_TOKEN>' \
--data '{
"reason": "test",
"status": "rejected"
}'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| country | string | Yes | Country code. Fixed value for Malaysia: MY |
| invoiceId | UUID | Yes | Unique identifier of the invoice to be cancelled or rejected |
Header Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| r-auth | string (JWT) | Yes | Authentication token. Must be a JWT signed with the HS512 algorithm |
| Content-Type | string | Yes | Must be application/json |
| Accept | string | No | Acceptable response media type |
Request Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| status | string (enum) | Yes | Action to apply to the invoice. Valid values: cancelled, rejected |
| reason | string | Yes | Reason for the action. Values exceeding 300 characters are automatically truncated |
status — Valid Values
| Value | Description | Applicable Invoice Direction | Required Authority | Resulting Status |
|---|---|---|---|---|
| cancelled | Cancels the invoice | Outgoing invoices only | LHDNM_CANCEL | LHDNM_CANCELLED |
| rejected | Rejects the invoice | Incoming invoices only | LHDNM_REJECT | LHDNM_REJECTED |
Responses
200 - Successful Response
true
Response Fields
| Field | Type | Description |
|---|---|---|
| (body) | boolean | Returns true when the operation completes successfully |
400 - Bad Request
Scenario 1 — Invalid status value
{
"errorCode": "INVALID_REQUEST",
"message": "Invalid status value. Accepted values: 'cancelled', 'rejected'.",
"timestamp": "2026-02-27T10:15:30Z"
}
A value other than cancelled or rejected was submitted in the status field.
Scenario 2 — status field missing or null
{
"errorCode": "INVALID_REQUEST",
"message": "CancelRejectRequest and its status cannot be null.",
"timestamp": "2026-02-27T10:15:30Z"
}
Request body is empty or status field is not included.
Scenario 3 — Invoice not from LHDNM source
{
"errorCode": "INVALID_INVOICE_SOURCE",
"message": "Invoice ID: {invoiceId} is not from LHDNM source.",
"timestamp": "2026-02-27T10:15:30Z"
}
The invoice was created from a source other than LHDNM.
Scenario 4 — Invoice in non-modifiable status
{
"errorCode": "INVALID_STATUS_TRANSITION",
"message": "Cannot cancel or reject invoice ID: {invoiceId} with status LHDNM_VALID.",
"timestamp": "2026-02-27T10:15:30Z"
}
Action attempted on an invoice in LHDNM_VALID or LHDNM_SUBMITTED status.
Scenario 5 — Attempt to cancel incoming invoice
{
"errorCode": "INVALID_OPERATION",
"message": "Cannot cancel incoming invoice with ID: {invoiceId}.",
"timestamp": "2026-02-27T10:15:30Z"
}
cancelled status applied to an incoming invoice.
Scenario 6 — Attempt to reject outgoing invoice
{
"errorCode": "INVALID_OPERATION",
"message": "Cannot reject outgoing invoice with ID: {invoiceId}.",
"timestamp": "2026-02-27T10:15:30Z"
}
rejected status applied to an outgoing invoice.
401 - Unauthorized
Cause: r-auth header missing, malformed, or JWT expired.
{
"errorCode": "UNAUTHORIZED",
"message": "Authentication token is missing or invalid.",
"timestamp": "2026-02-27T10:15:30Z"
}
403 - Forbidden
Cause: User lacks LHDNM_CANCEL or LHDNM_REJECT authority.
{
"errorCode": "ACCESS_DENIED",
"message": "User does not have the required authority to perform this action.",
"timestamp": "2026-02-27T10:15:30Z"
}
404 - Not Found
Cause: No invoice matching the provided invoiceId exists in the system.
{
"errorCode": "INVOICE_NOT_FOUND",
"message": "Invoice not found with ID: {invoiceId}.",
"timestamp": "2026-02-27T10:15:30Z"
}
429 - Too Many Requests
Cause: LHDNM API rate limit exceeded.
{
"errorCode": "TOO_MANY_REQUESTS",
"message": "LHDNM API rate limit exceeded. Please retry after some time.",
"timestamp": "2026-02-27T10:15:30Z"
}
Too many requests in a short period; LHDNM API has throttled the connection.
500 - Internal Server Error
Cause: Unexpected error during LHDNM API communication or system internals.
{
"errorCode": "INTERNAL_SERVER_ERROR",
"message": "An unexpected error occurred. Please contact support.",
"timestamp": "2026-02-27T10:15:30Z"
}
11. Validate Taxpayer TIN POST
Purpose of Use: This endpoint validates a Taxpayer Identification Number (TIN) against the LHDNM (Lembaga Hasil Dalam Negeri Malaysia — Inland Revenue Board of Malaysia) system for Malaysian taxpayers. It checks whether a TIN — belonging to a company or an individual — is registered and valid in the LHDNM database by matching it against a specified identity document (BRN, NRIC, Passport, or Army ID).
Verifying the tax information of both the receiving and supplying parties is mandatory in e-Invoice (MyInvois) processes. The TIN's validity must be confirmed through this endpoint before an invoice can be created.
Endpoint Information
| Property | Value |
|---|---|
| URL | /invoice/MY/validate-taxpayer-tin/{companyId} |
| Method | POST |
| Content-Type | application/json |
| Base URL | Stage Environment URLhttps://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authorization | r-auth header (JWT token) |
Example Request
curl --location 'https://api-stage.docnova.ai/invoice/MY/validate-taxpayer-tin/{companyId}' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'r-auth: <JWT_TOKEN>' \
--data '{
"idType": "BRN",
"idValue": "<IDENTITY_NUMBER>",
"tin": "<TIN_NUMBER>"
}'
Request Parameters
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| companyId | UUID | Yes | Unique identifier of the company performing the operation (UUID format). Used to retrieve the company's LHDNM OAuth2 token. |
Request Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| tin | string | Yes | The Taxpayer Identification Number to be validated. An alphanumeric value assigned by LHDNM, formatted according to country standards. |
| idType | enum(string) | Yes | The type of identity document. Must be one of the valid values in the table below. |
| idValue | string | Yes | The number/value of the identity document specified by idType. |
idType — Valid Values
| Value | Full Name | Usage |
|---|---|---|
| BRN | Business Registration Number | Company registration number — used for legal entities |
| NRIC | National Registration Identity Card | National ID card number — for Malaysian citizen individuals |
| PASSPORT | Passport ID | Passport number — for foreign national individuals |
| ARMY | Army ID | Military ID number — for Malaysian Armed Forces personnel |
Responses
200 - Successful Response
true
Response Fields
| Field | Type | Description |
|---|---|---|
| (root) | boolean | true — TIN and identity information are valid and match in the LHDNM system. false — TIN is invalid, not found, or does not match the provided identity information. |
Note: An HTTP 200 response indicates the request was processed successfully, not that the TIN is valid. TIN validity is determined by the boolean value in the body.
400 - Bad Request
Cause: tin, idType, or idValue fields are missing or invalid. idType contains an unsupported value.
{
"status": "400",
"error": {
"errorCode": "BAD_REQUEST",
"error": "Validation failed",
"InnerError": [
{
"propertyName": "tin",
"error": "must not be blank"
},
{
"propertyName": "idType",
"error": "must not be null"
},
{
"propertyName": "idValue",
"error": "must not be blank"
}
]
}
}
Triggers: tin or idValue empty/null; idType null or invalid enum (e.g., DRIVER_LICENSE).
401 - Unauthorized
Cause: r-auth header missing, JWT invalid or expired.
{
"status": "401",
"error": {
"errorCode": "UNAUTHORIZED",
"error": "Invalid or expired authentication token"
}
}
Triggers: r-auth not sent; JWT expired (exp in past); JWT signature invalid.
403 - Forbidden
Cause: User lacks ADMIN or LHDNM_TAXPAYER_TIN_VALIDATE authority on the specified companyId.
{
"status": "403",
"error": {
"errorCode": "FORBIDDEN",
"error": "User does not have required authority for this company"
}
}
Triggers: User does not have required role on this company; user attempts to use another company's companyId without authority.
404 - Not Found
Cause: companyId not registered, or no valid LHDNM OAuth2 token for the company.
{
"status": "404",
"error": {
"errorCode": "NOT_FOUND",
"error": "Token not found for the specified company."
}
}
Triggers: companyId UUID not registered; LHDNM token not configured for company; token deleted or expired.
500 - Internal Server Error
Cause: LHDNM API unreachable or unexpected internal error.
{
"status": "500",
"error": {
"errorCode": "INTERNAL_SERVER_ERROR",
"error": "An unexpected error occurred while processing the request"
}
}
Triggers: LHDNM API timeout/connection error; unexpected LHDNM response format; internal service failure.
When the LHDNM validation API returns an error (e.g., TIN not found, no match), this is expressed as HTTP 200 with body false, not as an HTTP error. A false value may also indicate a temporary LHDNM system issue.
12. 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 |
| Authentication | R-Auth header (JWT token) |
Example Request
{
curl --location 'https://api-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.
13. 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://app-stage.docnova.ai/ Production Environment URLhttps://api.docnova.ai/ |
| Authentication | R-Auth header (JWT token) |
Example Request
curl --location 'https://api-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.