Electronic Payroll DIAN

Issue Payroll Support Documents (NominaIndividual, TipoXML=102) and Adjustment Notes (NominaIndividualDeAjuste, TipoXML=103) per DIAN Resolution 000013/2021. Your system sends all data in one POST and the API generates XML, calculates CUNE (SHA-384), signs with XAdES-BES, zips and transmits to DIAN.

🔑 Company and environment by API Key: The endpoint derives the company and environment (production/sandbox) from the X-Api-Key header. DO NOT send id_empresa or ambiente in the body — they are redundant, ignored, and a security risk (a client with a test API Key should not be able to issue on behalf of another company).

⚠️ Important: The API does NOT require pre-existing employees, contracts or periods. Your payroll system sends all data in one POST and the API handles everything.

POST /v1/api/nomina/enviar

Generates XML, calculates CUNE (SHA-384), signs with XAdES-BES, zips, transmits to DIAN and persists. Returns CUNE, trackId, QR URL and DIAN response.

Body Parameters

FieldTypeRequiredDescription
transmitbooleanNotrue=send to DIAN. false=only generate XML/CUNE (default: true)
empleadoobjectYesEmployee data (see empleado sub-table)
periodoobjectYesPay period (see periodo sub-table)
devengadosarrayYesEarned lines (see devengados sub-table)
deduccionesarrayNoDeduction lines (see deducciones sub-table)
totalesobjectNoAuto-calculated from devengados/deducciones if omitted
notasarray<string>NoFree notes (NIE031)
novedadbooleanNoMark contractual novelty (default: false)
cune_novstringNoCUNE of previous document (required if novedad=true)
prefijostringNoConsecutive prefix (default: "NOM")
fecha_genstringNoYYYY-MM-DD (default: today)
hora_genstringNoHH:MM:SS-05:00 (default: current Colombia time)
periodo_nominastringNo1=Regular, 2=Extraordinary (default: 1)
tipo_monedastringNoCOP by default
trmnumberNoExchange rate (only if tipo_moneda != COP)
lugar_generacionobjectNoOverride { pais, departamento, municipio, idioma } — defaults to empresa
empleadorobjectNoEmployer override — defaults to empresa
pagoobjectNoPayment method info
fechas_pagosarray<string>NoPayment dates (YYYY-MM-DD)
redondeonumberNoRounding cents
novedadesarrayNoPeriod novelties
sancionesarrayNoDisciplinary sanctions

empleado

FieldTypeRequiredDescription
tipo_documentostringNo13=CC, 22=CE, 41=Passport (default: 13)
numero_documentostringYesEmployee document number
primer_nombrestringYesFirst name
otros_nombresstringNoMiddle names (if applicable)
primer_apellidostringYesFirst surname
segundo_apellidostringNoSecond surname
tipo_trabajadorstringNoDIAN 5.5.3: 01=Employee, 02=Independent, 09=Apprentice (default: 01)
sub_tipo_trabajadorstringNoDIAN 5.5.4: 00=None, 01=Rural, 02=Urban (default: 00)
alto_riesgo_pensionbooleanNoDecree 2090/2003
codigo_trabajadorstringNoInternal employee code
tipo_contratostringNoDIAN 5.5.2: 1=Fixed, 2=Indef, 3=Work, 4=Apprentice, 5=Services (default: 2)
lugar_trabajo_paisstringNoISO 3166-1 alpha-2 (default: CO)
lugar_trabajo_departamentostringNoDANE department code
lugar_trabajo_municipiostringNoDANE municipality code
lugar_trabajo_direccionstringNoWorkplace address

periodo

FieldTypeRequiredDescription
fecha_ingresostringNoYYYY-MM-DD
fecha_retirostringNoYYYY-MM-DD (opcional)
fecha_liquidacion_iniciostringYesYYYY-MM-DD
fecha_liquidacion_finstringYesYYYY-MM-DD
tiempo_laborado_diasintegerYesDays worked (>= 1)

