📄 API documentos/crear — Crear Documento Electrónico
Endpoint: POST /api/documentos/crear
Controller: ElectronicDocumentController@process
Form Request: ProcessElectronicDocumentRequest
Service: ElectronicDocumentService
Autenticación: auth:sanctum (Bearer Token)
🔀 Flujo General
flowchart TD
A["🌐 Cliente API\nPOST /api/documentos/crear"] -->|"Bearer Token + JSON"| B["🔐 Middleware\nauth:sanctum"]
B -->|"No autenticado"| ERR0["⛔ 401 - No autenticado"]
B -->|"Autenticado"| C["📋 ProcessElectronicDocumentRequest\nPrepareForValidation + Validación"]
C -->|"❌ Inválido"| ERR1["⛔ 422 - Error de Validación"]
C -->|"✅ Válido"| D["🏢 Buscar Company\npor company_key"]
D -->|"No encontrada"| ERR2["⛔ 422 - Compañía no encontrada"]
D -->|"Encontrada"| E{"Se envió\nreceptor?"}
E -->|"Sí"| F["👤 Buscar o Crear\nCliente/Receptor"]
E -->|"No (solo tiquetes 04)"| F2["📝 Continuar\nsin receptor"]
F --> G["📝 Crear Documento"]
F2 --> G
G --> H["💰 Calcular Totales\nsubtotal + tax + total"]
H --> I["💾 Guardar Documento\nen Base de Datos"]
I --> J["📄 Finalizar Proceso\nConsecutivos + XML + Hacienda"]
J --> K["✅ 201 - Respuesta Exitosa"]
I -->|"Error"| ERR3["⛔ 422 - Error al procesar"]
style A fill:#4f46e5,color:#fff,stroke:#3730a3
style B fill:#7c3aed,color:#fff,stroke:#5b21b6
style C fill:#8b5cf6,color:#fff,stroke:#7c3aed
style D fill:#6366f1,color:#fff,stroke:#4f46e5
style E fill:#f59e0b,color:#fff,stroke:#d97706
style F fill:#0891b2,color:#fff,stroke:#0e7490
style G fill:#059669,color:#fff,stroke:#047857
style H fill:#10b981,color:#fff,stroke:#059669
style I fill:#14b8a6,color:#fff,stroke:#0d9488
style J fill:#06b6d4,color:#fff,stroke:#0891b2
style K fill:#16a34a,color:#fff,stroke:#15803d
style ERR0 fill:#dc2626,color:#fff,stroke:#b91c1c
style ERR1 fill:#dc2626,color:#fff,stroke:#b91c1c
style ERR2 fill:#dc2626,color:#fff,stroke:#b91c1c
style ERR3 fill:#dc2626,color:#fff,stroke:#b91c1c
📥 Campos de Entrada (Request)
🔑 Autenticación de Empresa
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
company_key |
string |
✅ Sí |
required, exists:companies,company_key |
Llave única de la empresa emisora. Los datos del emisor (nombre, identificación, dirección, etc.) se obtienen automáticamente de la empresa vinculada a esta llave. |
👤 Receptor
Datos del cliente receptor de la factura. Si la identificación coincide con un cliente existente del emisor, los datos se pre-llenan automáticamente.
Nota: Para Tiquetes Electrónicos (document_type: "04"), el receptor es opcional. Si se envía, se busca o crea el cliente normalmente. Si no se envía, el documento se genera sin receptor. Para los demás tipos de documento, el receptor es obligatorio.
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
receptor |
object |
⚡ Condicional |
required (excepto tiquetes 04) |
Objeto con los datos del receptor. Obligatorio para tipos 01, 02, 03, 08, 09. Opcional para tiquetes (04). |
receptor.full_name |
string |
✅ Sí |
required, max:100 |
Nombre completo del receptor. |
receptor.identification |
string |
✅ Sí |
required, max:12 |
Número de identificación del receptor. Se valida longitud según tipo: Física=9, Jurídica=10, DIMEX=11-12, NITE=10. |
receptor.identification_type_id |
integer |
⚡ Condicional |
nullable, exists:identifications,id |
ID del tipo de identificación. Puede enviarse el ID o el código. |
receptor.identification_type_code |
string |
⚡ Condicional |
required_without:receptor.identification_type_id, exists:identifications,code |
Código del tipo de identificación (ej: "01" = Física, "02" = Jurídica, "03" = DIMEX, "04" = NITE). Se convierte automáticamente a ID. |
receptor.commercial_name |
string |
❌ No |
nullable, max:80 |
Nombre comercial del receptor. |
receptor.email |
string |
❌ No |
nullable, email, max:160 |
Correo electrónico del receptor. |
receptor.phone.number |
string |
❌ No |
nullable |
Número de teléfono del receptor. |
receptor.phone.country_code |
string |
❌ No |
nullable, max:3 |
Código de país del teléfono (ej: "506"). |
receptor.address |
string |
❌ No |
nullable, max:250 |
Dirección del receptor. |
receptor.provincia_id |
integer |
❌ No |
nullable, exists:locations,id |
ID de la provincia (se puede enviar ID o código). |
receptor.canton_id |
integer |
❌ No |
nullable, exists:locations,id |
ID del cantón. Se valida que pertenezca a la provincia. |
receptor.distrito_id |
integer |
❌ No |
nullable, exists:locations,id |
ID del distrito. Se valida que pertenezca al cantón. |
receptor.barrio_id |
integer |
❌ No |
nullable, exists:locations,id |
ID del barrio. Se valida que pertenezca al distrito. |
receptor.f_identification |
string |
⚡ Condicional |
nullable, max:20, requerido si DIMEX |
Identificación extranjera. Obligatorio cuando el tipo de identificación es DIMEX (3). |
receptor.primary_activity |
string |
❌ No |
nullable, size:6 |
Código de actividad económica primaria del receptor (6 caracteres exactos). |
Ubicación por códigos (alternativa a IDs): También se pueden enviar receptor.provincia_code, receptor.canton_code, receptor.distrito_code y receptor.barrio_code en lugar de los IDs. El sistema los convierte automáticamente de forma jerárquica.
📊 Resumen de Factura
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
resumen_factura |
object |
✅ Sí |
required, array |
Objeto con la información general de la factura. |
resumen_factura.currency_id |
integer |
⚡ Condicional |
nullable, exists:currencies,id |
ID de la moneda. Puede enviarse el ID o el código. |
resumen_factura.currency_code |
string |
⚡ Condicional |
required_without:resumen_factura.currency_id, exists:currencies,code |
Código de la moneda (ej: "CRC", "USD"). Se convierte automáticamente a ID. |
resumen_factura.rate |
numeric |
✅ Sí |
required, min:1 |
Tipo de cambio. Valor por defecto: 1. |
resumen_factura.payment_method_id |
integer |
⚡ Condicional |
nullable, exists:payment_methods,id |
ID del método de pago. |
resumen_factura.payment_method_code |
string |
⚡ Condicional |
required_without:resumen_factura.payment_method_id, exists:payment_methods,code |
Código del método de pago (ej: "01" = Efectivo, "02" = Tarjeta, etc.). Se convierte a ID. |
resumen_factura.payment_method_other |
string |
⚡ Condicional |
nullable, max:80, requerido si método="99" |
Descripción del método de pago cuando se selecciona "Otros" (código 99). |
resumen_factura.condition_id |
integer |
⚡ Condicional |
nullable, exists:conditions,id |
ID de la condición de venta. |
resumen_factura.condition_code |
string |
⚡ Condicional |
required_without:resumen_factura.condition_id, exists:conditions,code |
Código de la condición de venta (ej: "01" = Contado, "02" = Crédito). Se convierte a ID. |
resumen_factura.sale_condition_other |
string |
⚡ Condicional |
nullable, max:80, requerido si condición="99" |
Descripción cuando la condición de venta es "Otros" (código 99). |
resumen_factura.credit_term |
date |
⚡ Condicional |
nullable, requerido si condición="02" (Crédito) |
Fecha de plazo de crédito. Obligatorio cuando la condición de venta es "Crédito". |
📄 Metadatos del Documento
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
document_type |
string |
✅ Sí |
required, valores: 01, 02, 03, 04, 08, 09 |
Tipo de documento electrónico (ver tabla de tipos abajo). |
branch_type |
string |
✅ Sí |
required, valores: sucursal, principal |
Tipo de sucursal del emisor. |
activity_code |
string |
❌ No |
nullable, size:6 |
Código de actividad económica del emisor. |
client_activity_code |
string |
❌ No |
nullable, size:6 |
Código de actividad económica del cliente. |
cash_register_id |
integer |
❌ No |
nullable, exists:cash_registers,id |
ID de la caja registradora asociada. |
razon |
string |
✅ Sí |
required, max:180 |
Razón o motivo del documento. |
test_mode |
boolean |
❌ No |
nullable |
Si se genera en modo de prueba. Si no se envía, hereda la configuración de la empresa. |
Tipos de documento:
| Código |
Tipo |
01 |
Factura Electrónica |
02 |
Nota de Débito |
03 |
Nota de Crédito |
04 |
Tiquete Electrónico |
08 |
Factura de Compra |
09 |
Factura de Exportación |
🔗 Información de Referencia (Solo Notas de Crédito/Débito)
Estos campos son obligatorios cuando document_type es "02" (Nota Débito) o "03" (Nota Crédito).
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
reference_type |
string |
⚡ Requerido si tipo 02/03 |
max:2 |
Tipo de referencia del documento original. |
reference_type_other |
string |
⚡ Requerido si reference_type="99" |
max:80 |
Descripción cuando el tipo de referencia es "Otros". |
reference_doc |
string |
⚡ Requerido si tipo 02/03 |
max:50 |
Número o consecutivo del documento de referencia original. |
reference_date |
date |
⚡ Requerido si tipo 02/03 |
date |
Fecha del documento de referencia original. |
reference_code_id |
integer |
⚡ Requerido si tipo 02/03 |
exists:reference_codes,id |
ID del código de referencia. |
reference_code_other |
string |
⚡ Requerido si reference_code="99" |
max:80 |
Descripción cuando el código de referencia es "Otros". |
🛒 Detalles / Líneas del Documento
Array de productos o servicios que componen el documento.
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
detalles |
array |
✅ Sí |
required, min:1 |
Array de líneas de detalle. Debe tener al menos 1 elemento. |
detalles.*.name |
string |
✅ Sí |
required, max:200 |
Nombre del producto o servicio. |
detalles.*.code |
string |
✅ Sí |
required, max:13 |
Código CABYS del producto/servicio. |
detalles.*.internal_code |
string |
❌ No |
nullable, max:50 |
Código interno del producto en el sistema del emisor. |
detalles.*.type |
string |
✅ Sí |
required, valores: servicio, producto |
Tipo de ítem. |
detalles.*.quantity |
numeric |
✅ Sí |
required, min:0.00001 |
Cantidad del producto/servicio. |
detalles.*.price |
numeric |
✅ Sí |
required, min:0 |
Precio unitario. |
detalles.*.measurement |
object |
❌ No |
nullable, array |
Unidad de medida. |
detalles.*.measurement.code |
string |
❌ No |
nullable, max:10 |
Código de la unidad de medida (ej: "Unid", "Kg", "Km"). |
detalles.*.tariff_item |
string |
❌ No |
nullable, max:12 |
Partida arancelaria (para exportaciones). |
detalles.*.is_special_service |
boolean |
❌ No |
nullable, default: false |
Si es un servicio especial. |
Descuentos por línea:
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
detalles.*.base_discount |
numeric |
❌ No |
nullable, min:0, default: 0 |
Monto o porcentaje del descuento. |
detalles.*.discount_is_percentage |
boolean |
❌ No |
nullable, default: false |
Si true, base_discount es un porcentaje. Si false, es un monto fijo. |
detalles.*.discount_type |
object |
❌ No |
nullable, array |
Tipo de descuento. |
detalles.*.discount_type.code |
string |
❌ No |
nullable, max:2 |
Código del tipo de descuento. |
detalles.*.code_description |
string |
❌ No |
nullable, max:50 |
Descripción del código. |
detalles.*.discount_description |
string |
❌ No |
nullable, max:80 |
Descripción del descuento. |
Impuestos por línea:
| Campo |
Tipo |
Requerido |
Validación |
Descripción |
detalles.*.tax_code |
string |
❌ No |
nullable, max:2 |
Código del tipo de impuesto (ej: "01" = IVA). |
detalles.*.tax_fee |
object |
❌ No |
nullable, array |
Tarifa del impuesto. |
detalles.*.tax_fee.code |
string |
❌ No |
nullable, max:2 |
Código de la tarifa (ej: "08" = 13% general). |
detalles.*.tax_fee.fee |
numeric |
❌ No |
nullable, min:0, max:1 |
Porcentaje del impuesto como decimal (ej: 0.13 = 13%). |
detalles.*.tax_other |
string |
❌ No |
nullable, max:80 |
Descripción cuando el impuesto es "Otros". |
detalles.*.factor_iva |
numeric |
❌ No |
nullable, min:0, max:1, default: 0 |
Factor IVA para impuestos con código "08". |
detalles.*.activity_code |
string |
❌ No |
nullable, size:6 |
Código de actividad económica del detalle. |
detalles.*.commission |
numeric |
❌ No |
nullable, min:0, default: 0 |
Comisión aplicada a la línea. |
📤 Respuesta Exitosa (201)
{
"success": true,
"message": "Documento procesado exitosamente",
"data": {
"document_id": 123,
"consecutive": "00100001010000000001",
"key": "50601032600310...",
"status": "pending"
}
}
| Campo |
Tipo |
Descripción |
success |
boolean |
Siempre true en caso de éxito. |
message |
string |
Mensaje descriptivo del resultado. |
data.document_id |
integer |
ID del documento creado en la base de datos. |
data.consecutive |
string |
Número consecutivo asignado al documento. |
data.key |
string |
Clave numérica del documento electrónico (50 dígitos). |
data.status |
string |
Estado del documento. Usualmente "pending" mientras Hacienda procesa. |
⛔ Respuestas de Error
| Código HTTP |
Condición |
Estructura |
401 |
Token de autenticación no proporcionado o inválido |
{ "message": "Unauthenticated." } |
422 |
Campos de entrada no válidos |
{ "message": "...", "errors": { "campo": ["error"] } } |
422 |
company_key no encontrada |
{ "success": false, "message": "Compañía no encontrada", "errors": {...} } |
422 |
Error al procesar el documento |
{ "success": false, "message": "Error al procesar el documento: ...", "errors": {...} } |
📦 Ejemplo de Payload Completo
Factura Electrónica (tipo 01) - Usando IDs
{
"company_key": "mi-llave-empresa",
"document_type": "01",
"branch_type": "principal",
"test_mode": true,
"razon": "Venta de productos varios",
"receptor": {
"full_name": "Juan Pérez García",
"identification": "123456789",
"identification_type_id": 1,
"email": "juan@email.com",
"phone": {
"number": "88888888",
"country_code": "506"
},
"address": "San José, Costa Rica"
},
"resumen_factura": {
"currency_id": 55,
"rate": 1,
"payment_method_id": 1,
"condition_id": 1
},
"detalles": [
{
"name": "Producto de ejemplo",
"code": "1234567890123",
"internal_code": "PROD-001",
"type": "producto",
"quantity": 2,
"price": 5000,
"tax_code": "01",
"tax_fee": {
"code": "08",
"fee": 0.13
}
}
]
}
Tiquete Electrónico (tipo 04) - Usando Códigos
{
"company_key": "mi-llave-empresa",
"document_type": "04",
"branch_type": "principal",
"test_mode": true,
"razon": "Venta al detalle",
"receptor": {
"full_name": "Cliente Genérico",
"identification": "000000000",
"identification_type_code": "01"
},
"resumen_factura": {
"currency_code": "CRC",
"rate": 1,
"payment_method_code": "01",
"condition_code": "01"
},
"detalles": [
{
"name": "Servicio profesional",
"code": "9876543210987",
"type": "servicio",
"quantity": 1,
"price": 25000,
"tax_code": "01",
"tax_fee": {
"code": "08",
"fee": 0.13
}
}
]
}
Nota de Crédito (tipo 03) - Con Referencia
{
"company_key": "mi-llave-empresa",
"document_type": "03",
"branch_type": "principal",
"test_mode": true,
"razon": "Devolución de producto defectuoso",
"reference_type": "01",
"reference_doc": "00100001010000000001",
"reference_date": "2026-03-01",
"reference_code_id": 1,
"receptor": {
"full_name": "Juan Pérez García",
"identification": "123456789",
"identification_type_id": 1
},
"resumen_factura": {
"currency_id": 55,
"rate": 1,
"payment_method_id": 1,
"condition_id": 1
},
"detalles": [
{
"name": "Producto devuelto",
"code": "1234567890123",
"type": "producto",
"quantity": 1,
"price": 5000,
"tax_code": "01",
"tax_fee": {
"code": "08",
"fee": 0.13
}
}
]
}
Detalle con Descuento Porcentual
{
"name": "Producto con descuento",
"code": "1234567890123",
"type": "producto",
"quantity": 3,
"price": 10000,
"base_discount": 15,
"discount_is_percentage": true,
"discount_description": "Descuento por volumen",
"tax_code": "01",
"tax_fee": {
"code": "08",
"fee": 0.13
}
}
🗂 APIs Auxiliares de Consulta
Para enviar correctamente tu payload, probablemente necesites conocer los identificadores (id o code) de los distintos catálogos. Puedes consultar los siguientes endpoints auxiliares.
Autenticación: Todos los endpoints requieren el esquema Bearer Token (auth:sanctum).
Método HTTP: GET
| Endpoint |
Descripción |
Datos que proporciona |
/api/ciudades |
Catálogo de ubicaciones geográficas. |
Provincias, cantones, distritos y barrios de Costa Rica. |
/api/identificaciones |
Tipos de identificación. |
01 (Física), 02 (Jurídica), 03 (DIMEX), 04 (NITE). |
/api/monedas |
Monedas soportadas válidas. |
CRC (Colón costarricense), USD (Dólar estadounidense), etc. |
/api/metodos-de-pago |
Catálogo de métodos de pago. |
01 (Efectivo), 02 (Tarjeta), 03 (Cheque), 04 (Transferencia), 99 (Otros). |
/api/condiciones |
Catálogo de condiciones de venta. |
01 (Contado), 02 (Crédito), 03 (Consignación), 04 (Apartado), 05 (Arrendamiento con opción compra), 06 (Arrendamiento en función financiera). |
/api/codigos-referencia |
Códigos para referenciar documentos. |
Usados al crear notas de crédito/débito (Ej: 01 - Anula Documento de Referencia, 02 - Corrige texto documento de referencia, etc). |
/api/unidades-medida |
Unidades de medida estandarizadas. |
Ej: Unid, Sp, m, kg, g, L. |
/api/tipos-descuento |
Códigos de tipos de descuento aplicables. |
Naturaleza del descuento comercial. |
/api/impuestos |
Catálogo de tipos de impuestos. |
01 (Impuesto al Valor Agregado), 02 (Selectivo de Consumo), etc. |
/api/factores |
Códigos de tarifas de impuesto (factores IVA). |
Ej: 08 (13% general), 01 (Exento 0%), 02 (1%), 03 (2%), 04 (4%), 07 (8%). |