The Spanish version is the authoritative reference. View in Spanish
📤 Issue documents
The main flow — issuing a document from the POS — is invoked with POST /api/v1/process-documents. This is the endpoint your POS will call on every sale.
Prefer to start from the code? The same flow is implemented in 8 languages in Integration examples.
POST /api/v1/process-documents is the only issuance route. The four input forms are selected with the inputType query param, not with different routes.
🔗 REST integration
What parameters it carries in the URL
They all go as query params (?env=…&operation=…&…). The first five are required; origin is conditional.
What goes in the body
The body format depends on inputType. Not all of them travel as JSON, and not all of them travel as base64:
inputType | Content-Type | Body |
|---|---|---|
json | application/json | The document object (inside document, or the bare object) |
xml | application/json | { "document": "<base64-encoded XML>" } |
xdoc | application/json | { "document": "<base64-encoded xDoc>" } |
txt | text/plain | The POS plain text as is: the body is the document, with no base64 and no JSON wrapper |
txt carries neither JSON nor base64With inputType=txt the request body is the POS plain text directly, with Content-Type: text/plain. Sending it inside a JSON object or base64-encoded makes the issuance fail.
🏢 Multiroot — several issuers on one device
From xPOS Core 2.6.0 onwards, a single device can have several issuers installed (several onboardings, each with its own certificate, credentials and folio ranges). Before 2.6.0 an installation operated a single issuer.
The origin parameter is the taxId of the issuer that owns the sale, and it sets the context for the whole pipeline: which range the folio is taken from, which certificate signs it, which credentials are used against the authority, and which issuer the document is attributed to.
| Issuers installed | origin | Behaviour |
|---|---|---|
| One | Optional | If omitted, it resolves to the only installed issuer. The contract is unchanged from previous versions. |
| Two or more | Required | Without origin the request is ambiguous and is rejected with HTTP 400. |
With several issuers installed and no origin, xPOS does not pick an issuer on its own: it returns 400. Signing a document with the wrong issuer is a legal problem; a 400 is an integration problem that gets fixed on the spot.
It applies equally over REST and WebSocket. A POS that integrates a single issuer today and never sends origin keeps working unchanged.
What xPOS Core does with your document
xPOS applies one of three internal patterns depending on the country. The difference lies in whether the final tax format is XML or JSON, and whether there is branching by document type.
Pattern A — XML with XSD (most countries)
When a document arrives with operation=consolidate:
- Receives the input (
json,xml,xdocortxt). - If the input is not XML, transforms it into XML
<root>. - Applies
input_to_dte_<country>.xslt→ Gosocket XML. - Applies
dte_to_fiscal_<country>.xslt→ tax DTE. - Validates the result against the official XSD.
- Assigns a folio (if the Folio Manager is active).
- Signs the DTE.
- Sends it to the tax authority.
- Returns the response to the POS.
- Publishes the DTE in Gosocket (Inbox).
Pattern B — JSON with JSON Schema
Same as Pattern A, but steps 4 and 5 generate tax JSON and validate against JSON Schema instead of XSD.
Pattern C — dual XML
Same as Pattern A, but step 4 branches according to the document type (tax DTE vs. equivalent, each with its own XSLT).
operation = testtest executes only steps 1–5 (transformation + validation). It does not assign a folio, does not sign, does not send to the tax authority and does not publish in Gosocket. It serves to validate that the document is well formed before issuing it for real.
Where txt and xdoc come in
txt and xdoc do not go through input_to_dte: each enters through its own transformation sheet, and follows the common path from there.
inputType | Entry sheet | Steps it replaces |
|---|---|---|
json / xml | input_to_dte_<country> | — (standard path) |
txt | other_to_dte_<country> | Replaces steps 2–3 |
xdoc | xdoc_to_dte_<country> | Replaces steps 2–3 |
From step 4 onwards the flow is identical for all four inputs.
Transformation sheets are downloaded by onboarding. If the sheet matching your inputType is not installed, the request fails with HTTP 404 before reaching the folio manager. If that happens, run PUT /api/v1/reobtain-config and retry.
🔄 WebSocket integration
The WebSocket channel does not appear in the Swagger (OpenAPI 3.0 does not model WebSockets). The functional contract described here is the implementation agreement for the ws://localhost:3200 integration.
Same functional flow as REST, with the difference that the parameters travel inside the request object (not in query params).
How it is sent
An object is assembled with the same content as the REST POST:
{"env":"sbx","operation":"consolidate","typeDoc":<N>,"country":"<XX>","inputType":"json","origin":"<taxId>","document":{...}}That object is serialized to a string and the string is sent in base64. The server processes it and also responds in base64; upon decoding, the structure is equivalent to the REST response.
origin follows the same rules as in REST: optional with a single issuer installed, required with two or more.
📬 And the response?
Regardless of the channel (REST or WebSocket), xPOS Core returns the same JSON object. It is documented field by field — including the error-handling contract — in Response and error handling.
Do you need the response in your own format (an XML or a JSON with the structure your ERP expects)? See Custom response.