devengados[]

FieldTypeRequiredDescription
seccionstringYesBASIC, TRANSPORT, HED, HEN, HRD, HRN, SND, VACATIONS, BONUSES, etc.
descripcionstringNoFree description
dias_trabajadosintegerNoOnly for BASICO
sueldo_trabajadonumberNoOnly for BASICO (if valor_total is omitted)
auxilio_transportenumberNoOnly for TRANSPORT (if valor_total is omitted)
valor_totalnumberNoTotal earned value. If omitted, uses sueldo_trabajado or auxilio_transporte

deducciones[]

FieldTypeRequiredDescription
seccionstringYesHEALTH, PENSION, SINDICATE, SANCTION, LOAN, TAX_WITHHOLDING, etc.
descripcionstringNoFree description
porcentajenumberNoPercentage (e.g. 4 for health)
base_calculonumberNoCalculation base (IBC)
valor_totalnumberYesTotal deduction value

Example

JSON
{
  "transmit": true,
  "empleado": {
    "tipo_documento": "13",
    "numero_documento": "1234567890",
    "primer_nombre": "JUAN",
    "otros_nombres": "CARLOS",
    "primer_apellido": "PEREZ",
    "segundo_apellido": "GOMEZ",
    "tipo_trabajador": "01",
    "sub_tipo_trabajador": "00",
    "alto_riesgo_pension": false,
    "lugar_trabajo_pais": "CO",
    "lugar_trabajo_departamento": "76",
    "lugar_trabajo_municipio": "76001",
    "lugar_trabajo_direccion": "Calle 1 #2-3",
    "tipo_contrato": "2"
  },
  "periodo": {
    "fecha_ingreso": "2026-01-15",
    "fecha_liquidacion_inicio": "2026-07-01",
    "fecha_liquidacion_fin": "2026-07-31",
    "tiempo_laborado_dias": 30
  },
  "devengados": [
    {
      "seccion": "BASICO",
      "dias_trabajados": 30,
      "sueldo_trabajado": 1300000,
      "valor_total": 1300000,
      "descripcion": "Salario basico julio"
    },
    {
      "seccion": "TRANSPORTE",
      "auxilio_transporte": 162000,
      "valor_total": 162000,
      "descripcion": "Auxilio de transporte"
    }
  ],
  "deducciones": [
    {
      "seccion": "SALUD",
      "porcentaje": 4,
      "base_calculo": 1300000,
      "valor_total": 52000,
      "descripcion": "Aporte salud EPS"
    },
    {
      "seccion": "FONDO_PENSION",
      "porcentaje": 4,
      "base_calculo": 1300000,
      "valor_total": 52000,
      "descripcion": "Aporte pension AFP"
    }
  ],
  "notas": [
    "Liquidacion de julio 2026"
  ]
}

Code Examples

CURL
curl -X POST https://api.jcflow.com.co/v1/api/nomina/enviar \
  -H "X-Api-Key: sk_test_tu_api_key_aqui" \
  -H "Content-Type: application/json" \
  -d '{"transmit":true,"empleado":{"tipo_documento":"13","numero_documento":"1234567890","primer_nombre":"JUAN","otros_nombres":"CARLOS","primer_apellido":"PEREZ","segundo_apellido":"GOMEZ","tipo_trabajador":"01","sub_tipo_trabajador":"00","alto_riesgo_pension":false,"lugar_trabajo_pais":"CO","lugar_trabajo_departamento":"76","lugar_trabajo_municipio":"76001","lugar_trabajo_direccion":"Calle 1 #2-3","tipo_contrato":"2"},"periodo":{"fecha_ingreso":"2026-01-15","fecha_liquidacion_inicio":"2026-07-01","fecha_liquidacion_fin":"2026-07-31","tiempo_laborado_dias":30},"devengados":[{"seccion":"BASICO","dias_trabajados":30,"sueldo_trabajado":1300000,"valor_total":1300000,"descripcion":"Salario basico julio"},{"seccion":"TRANSPORTE","auxilio_transporte":162000,"valor_total":162000,"descripcion":"Auxilio de transporte"}],"deducciones":[{"seccion":"SALUD","porcentaje":4,"base_calculo":1300000,"valor_total":52000,"descripcion":"Aporte salud EPS"},{"seccion":"FONDO_PENSION","porcentaje":4,"base_calculo":1300000,"valor_total":52000,"descripcion":"Aporte pension AFP"}],"notas":["Liquidacion de julio 2026"]}'

