> For the complete documentation index, see [llms.txt](https://api.qvalia.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api.qvalia.io/api-documentation/apis/transaction-api.md).

# Transaction API

Qvalia Transaction API

> This is a condensed version of the Qvalia Developer Tools page, see the main page
>
> for more detailed information:

{% content-ref url="/pages/lZlrrZ0gu5MG85GDz5tL" %}
[API](/qvalia-developer-tools/api.md)
{% endcontent-ref %}

The Qvalia Transaction API has endpoints for all [Peppol messages](https://qvalia.com/help/what-are-the-message-types-in-peppol/).

{% hint style="success" %}
All transaction endpoints support both JSON and XML!
{% endhint %}

API specifications are available in OPenAPI format:

[Download OpenAPI definitions](https://openapi.gitbook.com/o/-McAY8WYeIvMOpDL_Y9w/spec/transaction-api.yaml)

### Authentication <a href="#authentication" id="authentication"></a>

We use API keys or JWT for the Authentication of requests. You can get your API key from our Support team and you’ll get a separate key and URL for Production and Test environments. All requests are using HTTPS with a minimum of TLS 1.2.

{% hint style="success" %} <mark style="color:$success;">See</mark> [Ways to authenticate](/api-documentation/apis/ways-to-authenticate.md)<mark style="color:$success;">for detailed information!</mark>
{% endhint %}

Each request made to the API will contain your `account registration number` which is your account identifier for your Qvalia account. Your account identifier will be provided to you from the Support team during the onboarding process.

Your requests must use the registration number as e.g. `POST /{account registration number}/invoices/outgoing`

### UBL JSON Representation standard <a href="#ubl-json-representation-standard" id="ubl-json-representation-standard"></a>

For the JSON representation of the format please refer to <http://docs.oasis-open.org/ubl/UBL-2.1-JSON/v2.0/UBL-2.1-JSON-v2.0.html>

UBL JSON samples and schemas can be found here: <http://docs.oasis-open.org/ubl/UBL-2.1-JSON/v2.0/cnd01/>

### UBL XML Representation standard <a href="#ubl-xml-representation-standard" id="ubl-xml-representation-standard"></a>

For the XML representation, <https://docs.oasis-open.org/ubl/UBL-2.1.html>

The UBL version 2.1 has been selected due to the many compliant standars with UBL 2.1, mainly the Peppol standard (peppol.eu).

XML samples and XML schemas can be found here: <http://docs.oasis-open.org/ubl/os-UBL-2.1/>

### Country-specific or International document types <a href="#required" id="required"></a>

See the API page under Qvalia Developer Tools:

{% content-ref url="/pages/lZlrrZ0gu5MG85GDz5tL" %}
[API](/qvalia-developer-tools/api.md)
{% endcontent-ref %}

### Required <a href="#required" id="required"></a>

As the UBL JSON schema is fairly big, we only list the `required` attributes in the sample request and response data. You can browse the complete `JSON schema` viewing the `UBL-Invoice-2.1`.

### Attachments <a href="#attachments" id="attachments"></a>

Often our customers wants to add, or request, attached documents to their messages, e.g. their invoices.

We support all the same attachments as Peppol does: Peppol media types

See more under [Attachments to messages](/qvalia-developer-tools/attachments-to-messages.md)

A PDF attachment whose `DocumentDescription` or `filename` contains `Commercial Invoice` is used as the invoice PDF (for e-mail, post, internet bank, digital mailbox and Duplo), and Qvalia generates none of its own. See [Your own invoice PDF](/qvalia-developer-tools/attachments-to-messages.md#commercial-invoice).

### Supported formats on `/invoices` and `/creditnotes` <a href="#supported-formats" id="supported-formats"></a>

`POST /transaction/{accountRegNo}/invoices/outgoing` and `POST /transaction/{accountRegNo}/creditnotes/outgoing` take these formats directly. The `CustomizationID` (BT-24) in the document says which one it is, and decides the validation rules.

| Format                                                                                | `CustomizationID` (BT-24)                                                                                                                                 | Send as          | Validated with                                                                        |
| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------- |
| **Peppol BIS Billing 3.0** (UBL)                                                      | `urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0`                                                                              | XML, or UBL JSON | Peppol BIS Billing 3.0 rules                                                          |
| **Peppol BIS Self-Billing 3.0** (UBL)                                                 | `urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:selfbilling:3.0`                                                                          | XML, or UBL JSON | Peppol BIS Self-Billing 3.0 rules                                                     |
| **Peppol PINT** (UBL): EU, A-NZ, Japan, Malaysia, Singapore, UAE                      | `urn:peppol:pint:billing-1@<country>-1`, e.g. `urn:peppol:pint:billing-1@jp-1`                                                                            | XML, or UBL JSON | That PINT's rules. See [Country-specific or International document types](#required). |
| **XRechnung 3.0 UBL**, plain or Extension (Peppol code list rows 237, 238, 240)       | `urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0` (+ `#conformant#urn:xeinkauf.de:kosit:extension:xrechnung_3.0` for the Extension) | XML              | KoSIT's XRechnung rules                                                               |
| **CII**, UN/CEFACT CrossIndustryInvoice D16B: Peppol BIS Billing CII (row 36)         | `urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0`                                                                              | XML              | EN 16931 CII rules, then Peppol rules on the converted UBL                            |
| **CII**: EN 16931 CII (row 94), e.g. the XML of a ZUGFeRD / Factur-X EN 16931 invoice | `urn:cen.eu:en16931:2017`                                                                                                                                 | XML              | EN 16931 CII rules, then Peppol rules on the converted UBL                            |
| **CII**: XRechnung 3.0 CII, plain or Extension (rows 239, 242)                        | as XRechnung UBL above                                                                                                                                    | XML              | KoSIT's XRechnung CII rules, then XRechnung rules on the converted UBL                |

* UBL JSON is the OASIS UBL 2.1 JSON representation (see above). XRechnung and CII are XML only: their `UBLExtensions` (the XRechnung Extension, or vendor data) cannot be carried in JSON, and a JSON body with `UBLExtensions` is answered with `422`.
* CII has one root element for invoices and credit notes alike. A CII credit note (type code 381 and the other credit-note codes) goes to `/creditnotes`, anything else to `/invoices`. The wrong one is answered with `422`, naming the right endpoint.
* Qvalia stores a CII document as the equivalent UBL, so `GET` returns UBL. The original CII is kept: it is what we send over Peppol when the receiver is registered for that CII document type (otherwise the UBL), and `GET /transaction/{accountRegNo}/document/download` returns it.
* The XRechnung UBL Credit Note Extension (row 241) was removed from Peppol on 2026-08-01 and is not accepted as UBL. Send such a credit note as XRechnung CII Extension instead.
* Only document types in the Peppol code list (currently v9.7), and not removed from it, are sent or received over Peppol.
* Other formats (Svefaktura 1.0, ZUGFeRD / Factur-X, EDIFACT, cXML, Finvoice 3.0, ...) go through the upload endpoint, see [Other formats than Peppol](#other-formats-than-peppol). More formats can be added on request: contact <help@qvalia.com>.

### Delivery methods <a href="#delivery-methods" id="delivery-methods"></a>

Outgoing invoices and credit notes go over Peppol by default. Add `delivery_method` to the `POST` to send them another way. It is taken by `POST /invoices/outgoing`, `POST /creditnotes/outgoing` and `POST /document/upload` only: any other endpoint answers `400` when it is given.

| `delivery_method`                                   | Sent                                                                                                                                       | The document must carry                                                                            |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `peppol` (default)                                  | Over the Peppol network                                                                                                                    | A receiver registered in Peppol                                                                    |
| `email`                                             | By e-mail                                                                                                                                  | The buyer's e-mail address (`AccountingCustomerParty > Party > Contact > ElectronicMail`)          |
| `postal`                                            | Printed and posted                                                                                                                         | The buyer's name and complete postal address (`AccountingCustomerParty > Party > PostalAddress`)   |
| `internetbank`, `kivra`, `billo`, `minameddelanden` | To a consumer's internet bank or digital mailbox                                                                                           | A Swedish personal number or FMI address (`AccountingCustomerParty > Party > PartyIdentification`) |
| `edi`                                               | Over EDI                                                                                                                                   | As agreed with Qvalia for your account                                                             |
| `finvoice`                                          | As Finvoice (3.0, or 2 if your account is set up for it), over the Finnish e-invoicing network (through Qvalia's Finnish operator partner) | The buyer's Finnish business ID or OVT code                                                        |
| `dynamic_routing`                                   | The channel Qvalia chooses for each receiver                                                                                               | Nothing extra                                                                                      |

Delivery methods must be added to your account before you can use them, except for `peppol`, which is the default and always enabled. Using a method outside your agreement results in a `403 Forbidden` error naming the refused delivery method.

Contact your Qvalia sales representative, or Qvalia sales, to add delivery methods to your agreement.

The document is always sent as Peppol BIS Billing 3.0 and validated as such. Only `peppol` also requires the receiver to be registered in Peppol.

{% hint style="info" %}
With `dynamic_routing`, Qvalia chooses the channel for each receiver, among the ones your account is set up for: Peppol, a digital mailbox or internet bank, e-mail or print.
{% endhint %}

### Other formats than Peppol <a href="#other-formats-than-peppol" id="other-formats-than-peppol"></a>

If your system does not produce Peppol BIS, upload the invoice or credit note in its own format and Qvalia converts it:

`POST /transaction/{accountRegNo}/document/upload?type=invoice&format=xrechnung`

* `type`: `invoice` or `creditnote`.
* `format`: one of the upload formats below.
* After conversion it is an ordinary outgoing document: the same validation, duplicate check, `overwrite` and `delivery_method` as a Peppol `POST`, and the same response with the document's `integrationId`.
* Add `validateOnly=true` to check the conversion without sending anything.
* Add `sendingPeppolId` and/or `receivingPeppolId` (`<scheme>:<identifier>`, e.g. `0007:5599000295`) to set the sender's and receiver's Peppol participant IDs, whatever the document says. Use this for a format with no Peppol address.

**Upload formats**

| `format`      | Format                                                                                                                                                            | Send it as                                                                                                                                                                                                   |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `svefaktura1` | Svefaktura 1.0                                                                                                                                                    | XML (`application/xml`)                                                                                                                                                                                      |
| `xrechnung`   | XRechnung 3.0, UBL or CII syntax (plain or Extension)                                                                                                             | XML (`application/xml`)                                                                                                                                                                                      |
| `cii`         | UN/CEFACT Cross Industry Invoice (CII D16B): Peppol BIS Billing CII, EN 16931 CII                                                                                 | XML (`application/xml`)                                                                                                                                                                                      |
| `zugferd`     | ZUGFeRD 2.x                                                                                                                                                       | The CII XML embedded in the PDF, not the PDF itself (`application/xml`)                                                                                                                                      |
| `facturx`     | Factur-X                                                                                                                                                          | The CII XML embedded in the PDF, not the PDF itself (`application/xml`)                                                                                                                                      |
| `edifact`     | UN/EDIFACT INVOIC, directory versions D.93A to D.16B, including EANCOM 1997 (D.96A) and EANCOM 2002 (D.01B). A credit note is an INVOIC with BGM 381, 383 or 396. | One message per upload, UTF-8 encoded (`application/edifact` or `text/plain`)                                                                                                                                |
| `cxml`        | cXML `InvoiceDetailRequest` (SAP Ariba, Coupa). A credit memo has `purpose="creditMemo"` or `"lineLevelCreditMemo"`.                                              | `application/xml`. cXML has no Peppol participant ids: give them with `receivingPeppolId` / `sendingPeppolId` unless the document carries them, and `buyerReference` for an invoice without a purchase order |
| `finvoice3`   | Finvoice 3.0 (Finland), an invoice or a credit note                                                                                                               | `application/xml`                                                                                                                                                                                            |

Peppol BIS, XRechnung and CII can also be sent straight to `POST .../invoices/outgoing` and `.../creditnotes/outgoing`, without the upload endpoint.

Qvalia stores the converted Peppol document. To get a document back in your format, use its `integrationId`:

`GET /transaction/{accountRegNo}/document/download?type=invoice&integrationId={integrationId}`

Without `format`, the document comes back in the format it was uploaded in. A document sent as CII comes back as the original CII. Svefaktura 1.0 and EDIFACT also come back as Peppol BIS: Svefaktura 1.0 can be uploaded but not produced, and EDIFACT is only produced as INVOIC D.96A (EANCOM 1997), which may not be the version you uploaded. Ask for `format=edifact` to get the D.96A. Any download format can be asked for, so a document sent as Peppol can also be downloaded as, for example, XRechnung.

**Download formats**

| `format`       | Format                                                                                    | Returned as                                                     |
| -------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `peppol`       | Peppol BIS Billing 3.0 UBL, as stored                                                     | XML                                                             |
| `xrechnung`    | XRechnung 3.0 UBL                                                                         | XML                                                             |
| `xrechnungcii` | XRechnung 3.0 CII                                                                         | XML                                                             |
| `cii`          | CII D16B, keeping the document's specification (the original, for a document sent as CII) | XML                                                             |
| `zugferd`      | ZUGFeRD PDF/A-3 with the CII embedded                                                     | JSON: `{ filename, mimeType, content }`, the PDF base64-encoded |
| `facturx`      | Factur-X PDF/A-3 with the CII embedded                                                    | JSON: `{ filename, mimeType, content }`, the PDF base64-encoded |
| `finvoice2`    | Finvoice 2 (invoices only)                                                                | XML                                                             |
| `finvoice3`    | Finvoice 3.0                                                                              | XML                                                             |
| `cxml`         | cXML `InvoiceDetailRequest` (a credit note as a credit memo)                              | XML                                                             |
| `edifact`      | UN/EDIFACT INVOIC D.96A, EANCOM 1997 (`EAN008`)                                           | EDIFACT (`application/edifact`), UTF-8                          |

Partners reach both endpoints for their accounts under `/partner/{partnerRegNo}/transaction/{accountRegNo}/document/...`.

{% hint style="info" %}
**Need another format?** We add formats on request: another e-invoice standard, another EDIFACT subset or trading partner guide, a national format, or a customer's or ERP system's own format. Contact <help@qvalia.com> with a few sample documents and we'll get back to you.
{% endhint %}

### Retrying a submission safely <a href="#retrying-a-submission-safely" id="retrying-a-submission-safely"></a>

Send an `Idempotency-Key` header on any POST — a unique value you generate per\
submission, a UUID by preference:

```
Idempotency-Key: b7f3a1c2-9d4e-4f5a-8b6c-1d2e3f4a5b6c
```

If the connection breaks after we accept the POST but before the response reaches you,\
repeating the identical request tells you whether the document was created, without\
creating a second one — you get the original response back, with the original\
`integrationId`.

| Situation                                     | Result                            |
| --------------------------------------------- | --------------------------------- |
| Same key, same body, request finished         | The original response is replayed |
| Same key, same body, original still in flight | `409`                             |
| Same key, different body                      | `400`                             |
| Key older than 24 hours                       | Treated as a new request          |

Keys are scoped to your account. A request that fails releases its key, so you can retry\
with the same one after an error.

### Duplicates <a href="#duplicates" id="duplicates"></a>

Submitting a document with the same document id and receiver as an existing one is\
rejected with `409 Conflict`. The response names the document it collided with:

```
{
  "status": "error",
  "type": "E_CONFLICT",
  "data": "Duplicate invoice, 123456-INV request rejected!",
  "metadata": { "integrationId": "6b928ef1-fb0d-4b9a-a56f-b5dbca7a0fd4" }
}
```

That is the same id the original successful submission returned, so you can reconcile\
without a follow-up `GET`. If you intend to replace the document, re-submit with\
`?overwrite=true`. To avoid the collision in the first place, send an `Idempotency-Key`.

#### Replacing a document with `?overwrite=true` <a href="#overwrite" id="overwrite"></a>

A submission with `?overwrite=true` is always stored as a **new** document, with its own `integrationId`, and processed like any other message. An outgoing one is sent again.

The document it replaces is kept, but it is no longer listed or returned by the read endpoints. You can still fetch it by its own `integrationId`, for example with `/status?integrationId=`. Its `metadata.replacedBy` names the new document's `integrationId`, and the new document names it in `metadata.replaces`.

Use the new `integrationId` from the response from then on. The old one keeps receiving the status updates for the message that was sent before it was replaced.

### Read endpoints <a href="#read-endpoints" id="read-endpoints"></a>

The `read` endpoints return only unread messages and mark what they return as read.

**There is one read mark per document per account, not a cursor per consumer.** If two\
systems poll the same account, each document goes to whichever asks first. Run one\
consumer per account, or use the plain `GET` endpoints with `limit`/`offset` instead.

If a document was marked read but your downstream handling failed, `markUnread=true`\
returns it to the unread pool. It must be scoped by at least one of `integrationId`,\
`documentId`, `from` or `updatedAtFrom`.

### Status endpoints <a href="#status-endpoints" id="status-endpoints"></a>

Every document type has a `/status` endpoint per direction, for example\
`GET /transaction/{accountRegNo}/invoices/outgoing/status`. It returns the delivery status of\
each matching document and every webhook delivery made for it — without the document payload,\
so it is cheap to poll. It takes the same filters as the plain `GET` (`integrationId`,\
`documentId`, `from`/`to`, `updatedAtFrom`/`updatedAtTo`, `limit`/`offset`), and returns only\
unread documents unless you add `includeRead=true`. It does not mark anything as read.

```json
{
  "status": "success",
  "data": [
    {
      "integrationId": "29cca64f-a7dd-49fa-a5f4-29f157d9fbc0",
      "globalTransactionId": "9b0896ae-e18f-442b-8378-bd445298c7e8",
      "readAt": null,
      "metadata": {
        "status": {
          "event": "message-log/update",
          "status": "processed",
          "deliveryMethod": "peppol",
          "updatedAt": "2026-09-29T06:36:42.622Z"
        },
        "webhooks_dispatched": [
          {
            "eventId": "f455a5d6-b94f-5908-b835-7a1cf67d438f",
            "eventType": "new_document",
            "success": false,
            "status": 502,
            "statusText": "Bad Gateway",
            "signed": false,
            "occurredAt": "2026-09-29T06:36:11.997Z",
            "dispatchedAt": "2026-09-29T06:36:12.579Z"
          }
        ]
      }
    }
  ]
}
```

| Field                          | Notes                                                                                          |
| ------------------------------ | ---------------------------------------------------------------------------------------------- |
| `integrationId`                | Qvalia's document id — the same one the document endpoints take.                               |
| `globalTransactionId`          | Platform-wide id for the document exchange, as carried on webhooks. `null` when not yet known. |
| `readAt`                       | When the document was marked read, or `null`.                                                  |
| `metadata.status`              | The latest delivery status — the same object delivered as `status` on webhooks.                |
| `metadata.webhooks_dispatched` | Every webhook delivery attempt for the document, oldest first. See below.                      |

Other keys can appear under `metadata`; ignore any you do not recognise.

#### `webhooks_dispatched`

One entry per delivery attempt, to each subscription that received the event.

| Field          | Notes                                                                                                 |
| -------------- | ----------------------------------------------------------------------------------------------------- |
| `eventId`      | The delivered event. Fetch its body again, for 30 days, with `GET …/webhook/{eventId}`.               |
| `eventType`    | `new_document`, `document_delivery`, `document_delayed` or `document_error`.                          |
| `success`      | Whether your endpoint answered `2xx`.                                                                 |
| `status`       | The HTTP status your endpoint answered. Absent when no response came back.                            |
| `statusText`   | The HTTP reason phrase for `status`, e.g. `Bad Gateway`.                                              |
| `error`        | Why no response came back (a timeout, an unreachable host). Present only when `status` is absent.     |
| `signed`       | Whether the delivery carried `X-Qvalia-Signature`.                                                    |
| `partnerRegNo` | On a child account's status: the partner, for a delivery to the partner's subscription to that child. |
| `occurredAt`   | When the event happened.                                                                              |
| `dispatchedAt` | When the delivery was attempted.                                                                      |

{% hint style="info" %}
A failed delivery is not retried. To recover one, take its `eventId` from here and fetch the body\
with `GET …/webhook/{eventId}` — see [Webhooks](/api-documentation/apis/partner-api/webhooks.md#delivery).
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://api.qvalia.io/api-documentation/apis/transaction-api.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
