Conectar tu sistema de facturación con la tienda (API)
Que tu propio sistema de facturación use los productos, el stock y los clientes de tu tienda, y que las ventas que factura bajen el stock y queden como pedidos cobrados. Vos elegís qué puede hacer. Incluye la guía para tu programador.
Si facturás con tu propio sistema, podés conectarlo con tu tienda para que use tus productos, tu stock y tus clientes, y para que las ventas que factura bajen el stock y aparezcan como pedidos cobrados en tu panel.
Cómo se activa
Entrá a Facturación → Configuración
En tu panel: Facturación → Configuración, elegí «Otro sistema de facturación» y bajá hasta «2 · Que tu sistema use la tienda». Ahí mismo está, arriba, la conexión para facturar desde la tienda con tu sistema: todo lo de tu sistema de facturación vive en esa pantalla.
Elegí qué puede hacer tu sistema
Marcá las casillas. Sólo lectura son las tres primeras (productos, stock y clientes). Para que las ventas bajen el stock, marcá también «Registrar las ventas». Lo podés cambiar cuando quieras, sin cambiar la llave.
Creá la llave y pasásela a tu programador
Tocá Crear la llave. Se muestra una sola vez: copiala y pasásela a quien programa tu sistema, junto con la dirección que aparece en la misma pantalla y el link de esta página.
Con la llave, tu sistema puede hacer lo que marcaste. Si se pierde o la vio quien no debía, creá una nueva desde la misma pantalla: la anterior deja de funcionar al instante. Desconectar la corta del todo.
Guía técnica (para tu programador)
Escribila (ej. https://mitienda.com.py o https://mitienda.maxtiendas.app) y todas las URLs de esta guía quedan listas para copiar.
Todas las rutas de esta página quedan así: https://tutienda.maxtiendas.app/api/v2/admin/external-billing
1. Antes de empezar
El administrador de la tienda entra a su panel → Facturación → Configuración, elige «Otro sistema de facturación» y, en «2 · Que tu sistema use la tienda», marca qué puede hacer tu sistema y genera la llave él mismo. Te pasa dos cosas:
| Dato | Ejemplo |
|---|---|
| Dirección base | https://mitienda.maxtiendas.app/api/v2/admin/external-billing |
| Llave | 57|kH3n... (se muestra una sola vez) |
Cada llamada lleva tres cabeceras:
Authorization: Bearer <llave>
Accept: application/json
Content-Type: application/json
Permisos de la llave
El comerciante elige qué habilita. Si llamás a algo que no habilitó, la respuesta
es 403 con "permiso": "<cual>" en el cuerpo.
| Permiso | Rutas |
|---|---|
productos | GET /products |
stock | GET /stock |
clientes | GET /customers |
ventas | POST /sales, /sales/{id}/status, /sales/{id}/cancel |
notas | notas de crédito y de débito |
remisiones | notas de remisión |
cobros | cobros de ventas a crédito |
GET /me y DELETE /token funcionan con cualquier llave.
Respuestas y errores
| Código | Qué significa |
|---|---|
200 / 201 | Bien. 201 = se creó algo nuevo; 200 en un alta = ya existía (ver reintentos). |
401 | Falta la llave o no es válida (la borraron o crearon otra). |
403 | La llave no tiene ese permiso, o la ruta no es de esta integración. |
404 | La tienda no tiene ese documento. |
422 | Datos inválidos. El cuerpo trae message y errors por campo. |
429 | Más de 120 llamadas por minuto. Esperá y reintentá. |
2. Identificar la tienda
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/me {
"data": {
"tienda": "Mi Tienda",
"url": "https://mitienda.maxtiendas.app",
"stock": true,
"moneda": "PYG",
"iva": 10,
"usuario": "Juan Pérez"
}
}
stock: false→ la tienda no lleva inventario: no hace falta consultar stock.moneda→ todas las ventas tienen que venir en esta moneda.iva→ la tasa general de la tienda (10, 5 o 0).
3. Productos
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/products Dos formas:
- Buscar (para el buscador al facturar):
GET /products?q=sofa→ hasta 50 resultados, por nombre o código. - Traer todo (para sincronizar tu base): sin
q, paginado.page(desde 1),per_page(máximo 200, por defecto 100)updated_since=2026-10-01T00:00:00→ sólo lo modificado desde esa fecha
{
"data": [
{
"product_id": 1,
"attribute_id": null,
"codigo": "16707",
"descripcion": "Sofa Molufan Dallas 3 y 2 Lugares",
"nombre": "Sofa Molufan Dallas 3 y 2 Lugares",
"variacion": null,
"precio": 3500000,
"iva": 10,
"stock": { "controla": true, "disponible": 400 }
},
{
"product_id": 15,
"attribute_id": 88,
"codigo": "REM-AZ-M",
"descripcion": "Remera básica - Color : Azul, Talle : M",
"nombre": "Remera básica",
"variacion": "Color : Azul, Talle : M",
"precio": 120000,
"iva": 10,
"stock": { "controla": true, "disponible": 7 }
}
],
"meta": { "page": 1, "per_page": 100, "total": 2532, "last_page": 26 }
}
- Cada variación (talle, color) es su propia fila, con su
attribute_id. Se factura y se descuenta la variación, no el producto general. precioes el precio de venta con IVA incluido (la oferta, si tiene).- Guardá
product_idyattribute_id: con eso la venta baja el stock de lo correcto. metasólo viene al traer todo, no en la búsqueda.
4. Stock
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/stock?items=1:0,15:88 Lo disponible justo antes de emitir (entre la búsqueda y la emisión pudo venderse algo en la web).
items = pares product_id:attribute_id separados por coma (0 si no tiene variación), hasta 200.
{
"data": [
{ "product_id": 1, "attribute_id": null, "existe": true, "stock": { "controla": true, "disponible": 400 } },
{ "product_id": 15, "attribute_id": 88, "existe": true, "stock": { "controla": true, "disponible": 7 } }
]
}
5. Clientes
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/customers Igual que productos: ?q= busca (nombre, apellido, correo, CI o RUC; hasta 50) y sin q trae todos paginados con updated_since.
{
"data": [
{
"customer_id": 4,
"codigo_cliente": "MT-4",
"nombre": "Ana González",
"ruc": null,
"naturaleza": 2,
"tipo_documento": 1,
"numero_documento": "4760362",
"direccion": "Av. Mcal. López 1234",
"email": "ana@ejemplo.com",
"telefono": "0981234567"
}
],
"meta": { "page": 1, "per_page": 100, "total": 12, "last_page": 1 }
}
naturaleza: 1 = contribuyente (tiene RUC), 2 = no contribuyente.tipo_documento(sin RUC): 1 = cédula, 5 = innominado.- Mandá
codigo_clienteen la venta: así el pedido queda a nombre de ese cliente en la tienda.
6. Registrar una venta
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales Cuando tu sistema emite una factura con productos de la tienda, mandala acá. La tienda crea un pedido cobrado y facturado y baja el stock.
{
"documento_id": 5001,
"numero": "001-001-0000123",
"cdc": "01800123456001001000012312026100112345678901",
"estado": "APPROVED",
"fecha": "2026-10-01T10:30:00",
"moneda": "PYG",
"total": 300000,
"condicion": 1,
"pagos": [ { "tipo_pago": 1, "monto": 300000 } ],
"receptor": {
"nombre": "Ana González",
"numero_documento": "4760362",
"email": "ana@ejemplo.com",
"telefono": "0981234567",
"codigo_cliente": "MT-4"
},
"items": [
{
"product_id": 1,
"product_attribute_id": null,
"codigo": "16707",
"descripcion": "Sofa Molufan Dallas",
"cantidad": 2,
"precio_unitario": 150000,
"descuento": 0
}
]
}
Respuesta 201:
{ "message": "Venta registrada.", "data": { "order_id": 111, "reference": "SBK580321276", "existed": false } }
| Campo | Obligatorio | Qué es |
|---|---|---|
documento_id | sí | El identificador interno y único del documento en TU sistema (entero > 0). Es la clave de todo lo demás: reintentos, anulación, notas, cobros. |
total | sí | Total de la factura. |
items | sí | Las líneas (1 a 999). |
items.*.descripcion | sí | |
items.*.cantidad | sí | Mayor a 0. |
items.*.precio_unitario | sí | Con IVA incluido. Manda el de la factura, aunque difiera del catálogo. |
items.*.product_id / product_attribute_id | no | Los de la tienda. Sin product_id la línea no mueve stock (sirve para servicios, fletes, cosas que no están en la tienda). |
numero, cdc, estado, fecha | no | Los datos de la factura electrónica. |
moneda | no | Por defecto PYG. Tiene que ser la de la tienda (GET /me), si no → 422. |
condicion | no | 1 = contado, 2 = crédito. |
pagos[] | no | Cómo se cobró (contado). tipo_pago según SIFEN: 1 efectivo · 3 tarjeta de crédito · 4 tarjeta de débito · 5 transferencia · 7 billetera · 16 pago bancario · 17 pago móvil · 21 pago electrónico. |
credito | no | Si es a crédito: condicion (1 plazo, 2 cuotas), plazo, cuotas, entrega_inicial, detalle_cuotas[] { monto, vencimiento }. La tienda arma el plan de cuotas. |
receptor | no | A quién se facturó. Con codigo_cliente (MT-<id>) se engancha al cliente de la tienda. |
Reintentos (importante)
Si no recibís respuesta, reintentá con el mismo documento_id. Si la venta ya
estaba registrada, la respuesta es 200 con "existed": true y el mismo pedido.
Nunca se duplica.
Si el comercio también factura desde la tienda con tu sistema
Las dos conexiones se pueden usar juntas. Las facturas que la tienda te pidió emitir
(POST /sifen/de, en la guía Facturar con tu facturadora)
ya están en la tienda con su pedido: no hace falta mandarlas de vuelta. Si tu sistema
manda todas sus ventas sin distinguir, tampoco pasa nada, con una condición: el
documento_id tiene que ser el mismo id que le devolviste a la tienda al emitirla.
Con eso la respuesta es "existed": true y el pedido de la tienda; no se crea otro ni se
descuenta el stock dos veces. Vale igual para las notas de crédito, débito y remisión.
7. Después de emitir
Todas usan el documento_id de la venta en la dirección.
Estado ante la SET
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/status { "estado": "APPROVED", "cdc": "0180…", "numero": "001-001-0000123" }
Sólo registra el estado. Si la SET la rechazó, anulala con la ruta de abajo para que vuelva el stock.
Anular la venta
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/cancel Sin cuerpo. El pedido pasa a Cancelado y la mercadería vuelve al stock.
8. Notas de crédito y de débito (permiso notas)
Nota de crédito
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/credit-notes {
"documento_id": 7001,
"numero": "001-001-0000045",
"total": 150000,
"motivo": 2,
"items": [ { "product_id": 1, "product_attribute_id": null, "cantidad": 1 } ]
}
documento_ides el de la nota (único en tu sistema); el de la URL es el de la factura.motivo(SIFEN): 1 devolución y ajuste de precios · 2 devolución · 3 descuento · 4 bonificación · 5 crédito incobrable.- Con devolución (
motivo1 o 2) eitems, esa mercadería vuelve al stock. - Anular la nota:
POST /credit-notes/{documento_id_de_la_nota}/cancel.
Nota de débito
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/debit-notes { "documento_id": 7002, "numero": "001-001-0000046", "total": 50000, "motivo": 1 }
Sube lo que se debe del pedido.
Nota de remisión (permiso remisiones)
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/remissions La nota de remisión que tu sistema emitió para el traslado de esa venta.
{ "documento_id": 9001, "numero": "001-001-0000009", "cdc": "0180…", "estado": "APPROVED" }
documento_id: el de la remisión en tu sistema (único); el de la URL es el de la factura.- Queda registrada en el pedido de esa venta y no mueve stock (la mercadería ya salió con la factura).
- Reintentar con el mismo
documento_idno la duplica: responde200con"existed": true.
9. Cobros de ventas a crédito (permiso cobros)
Registrar un cobro
https://tutienda.maxtiendas.app/api/v2/admin/external-billing/sales/{documento_id}/payments { "recibo_id": 9001, "numero": "REC-0045", "importe": 100000, "fecha": "2026-10-15", "forma_pago": 1 }
recibo_id: identificador único del recibo en tu sistema. Reintentar con el mismo no lo duplica.- Se reparte solo entre las cuotas pendientes del pedido.
- Anular:
POST /sales/{documento_id}/payments/{recibo_id}/cancel.
10. Dar de baja la llave
DELETE /token — tu sistema elimina su propia llave (por ejemplo, al desinstalar la integración).
El comerciante también puede desconectarla desde su panel cuando quiera.
11. Flujo recomendado
- Al instalar:
GET /me(moneda, si lleva stock). Traé todo el catálogo y los clientes paginando. - Cada noche (o cada hora):
GET /products?updated_since=<última sincronización>y lo mismo con clientes. - Al facturar: buscá con
?q=; antes de emitir,GET /stockde las líneas para no vender lo que no hay. - Al emitir:
POST /sales. Si falla la red, reintentá con el mismodocumento_id. - Cuando responde la SET:
POST /sales/{id}/status; si la rechaza,POST /sales/{id}/cancel. - Anulaciones, notas, remisiones y cobros: las rutas de las secciones 7 a 9.
12. Probar con curl
BASE="https://mitienda.maxtiendas.app/api/v2/admin/external-billing"
KEY="57|kH3n..."
curl -s "$BASE/me" -H "Authorization: Bearer $KEY" -H "Accept: application/json"
curl -s "$BASE/products?per_page=5" -H "Authorization: Bearer $KEY" -H "Accept: application/json"
curl -s -X POST "$BASE/sales" \
-H "Authorization: Bearer $KEY" -H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"documento_id":1,"total":150000,"items":[{"product_id":1,"descripcion":"Prueba","cantidad":1,"precio_unitario":150000}]}'
⚠️ La última llamada registra una venta de verdad y baja el stock. Para probar, usá una tienda de prueba, o anulala después con
POST /sales/1/cancel.
¿Te sirvió este artículo?
¡Gracias por tu opinión!