📤 Emitir documentos
El flujo principal — emitir un documento desde el POS — se invoca con POST /api/v1/process-documents. Este es el endpoint que tu POS llamará en cada venta.
¿Prefieres partir del código? El mismo flujo está implementado en 8 lenguajes en Ejemplos de integración.
POST /api/v1/process-documents es la única ruta de emisión. Las cuatro formas de entrada se seleccionan con el query param inputType, no con rutas distintas.
🔗 Integración REST
Qué parámetros lleva en la URL
Todos van como query params (?env=…&operation=…&…). Los cinco primeros son obligatorios; origin es condicional.
Qué va en el body
El formato del cuerpo depende de inputType. No todos van en JSON ni todos van en base64:
inputType | Content-Type | Cuerpo |
|---|---|---|
json | application/json | El objeto del documento (dentro de document, o el objeto suelto) |
xml | application/json | { "document": "<XML en base64>" } |
xdoc | application/json | { "document": "<xDoc en base64>" } |
txt | text/plain | El texto plano del POS tal cual: el cuerpo es el documento, sin base64 y sin envoltorio JSON |
txt no lleva JSON ni base64Con inputType=txt el cuerpo de la petición es el texto plano del POS directamente, con Content-Type: text/plain. Enviarlo dentro de un objeto JSON o codificado en base64 hace fallar la emisión.
🏢 Multiroot — varios emisores en un mismo equipo
A partir de xPOS Core 2.6.0 un mismo equipo puede tener varios emisores instalados (varios onboardings, cada uno con su propio certificado, credenciales y rangos de folios). Antes de 2.6.0 una instalación operaba un solo emisor.
El parámetro origin es el taxId del emisor dueño de la venta, y fija el contexto de todo el procesamiento: de qué rango se toma el folio, con qué certificado se firma, con qué credenciales se envía a la autoridad y a qué emisor se atribuye el documento.
| Emisores instalados | origin | Comportamiento |
|---|---|---|
| Uno | Opcional | Si no se envía, se resuelve al único emisor instalado. El contrato no cambia respecto de versiones anteriores. |
| Dos o más | Obligatorio | Sin origin la petición es ambigua y se rechaza con HTTP 400. |
Con varios emisores instalados y sin origin, xPOS no elige un emisor por su cuenta: responde 400. Firmar un documento con el emisor equivocado es un problema legal; un 400 es un problema de integración que se corrige en el momento.
Aplica igual en REST y en WebSocket. Un POS que hoy integra un solo emisor y nunca envía origin sigue funcionando sin cambios.
Qué hace xPOS Core con tu documento
xPOS aplica uno de tres patrones internos según el país. La diferencia está en si el formato tributario final es XML o JSON, y en si hay bifurcación por tipo de documento.
Patrón A — XML con XSD (mayoría de países)
Cuando llega un documento con operation=consolidate:
- Recibe el input (
json,xml,xdocotxt). - Si el input no es XML, lo transforma a XML
<root>. - Aplica
input_to_dte_<pais>.xslt→ XML Gosocket. - Aplica
dte_to_fiscal_<pais>.xslt→ DTE tributario. - Valida el resultado contra el XSD oficial.
- Asigna folio (si el Gestor de Folios está activo).
- Firma el DTE.
- Lo envía a la entidad tributaria.
- Devuelve la respuesta al POS.
- Publica el DTE en Gosocket (Inbox).
Patrón B — JSON con JSON Schema
Igual que el Patrón A, pero los pasos 4 y 5 generan JSON tributario y validan contra JSON Schema en lugar de XSD.
Patrón C — XML dual
Igual que el Patrón A, pero el paso 4 se bifurca según el tipo de documento (DTE tributario vs. equivalente, cada uno con su XSLT).
operation = testtest ejecuta solo los pasos 1–5 (transformación + validación). No asigna folio, no firma, no envía a la entidad tributaria y no publica en Gosocket. Sirve para validar que el documento está bien armado antes de emitirlo en serio.
Dónde entran txt y xdoc
txt y xdoc no pasan por input_to_dte: cada uno entra por su propia hoja de transformación, y desde ahí sigue el camino común.
inputType | Hoja de entrada | Pasos que reemplaza |
|---|---|---|
json / xml | input_to_dte_<pais> | — (camino estándar) |
txt | other_to_dte_<pais> | Reemplaza los pasos 2–3 |
xdoc | xdoc_to_dte_<pais> | Reemplaza los pasos 2–3 |
Desde el paso 4 en adelante el flujo es idéntico para las cuatro entradas.
Las hojas de transformación las descarga el onboarding. Si la hoja correspondiente a tu inputType no está instalada, la petición falla con HTTP 404 antes de tocar el foliador. Si te ocurre, ejecuta PUT /api/v1/reobtain-config y reintenta.
🔄 Integración por WebSocket
El canal WebSocket no aparece en el Swagger (OpenAPI 3.0 no modela WebSockets). El contrato funcional descrito aquí es el acuerdo de implementación para la integración ws://localhost:3200.
Mismo flujo funcional que REST, con la diferencia de que los parámetros viajan dentro del objeto de request (no en query params).
Cómo se envía
Se arma un objeto con el mismo contenido que el POST REST:
{"env":"sbx","operation":"consolidate","typeDoc":<N>,"country":"<XX>","inputType":"json","origin":"<taxId>","document":{...}}Ese objeto se serializa a string y el string se envía en base64. El servidor procesa y responde también en base64; al decodificar, la estructura es equivalente al response REST.
origin sigue las mismas reglas que en REST: opcional con un solo emisor instalado, obligatorio con dos o más.
📬 ¿Y la respuesta?
Independientemente del canal (REST o WebSocket), xPOS Core devuelve el mismo objeto JSON. Está documentado campo a campo — incluido el contrato de errores — en Response y manejo de errores.
¿Necesitas la respuesta en tu propio formato (un XML o un JSON con la estructura que espera tu ERP)? Ver Respuesta personalizada.