Factura (01)
La Factura (tipo 01) se emite a consumidor final — personas naturales sin NRC, o clientes que no requieren crédito fiscal. Es el tipo de DTE más común en retail, restaurantes y servicios al público.
Detalles técnicos
| Método | POST |
| URL | https://ocote.io/api/connect/invoice |
| Content-Type | application/json |
| Autenticación | Header Authorization: Bearer odt_... |
Request
Campos principales
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
doc_type | string | No (default "01") | Tipo de DTE. Para Factura: "01". |
lines | array | Sí | Líneas del documento. Al menos una. Ver LineIn. |
customer | object | No | Datos del cliente. Opcional en Factura 01. Ver CustomerIn. |
customer_name | string | No | Nombre del consumidor para facturas sin objeto customer. Default: "Consumidor Final". |
payment_method | string | No (default "01") | Forma de pago. Ver Catálogos MH. |
transaction_condition | int | No (default 1) | 1 = Contado, 2 = Crédito, 3 = Otro. |
deadline | int | No (default 1) | Plazo de pago en días (solo aplica a transaction_condition: 2). |
period | int | No (default 1) | Periodo del plazo. |
activity_code | string | No | Código de actividad económica del emisor para este documento. Override del default de la empresa. |
redirect_email | string | No | Correo adicional al que se envía copia del DTE (además del del customer). |
external_ref | string | No | Tu identificador idempotente. Ver Retry e idempotencia. |
Líneas (lines)
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
description | string | Sí | Descripción del producto/servicio. Máx 1 000 caracteres. |
quantity | float | Sí | Cantidad. Debe ser mayor a cero. |
unit_price | float | Sí | Precio unitario con IVA incluido. Debe ser mayor a cero. |
discount_percentage | float | No (default 0) | Descuento en porcentaje (0-99). |
Cliente (customer)
Totalmente opcional en Factura 01. Si no lo envías o lo envías incompleto, Ocote aplica defaults razonables:
| Campo | Tipo | Requerido | Default (al crear) | Descripción |
|---|---|---|---|---|
name | string | Sí (si envías customer) | — | Nombre o razón social. |
nit | string | No | — | NIT del cliente (si aplica). |
nrc | string | No | — | NRC del cliente (solo si es contribuyente IVA). |
dui | string | No | — | DUI para personas naturales. |
document_type | string | No | "36" | Tipo de documento identificador MH. |
type_contributor | int | No | 1 (Pequeño) | Tipo de contribuyente. Ver Convenciones. |
favorite_doc | string | No | "01" | Tipo de DTE preferido del cliente. |
address | string | No | "San Salvador" | Dirección. |
activity_code | string | No | — | Código actividad económica del cliente. |
department | string | No | — | Código de departamento MH. Ver Catálogos MH. Si lo envías, municipality también es obligatorio. |
municipality | string | No | — | Código de municipio MH. |
email | string | No | — | Correo electrónico para envío del DTE. |
phone | string | No | — | Teléfono. Bug conocido: omite este campo temporalmente, ver Convenciones. |
Si el customer.nit (o customer.dui) ya existe en tu empresa en Ocote, el API actualiza únicamente los campos que enviaste explícitamente. Si no existe, crea el cliente con los defaults de la tabla anterior. Los campos fiscales sensibles (type_contributor, favorite_doc, document_type, nit, nrc, dui) se auditan en el log interno de Ocote cuando cambian.
Response
Ver Respuestas y estados para la semántica completa de flags. Campos específicos de /invoice:
| Campo | Tipo | Descripción |
|---|---|---|
document_id | string (UUID) | Identificador interno Ocote. |
external_ref | string | El que enviaste (o el autogenerado). |
control_number | string | Correlativo DTE MH. Nunca se regenera. |
generation_code | string | Código de generación MH (igual al UUID en mayúsculas). |
reception_stamp | string | Sello de recepción MH. Vacío si contingency: true o rejected: true. |
amount_taxable | float | Base gravable (precio sin IVA). |
amount_vat | float | IVA 13%. |
amount_gross | float | Total con IVA, antes de retención. |
amount_retention | float | Retención IVA 1% (aplica solo si receptor es type_contributor 3 o 4 y amount_taxable >= 100). |
amount_total | float | Total neto = amount_gross − amount_retention. |
ticket_url | string | URL al ticket PDF. Disponible si el documento se procesó. |
json_url | string | URL al JSON firmado. Solo si dte_success: true. |
dte | object | Schema completo del DTE firmado (solo si dte_success: true). |
Ejemplo mínimo: venta simple
curl -X POST https://ocote.io/api/connect/invoice \
-H "Authorization: Bearer odt_xxx" \
-H "Content-Type: application/json" \
-d '{
"external_ref": "VENTA-2026-0042",
"lines": [
{ "description": "Café americano", "quantity": 2, "unit_price": 2.50 },
{ "description": "Empanada de pollo", "quantity": 1, "unit_price": 3.00 }
]
}'
const { data } = await axios.post(
'https://ocote.io/api/connect/invoice',
{
external_ref: 'VENTA-2026-0042',
lines: [
{ description: 'Café americano', quantity: 2, unit_price: 2.50 },
{ description: 'Empanada de pollo', quantity: 1, unit_price: 3.00 },
],
},
{ headers: { Authorization: `Bearer ${process.env.OCOTE_API_KEY}` } }
);
r = requests.post(
"https://ocote.io/api/connect/invoice",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"external_ref": "VENTA-2026-0042",
"lines": [
{"description": "Café americano", "quantity": 2, "unit_price": 2.50},
{"description": "Empanada de pollo", "quantity": 1, "unit_price": 3.00},
],
},
)
Ejemplo completo: con cliente y crédito
curl -X POST https://ocote.io/api/connect/invoice \
-H "Authorization: Bearer odt_xxx" \
-H "Content-Type: application/json" \
-d '{
"external_ref": "VENTA-2026-0043",
"customer": {
"name": "Juan Pérez",
"dui": "01234567-8",
"email": "juan@example.com",
"address": "Colonia Escalón, San Salvador"
},
"lines": [
{
"description": "Consultoría de marketing - 8 horas",
"quantity": 8,
"unit_price": 50.00,
"discount_percentage": 10
}
],
"payment_method": "05",
"transaction_condition": 2,
"deadline": 30,
"redirect_email": "contabilidad@miempresa.com"
}'
payment_method: "05" = Transferencia. transaction_condition: 2 = Crédito. deadline: 30 = 30 días. Ver Catálogos MH para el listado completo de códigos.
Respuesta exitosa
{
"success": true,
"dte_success": true,
"contingency": false,
"rejected": false,
"posted": true,
"is_duplicate": false,
"document_id": "a1b2c3d4-1234-5678-9abc-def012345678",
"external_ref": "VENTA-2026-0042",
"control_number": "DTE-01-M001P001-000000000000123",
"generation_code": "A1B2C3D4-1234-5678-9ABC-DEF012345678",
"reception_stamp": "20260421154532...",
"amount_taxable": 7.96,
"amount_vat": 1.04,
"amount_gross": 9.00,
"amount_retention": 0.00,
"amount_total": 9.00,
"ticket_url": "https://ocote.io/api/connect/file/a1b2c3d4-1234-5678-9abc-def012345678?type=ticket&key=odt_xxx",
"json_url": "https://ocote.io/api/connect/file/a1b2c3d4-1234-5678-9abc-def012345678?type=json&key=odt_xxx"
}
Errores de validación específicos
HTTP 400 con detalle en detail:
| Mensaje | Causa |
|---|---|
doc_type debe ser uno de: 01, 03, 11 | Valor de doc_type inválido. |
Debe incluir al menos una línea | lines vacío o ausente. |
Línea N: cantidad debe ser mayor a cero | Algún item con quantity <= 0. |
Línea N: precio unitario debe ser mayor a cero | Algún item con unit_price <= 0. |
Línea N: descripción es requerida | Descripción vacía. |
Departamento/municipio no encontrado: X/Y | Combinación department/municipality no existe en el catálogo MH. |
Ver también
- Convenciones — montos con IVA incluido, timezone, valores enumerados.
- CCF (03) — emisión a contribuyentes IVA con NIT y NRC.
- Wildcard items — cómo funciona el catálogo interno y retenciones automáticas.
- Catálogos MH — códigos de actividad, departamento, municipio, forma de pago.
- Respuestas y estados — semántica completa del response.