📄 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%).