Success Response

JSON
{
  "success": true,
  "message": "Nómina Electrónica procesada exitosamente",
  "data": {
    "id": 1,
    "cune": "A1B2C3D4E5F6...",
    "cune_scheme": "CUNE-SHA384",
    "qr_url": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=A1B2C3D4...",
    "trackId": "uuid-track-id",
    "transmission": {
      "isValid": true,
      "statusCode": "00",
      "statusDescription": "Procesado Correctamente",
      "errors": []
    },
    "totales": { "devengados": 1462000, "deducciones": 104000, "comprobante": 1358000 },
    "ambiente": 2,
    "xml": "<NominaIndividual>...</NominaIndividual>"
  }
}

POST /v1/api/nomina/ajuste

Creates an Adjustment Note (NominaIndividualDeAjuste, TipoXML=103) that REPLACES or DELETES a previous payroll referenced by CUNE. The API looks up the original by CUNE (not by id) and generates the adjustment XML.

FieldTypeRequiredDescription
cune_referenciastringYesCUNE of original payroll to replace/delete
empleadoobjectYesEmployee data
tipo_notaintegerNo1=Replace, 2=Delete (DIAN 5.5.8, default: 1)
numero_referenciastringNoOriginal payroll number (default: stored consecutivo)
fecha_referenciastringNoYYYY-MM-DD (default: stored fecha_gen)
transmitbooleanNotrue=send to DIAN (default: true)
prefijostringNoConsecutive prefix (default: "NOM")
fecha_genstringNoYYYY-MM-DD (default: today)
hora_genstringNoHH:MM:SS-05:00 (default: current Colombia time)
periodo_nominastringNo1=Regular, 2=Extraordinary (default: uses original)
lugar_generacionobjectNoGeneration location override
empleadorobjectNoEmployer override
periodoobjectNoPay period (default: uses original)
devengadosarrayNoCorrected earned lines (default: empty)
deduccionesarrayNoCorrected deduction lines (default: empty)
totalesobjectNoTotals (default: zeros)
notasarray<string>NoFree notes

GET /v1/api/nomina/estado/:trackId

Queries the current payroll status via DIAN GetStatus and updates it in the DB. trackId is in the URL; id_empresa is not sent.

No parameterstrackId is the final URL segment.

GET /v1/api/nomina/listar

Lists the company payrolls with pagination and optional filters. The company is determined by the API Key.

FieldTypeRequiredDescription
pageintegerNoPage (default 1)
limitintegerNoItems per page (default 20)
tipostringNoINDIVIDUAL | AJUSTE
estadostringNoenviada | aceptada | rechazada | error | borrador
fecha_desdestringNoYYYY-MM-DD
fecha_hastastringNoYYYY-MM-DD

GET /v1/api/nomina/:id

Returns the detail of a specific payroll, including earned and deduction lines.

GET /v1/api/nomina/:id/xml

Downloads the signed payroll XML (text/xml).

GET /v1/api/nomina/:id/zip

Downloads the ZIP containing the signed XML (application/zip).

💡 Tip: In the sandbox environment (Habilitación), DIAN accepts any correctly calculated CUNE. You can use an sk_test_ API Key without a real digital certificate during development.