API Reference v2.5.0

Documentación de la API de Wardian

Integra facturación electrónica, inventarios y más. Todas las peticiones se autentican con una API Key.

  • Base URL: //qa.wardian.com.co/dist/api/
  • Formato: JSON
  • Autenticación: header X-API-Key

Autenticación

Envía tu API Key en el header X-API-Key en cada petición. Si falta o es inválida, la API responde 401 Unauthorized.

X-API-Key: wrd_tu_api_key_aqui

1 Generar tu API Key

En tu panel, ve a Software → Documentación → API Keys y presiona Generar API Key. Cópiala y guárdala; solo se muestra completa al crearla.

Ir a generar mi API Key

2 Primer request

Toda petición lleva el header X-API-Key. Para POST, envía el cuerpo en JSON con Content-Type: application/json. Las respuestas son JSON.

GET (listar)
const res = await fetch("//qa.wardian.com.co/dist/api/products/data_list.php", {
  headers: { "X-API-Key": "wrd_tu_api_key_aqui" }
});
const data = await res.json();
POST (crear)
const res = await fetch("//qa.wardian.com.co/dist/api/third/create.php", {
  method: "POST",
  headers: {
    "X-API-Key": "wrd_tu_api_key_aqui",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ /* campos del endpoint */ })
});
const data = await res.json();

Códigos de error

CódigoSignificado
200OK
400Petición inválida (faltan datos)
401API Key inválida o ausente
404Recurso no encontrado
500Error interno

Relaciones (catálogos)

Varios campos de productos, terceros y de la factura estándar no son valores libres: referencian catálogos (IDs de la DIAN / DANE). Obtén los valores válidos antes de crear.

GET//qa.wardian.com.co/dist/api/references/tables.php?table={catalogo}

Catálogos globales (datos de referencia, públicos). Usa table=all para traerlos todos.

Campo que lo usatable=Descripción
unit_measure_idunidadesUnidades de medida DIAN
standard_code_idcodigos_estandarCódigos estándar de adopción
tribute_idtributosTributos (IVA, INC, etc.)
identification_document_iddocumentos_identidadTipos de documento (CC, NIT…)
municipalities_codemunicipiosMunicipios (DANE)
country_codepaisesPaíses
responsabilidades_iva, regimen_iva, autorretenciones, bancosOtros catálogos disponibles
GET (público, sin API Key)
const res = await fetch("//qa.wardian.com.co/dist/api/references/tables.php?table=unidades");
const data = await res.json();
Response
{
  "success": true,
  "data": [
    { "id": 70, "code": "94", "name": "unidad" }
  ]
}

Catálogos con endpoint propio (requieren X-API-Key)

CampoEndpointNotas
categoria_idapi/settings/categories/list.phpCategorías del usuario
numbering_range_idapi/numbering_ranges/list.phpResoluciones / rangos de numeración
payment_method_codeapi/pos/list_payment_methods.phpMétodos de pago DIAN
tax_rateValor directo: 0, 5, 8, 19
La factura estándar (api/invoice/generate.php) usa estas mismas relaciones en su customer (identification_document_id, tribute_id, municipalities_code) y en cada ítem (unit_measure_id, standard_code_id, tax_rate), más numbering_range_id y payment_method_code.

Productos

Campos como unit_measure_id, standard_code_id, tax_rate, categoria_id y tribute_id referencian catálogos. Consulta Relaciones / Catálogos para obtener los valores válidos. Son las mismas relaciones que usa la factura estándar.
GET//qa.wardian.com.co/dist/api/products/data_list.php

Lista los productos del usuario dueño de la API Key. Acepta paginación: ?pagina=1&search=texto.

Response
{
  "success": true,
  "data": [
    { "id": 123, "code_reference": "SKU-001", "name": "Camiseta", "price": "50000.00", "tax_rate": "19.00" }
  ]
}
POST//qa.wardian.com.co/dist/api/products/create.php

Crea un producto. Se envía como multipart/form-data (permite imágenes en files[]).

CampoDescripción
typereqTipo de producto
code_referencereqCódigo / referencia único
namereqNombre del producto
pricereqPrecio de venta
unit_measure_idreqUnidad de medida (id DIAN)
standard_code_idreqCódigo estándar (id)
tax_rate, cost_price, wholesale_priceopcImpuesto, costo, precio mayorista
categoria_id, details, requiere_stock, stockopcCategoría, detalles, control de stock
contenido_presentacion, lote, fecha_vencimiento, cums_codigoopcPresentación, lote, vencimiento, CUMS
files[]opcImágenes del producto
Request (JSON)
{
  "type": "Producto",
  "code_reference": "SKU-001",
  "name": "Camiseta",
  "price": "50000",
  "unit_measure_id": "70",
  "standard_code_id": "1",
  "tax_rate": "19",
  "categoria_id": "5"
}
Response
{
  "status": "success",
  "message": "Producto registrado exitosamente",
  "data": { "producto_id": 123, "code_reference": "SKU-001", "name": "Camiseta" }
}
Para adjuntar imágenes usa multipart/form-data (campo files[]) en vez de JSON.
POST//qa.wardian.com.co/dist/api/products/edit.php

Edita un producto existente. Mismos campos que crear, más:

CampoDescripción
idreqID del producto a editar
Request (JSON)
{ "id": "123", "name": "Camiseta Premium", "price": "60000" }
Response
{ "status": "success", "message": "Producto actualizado exitosamente" }

Terceros

GET//qa.wardian.com.co/dist/api/third/data_list.php

Lista los terceros (clientes/proveedores) del usuario. Acepta ?pagina=1&search=texto.

Response
{
  "success": true,
  "data": [
    { "id": 45, "identification": "901234567", "company_name": "ACME SAS", "email": "info@acme.co" }
  ]
}
POST//qa.wardian.com.co/dist/api/third/create.php

Crea un tercero.

CampoDescripción
typeSelectorreqTipo (Persona / Empresa)
identification_document_idreqTipo de documento (id DIAN)
identificationreqNúmero de identificación
address, email, phonereqDirección, correo, teléfono
tribute_idreqResponsabilidad tributaria (id)
dv, company_name, name, last_name, trade_nameopcDV, razón social, nombres, nombre comercial
ciiu, country_code, municipalities_codeopcCIIU, país, municipio (DANE)
Request (JSON)
{
  "typeSelector": "Empresa",
  "identification_document_id": "31",
  "identification": "901234567",
  "email": "info@acme.co",
  "phone": "3001234567",
  "address": "Calle 1 # 2-3",
  "tribute_id": "21"
}
Response
{
  "status": "success",
  "message": "Tercero creado exitosamente",
  "data": { "tercero_id": 45, "name": "ACME SAS", "identification": "901234567", "email": "info@acme.co", "phone": "3001234567" }
}
POST//qa.wardian.com.co/dist/api/third/edit.php

Edita un tercero. Mismos campos que crear, más:

CampoDescripción
tercero_idreqID del tercero a editar
Request (JSON)
{ "tercero_id": "45", "email": "nuevo@acme.co", "phone": "3009999999" }
Response
{ "status": "success", "message": "Tercero actualizado exitosamente" }

Categorías

GET//qa.wardian.com.co/dist/api/settings/categories/list.php

Lista las categorías de productos del usuario.

Response
{
  "success": true,
  "data": [
    { "id": 5, "nombre": "Ropa", "descripcion": "Prendas de vestir", "color": "#CFFF00", "activo": 1 }
  ]
}
POST//qa.wardian.com.co/dist/api/settings/categories/create.php

Crea una categoría de productos.

CampoDescripción
nombrereqNombre de la categoría
descripcion, color, icono, activoopcDescripción, color, ícono, estado
configuracion_puc_activa, cuenta_ingreso_venta, cuenta_costo_venta, cuenta_inventario, cuenta_compraopcCuentas contables PUC (si se activa la config)
Request (JSON)
{ "nombre": "Ropa", "descripcion": "Prendas de vestir", "color": "#CFFF00", "activo": "1" }
Response
{
  "status": "success",
  "message": "Categoría creada exitosamente",
  "data": { "categoria_id": 5, "nombre": "Ropa", "descripcion": "Prendas de vestir", "color": "#CFFF00" }
}
POST//qa.wardian.com.co/dist/api/settings/categories/edit.php

Edita una categoría. Mismos campos que crear, más:

CampoDescripción
categoria_idreqID de la categoría a editar
Request (JSON)
{ "categoria_id": "5", "nombre": "Ropa y Calzado" }
Response
{ "status": "success", "message": "Categoría actualizada exitosamente" }

Crear factura estándar

Antes de facturar: crea/ten el tercero (obtienes su id) y los productos, y ten a mano el numbering_range_id (ver Catálogos). La factura se envía a la DIAN y responde con el número y el CUFE.
Requisito de la cuenta: tu cuenta (la dueña de la API Key) debe estar habilitada en la DIAN — con credenciales DIAN configuradas y un rango de numeración autorizado. Sin eso, la DIAN responde error. El entorno (pruebas/producción) lo determina la configuración DIAN de tu cuenta.
POST//qa.wardian.com.co/dist/api/invoice/generate.php

Genera una factura electrónica de venta estándar (multipart/form-data). Responde JSON con el resultado DIAN.

Cabecera

CampoDescripción
customerreqID del tercero (de api/third)
numbering_range_idreqRango de numeración / resolución
payment_formreq1 Contado · 2 Crédito
payment_method_codereqMétodo de pago (catálogo)
observationopcNota / observación
payment_due_dateopcFecha de vencimiento (si crédito)
companyopcNombre del emisor (para el correo/PDF)
reference_code, cuenta_bancaria_id, cost_center_idopcReferencia, cuenta bancaria, centro de costo
currency_code, currency_value, currency_dateopcMoneda (por defecto COP)

Ítems — products[]

CampoDescripción
idreqID del producto (de api/products)
code_reference, namereqCódigo y nombre del ítem
quantity, pricereqCantidad y precio unitario
tax_ratereq% IVA: 0, 5, 8, 19
unit_measure_id, standard_code_id, tribute_idreqCatálogos (ver Relaciones)
discount_rate, is_excludedopc% descuento, excluido de IVA (0/1)
ret_fuente_rate, ret_iva_rate, ret_ica_rateopcRetenciones (si el cliente retiene)

Ejemplo

Request (JSON)
{
  "customer": "45",
  "numbering_range_id": "502",
  "payment_form": "1",
  "payment_due_date": "2026-07-02",
  "payment_method_code": "10",
  "observation": "Gracias por su compra",
  "products": [
    {
      "id": "123",
      "code_reference": "SKU-001",
      "name": "Camiseta",
      "quantity": "2",
      "price": "50000",
      "tax_rate": "19",
      "unit_measure_id": "70",
      "standard_code_id": "1",
      "tribute_id": "1",
      "discount_rate": "0",
      "is_excluded": "0"
    }
  ]
}
Response
{
  "status": "success",
  "message": "Factura creada exitosamente",
  "data": {
    "invoice_id": 47014,
    "bill_number": "SETP990000227",
    "cufe": "7b4a382a9a751cc88156a47f2eac24c7987353d1...",
    "code_reference": "INV6a46c29683f15fdc6"
  }
}
Importante: envía payment_due_date (una fecha, aun en contado) y en cada ítem discount_rate e is_excluded con valor (ej. 0). La DIAN rechaza campos vacíos/nulos con "Datos de la factura incompletos".

Crear factura por mandato

La facturación por mandato (operation_type 11) permite facturar por cuenta de terceros mandantes. Es idéntica a la factura estándar, pero cada ítem indica el mandante por el que se factura. La DIAN responde con el número y el CUFE.
Requisito de la cuenta: igual que la factura estándar — tu cuenta debe estar habilitada en la DIAN (credenciales configuradas y rango de numeración autorizado).
POST//qa.wardian.com.co/dist/api/invoice/generate_mandate.php

Genera una factura electrónica de venta por mandato. Responde JSON con el resultado DIAN.

Cabecera

Mismos campos que la factura estándar (customer, numbering_range_id, payment_form, payment_method_code, observation, payment_due_date, company, moneda…). El operation_type se fija internamente en 11.

Ítems — products[]

Mismos campos que la factura estándar (id, code_reference, name, quantity, price, tax_rate, catálogos, retenciones…) más los datos del mandante por el que se factura ese ítem:

CampoDescripción
mandate_identificationreqIdentificación (NIT/CC) del tercero mandante. Si va vacío, el ítem se factura sin mandato.
mandate_identification_document_idreqTipo de documento del mandante (catálogo documentos_identidad)
mandate_dvopcDígito de verificación del mandante (si aplica)

Ejemplo

Request (JSON)
{
  "customer": "45",
  "numbering_range_id": "502",
  "payment_form": "1",
  "payment_due_date": "2026-07-02",
  "payment_method_code": "10",
  "observation": "Facturación por mandato",
  "products": [
    {
      "id": "123",
      "code_reference": "SKU-001",
      "name": "Canon de arrendamiento",
      "quantity": "1",
      "price": "1000000",
      "tax_rate": "0",
      "unit_measure_id": "70",
      "standard_code_id": "1",
      "tribute_id": "1",
      "discount_rate": "0",
      "is_excluded": "0",
      "mandate_identification": "901234567",
      "mandate_identification_document_id": "31",
      "mandate_dv": "8"
    }
  ]
}
Response
{
  "status": "success",
  "message": "Factura de mandato creada exitosamente",
  "data": {
    "invoice_id": 47021,
    "code_reference": "INV6a46c29683f15fdc6",
    "bill_number": "SETP990000228",
    "api_status": "Created",
    "cufe": "8c5b493b0b862dd99267b58a3fbd35d8098464e2...",
    "comprobante_id": 90312
  }
}
Importante: igual que la factura estándar, envía payment_due_date y en cada ítem discount_rate e is_excluded con valor. Para facturar por mandato, cada ítem debe incluir mandate_identification (y su mandate_identification_document_id) del mandante.

Crear tiquete POS

Emite un tiquete POS electrónico (documento Factura de Venta POS) a la DIAN. Mismo formato de request que la factura estándar; usa el rango de numeración POS de tu cuenta.
Requisito de la cuenta: tu cuenta debe estar habilitada en la DIAN y tener un rango activo de tipo Factura de Venta POS. Si no envías numbering_range_id, se detecta automáticamente el rango POS activo del titular.
POST//qa.wardian.com.co/dist/api/invoice/generate_pos.php

Genera un tiquete POS electrónico. Responde JSON con el resultado DIAN.

Cabecera

CampoDescripción
customerreqID del tercero (de api/third)
payment_formreq1 Contado · 2 Crédito
payment_method_codeopcMétodo de pago DIAN (por defecto 10)
numbering_range_idopcRango POS. Si se omite, se auto-detecta el rango Factura de Venta POS activo
observationopcNota (por defecto "Tiquete POS Electrónico")
payment_due_date, municipality_id, tip_amount, seller_idopcVencimiento, municipio, propina, vendedor

Ítems — products[]

CampoDescripción
idreqID del producto (de api/products)
code_reference, namereqCódigo y nombre del ítem
quantity, price, discount_ratereqCantidad, precio unitario, % descuento
tax_ratereq% IVA: 0, 5, 8, 19
unit_measure_id, standard_code_id, tribute_idreqCatálogos (ver Relaciones)
is_excluded, requiere_stock, withholding_tax_rateopcExcluido de IVA (0/1), control de stock, retención

Ejemplo

Request (JSON)
{
  "customer": "8",
  "payment_form": "1",
  "payment_method_code": "10",
  "observation": "Venta POS",
  "products": [
    {
      "id": "72707",
      "code_reference": "ENVIO-SHOPIFY",
      "name": "Envío - Estándar",
      "quantity": "1",
      "price": "4000",
      "tax_rate": "0",
      "discount_rate": "0",
      "unit_measure_id": "70",
      "standard_code_id": "1",
      "tribute_id": "22",
      "is_excluded": "0",
      "requiere_stock": "0"
    }
  ]
}
Response
{
  "status": "success",
  "message": "Factura POS creada exitosamente",
  "data": {
    "invoice_id": 47016,
    "bill_number": "EPOS71",
    "cufe": "20764680cd9bd7b8d62c72442e012887c912cfc8...",
    "api_status": "Created",
    "dian_response": { "bill": { "number": "EPOS71", "cufe": "2076...", "total": 4000, "id": "347619492" } }
  }
}
El endpoint descuenta inventario de los ítems con requiere_stock=1 dentro de la transacción. Envía numbering_range_id explícito si manejas varios rangos POS por sucursal.

Crear factura RIPS (salud)

Emite una factura electrónica RIPS (sector salud — Registro Individual de Prestación de Servicios de Salud). La factura DIAN incluye los datos de salud (pacientes, servicios, CUPS) del paquete RIPS previamente validado en la plataforma.
Requisitos de la cuenta: habilitación DIAN (credenciales configuradas y rango de numeración autorizado) y un paquete RIPS validado (rips_id) creado desde el módulo de RIPS. Los datos clínicos (paciente/servicios) se toman de ese paquete, no se envían en el request.
POST//qa.wardian.com.co/dist/api/invoice/generate_rips.php

Genera una factura electrónica RIPS. Responde JSON con el resultado DIAN.

Cabecera

CampoDescripción
rips_idreqID del paquete RIPS validado. De él se cargan pacientes y servicios de salud.
invoice_typereqDebe ser "rips"
customerreqID del tercero (pagador — normalmente la EPS/entidad)
numbering_range_idreqRango de numeración / resolución
payment_formreq1 Contado · 2 Crédito
payment_method_codereqMétodo de pago (catálogo)
payment_due_datereqFecha de vencimiento (una fecha, aun en contado)
companyreqNombre del emisor (requerido para la notificación por correo)
observationopcNota / observación
cuenta_bancaria_id, cost_center_id, monedaopcCuenta bancaria, centro de costo, divisa
Los ítems (products) y los datos clínicos (health_data) se derivan automáticamente del paquete rips_id. No es necesario enviarlos.

Ejemplo

Request (JSON)
{
  "rips_id": "30",
  "invoice_type": "rips",
  "customer": "8",
  "numbering_range_id": "100",
  "payment_form": "1",
  "payment_method_code": "10",
  "payment_due_date": "2026-07-02",
  "company": "NEXO CONTABLE",
  "observation": "Servicios de salud - paquete RIPS"
}
Response
{
  "status": "success",
  "message": "Factura creada exitosamente",
  "data": {
    "invoice_id": 47021,
    "code_reference": "INV6a46da95177b095bb",
    "bill_number": "SETP990000231",
    "api_status": "Created",
    "cufe": "ad3a694a73e1a211f585d259c329c160031dbe2f...",
    "dian_response": { "bill": { "number": "SETP990000231", "total": 7350000 } }
  }
}
Importante: (1) el rips_id debe estar en estado validado y pertenecer a tu cuenta; (2) la cuenta debe tener credenciales DIAN configuradas; (3) envía payment_due_date (la DIAN rechaza con "Datos de la factura incompletos" si falta) y company (requerido por la notificación por correo). Los ítems y datos clínicos salen del paquete RIPS.

El flujo FEV-RIPS

RIPS = Registro Individual de Prestación de Servicios de Salud. FEV-RIPS es la pareja del RIPS con la factura electrónica de venta (FEV) en salud.

El orden importa: primero existe el paquete RIPS en la plataforma (con su rips_id), después se factura. No hay un endpoint que reciba un RIPS crudo y lo facture en un solo paso.
1. POST api/rips_invoice/rips.php            → registra el RIPS  (paquete_id)
2. GET  api/rips_invoice/get_rips_for_invoice.php?rips_id=N   → arma datos de factura
3. POST api/invoice/generate_rips.php        → factura ante la DIAN (CUFE) + valida ante MinSalud (CUV)

CUV ≠ CUFE (el punto que más confunde)

  • CUFE — lo asigna la DIAN al timbrar la factura. Identifica la factura.
  • CUV — lo asigna MinSalud (MUV) al validar el RIPS. Identifica la validación.
El CUFE no es un campo del RIPS: viaja dentro del XML de la factura que acompaña al RIPS en la validación ante MinSalud. Dentro del RIPS, la factura se referencia por su número (campo raíz numFactura) — no por el CUFE.

Estados del paquete

estadoSignificado
pendienteValidó localmente; falta su factura. En producción los RIPS sin factura quedan aquí hasta facturarse.
validadoCUV real de MinSalud.
rechazadoEl MUV lo rechazó (ver mensaje_respuesta con resultadosValidacion).
errorFalló la llamada al validador.

Estructura del payload RIPS

Forma del payload que registras en Registrar paquete RIPS. Sigue la estructura oficial Res. 2275/2023. Es también lo que genera Wardian al facturar desde un evento clínico.

Raíz — sin factura vs. con factura

La raíz es excluyente: un paquete se reporta como nota sin factura o con factura, nunca ambos.

Sin factura (RS)
{
  "numDocumentoIdObligado": "900123456",
  "numFactura": null,
  "numNota": "00001234",
  "tipoNota": "RS",
  "usuarios": [ /* … */ ]
}
Con factura (tras la FEV)
{
  "numDocumentoIdObligado": "900123456",
  "numFactura": "SETP990000001",
  "numNota": null,
  "tipoNota": null,
  "usuarios": [ /* … */ ]
}
No armas el modo con factura a mano: se activa solo. Al pasar un cufe (o al facturar el paquete), la plataforma resuelve la FEV localmente y reescribe la raíz a numFactura = número de esa factura, con tipoNota/numNota = null. Para notas crédito/débito coexisten numFactura + tipoNota (NC/ND) + numNota.

Usuario

Cada entrada de usuarios[] es un paciente con sus servicios. Códigos de residencia según la guía oficial (país Colombia = 170).

{
  "consecutivo": 1,
  "tipoDocumentoIdentificacion": "CC",
  "numDocumentoIdentificacion": "1234567890",
  "fechaNacimiento": "1985-06-15",
  "codSexo": "M",
  "codPaisResidencia": "170",
  "codMunicipioResidencia": "11001",   // DANE — de pacientes.municipio_id (o el tercero)
  "codZonaTerritorialResidencia": "02", // 02 = urbana
  "incapacidad": "NO",                  // "SI" | "NO"
  "codPaisOrigen": "170",
  "tipoUsuario": "01",
  "servicios": { "consultas": [ … ], "procedimientos": [ … ] }
}
codMunicipioResidencia es null si el paciente no tiene municipio DANE cargado (columna pacientes.municipio_id, con respaldo al tercero enlazado). El validador oficial lo exige — cárgalo desde la ficha del paciente.

Servicios — consultas vs. procedimientos

Wardian clasifica cada servicio en su bloque oficial según el tipo de evento: Consulta/Controlconsultas[]; el resto (incl. Procedimiento, Urgencia) → procedimientos[]. Difieren en algunos campos:

consultas[]
{
  "codPrestador": "800100123456",
  "fechaInicioAtencion": "2024-02-20 10:30:00",
  "numAutorizacion": "0000000",
  "codConsulta": "890201",
  "modalidadGrupoServicioTecSal": "01",
  "grupoServicios": "01",
  "codServicio": 890,
  "finalidadTecnologiaSalud": "11",
  "causaMotivoAtencion": "38",
  "codDiagnosticoPrincipal": "I10",
  "codDiagnosticoRelacionado1": null,
  "codDiagnosticoRelacionado2": null,
  "codDiagnosticoRelacionado3": null,
  "tipoDiagnosticoPrincipal": "02",
  "tipoDocumentoIdentificacion": "CC",
  "numDocumentoIdentificacion": "1234567890",
  "vrServicio": 50000,
  "conceptoRecaudo": "05",
  "valorPagoModerador": 0,
  "numFEVPagoModerador": null,
  "consecutivo": 1
}
procedimientos[]
{
  "codPrestador": "800100123456",
  "fechaInicioAtencion": "2024-02-20 14:00:00",
  "idMIPRES": null,
  "numAutorizacion": "0000000",
  "codProcedimiento": "880201",
  "modalidadGrupoServicioTecSal": "01",
  "grupoServicios": "01",
  "codServicio": 890,
  "viaIngresoServicioSalud": "01",
  "finalidadTecnologiaSalud": "11",
  "codDiagnosticoPrincipal": "I10",
  "codDiagnosticoRelacionado": null,
  "codComplicacion": null,
  "tipoDocumentoIdentificacion": "CC",
  "numDocumentoIdentificacion": "1234567890",
  "vrServicio": 500000,
  "conceptoRecaudo": "05",
  "valorPagoModerador": 0,
  "numFEVPagoModerador": null,
  "consecutivo": 1
}
Al pasar a con factura, la plataforma sella numFEVPagoModerador = número de la FEV en todo ítem con valorPagoModerador > 0, en cualquiera de los bloques.
Placeholders y brechas conocidas: causaMotivoAtencion (38) y tipoDiagnosticoPrincipal (02) son valores por defecto hasta que se capture el dato clínico real (sobreescribibles por cuenta vía rips_configuracion). Los bloques urgencias, hospitalizacion, medicamentos, otrosServicios y recienNacidos aún no se generan (requieren datos que el modelo clínico no almacena).
Nombre de campo (verificado vs. Anexo Técnico Res. 2275): el concepto de pago moderador es conceptoRecaudo (campos C18/P17), presente en consultas y procedimientos. El Anexo no define tipoPagoModerador — es un alias del mismo concepto. Como el MUV (nivel 1) valida con esquema estricto y rechaza claves desconocidas, se emite únicamente conceptoRecaudo.

Registrar paquete RIPS

Registra un paquete RIPS armado por tu sistema y lo envía al validador. Devuelve el paquete_id (= rips_id) que usarás para facturar. Aquí no se crea FEV.
POST//qa.wardian.com.co/dist/api/rips_invoice/rips.php

Cuerpo

CampoDescripción
payloadreqEl JSON RIPS completo — ver Estructura del payload (numDocumentoIdObligado, usuarios[] con servicios.consultas/servicios.procedimientos, …).
usuario_id_ripsopcDueño del RIPS. Por defecto, quien envía. Un principal puede enviar por sus subusuarios.
cufeopcCUFE de una FEV ya emitida. Si se envía, el RIPS se convierte a modo con factura (la raíz numFactura toma el número de esa factura) y se valida así. El CUFE se resuelve localmente contra tus facturas; no se escribe dentro del RIPS.
Request (JSON)
{
  "usuario_id_rips": 29,
  "payload": {
    "numDocumentoIdObligado": "900123456",
    "numNota": "00001234",
    "tipoNota": "RS",
    "usuarios": [ { "...": "ver Estructura del payload" } ]
  }
}
Response
{
  "status": "ok",
  "cuv": "a1b2c3...",
  "paquete_id": 30,
  "usuario_id_rips": 29,
  "usuario_id_envio": 29
}
Un CUV que empieza con WARDIAN- es simulado (validador inalcanzable) y solo ocurre fuera de producción. La opción cufe requiere la estructura moderna usuarios[].

Datos para facturar

Arma, a partir de un paquete RIPS con CUV, los datos listos para crear la factura: ítems, datos de salud, rango de numeración sugerido y cliente (EPS) sugerido.
GET//qa.wardian.com.co/dist/api/rips_invoice/get_rips_for_invoice.php?rips_id={id}

Solo devuelve paquetes con cuv no vacío.

Response (extracto)
{
  "status": "success",
  "data": {
    "rips_id": 30,
    "rips_cuv": "a1b2c3...",
    "rips_cufe": null,
    "numbering_range_id": 100,
    "invoice_type": "rips",
    "health_data": { "provider_code": "...", "patient": { "...": "" } },
    "items": [ { "code_references": "890201", "name": "Consulta", "price": 50000 } ]
  },
  "suggested_customer": { "id": 8, "name": "EPS ..." }
}
rips_cufe (tomado del payload_fev) es null hasta que el RIPS se factura. Pasa data a Crear factura RIPS.

Revalidar / con factura

Reenvía un paquete al validador. Útil para reemplazar un CUV simulado por uno real, o para promover un RIPS sin factura a con factura una vez emitida su FEV.
POST//qa.wardian.com.co/dist/api/rips_invoice/regenerate.php

Cuerpo

CampoDescripción
rips_idreqID del paquete a revalidar.
cufeopcSi se envía, convierte el paquete a modo con factura (raíz numFactura = número de esa FEV, resuelta localmente) antes de reenviar. El payload convertido se persiste.
Request (JSON)
{ "rips_id": 30, "cufe": "ad3a694a73e1..." }
Response
{
  "status": "success",
  "message": "RIPS regenerado correctamente con CUV real",
  "cuv": "a1b2c3...",
  "estado": "validado",
  "is_simulated": false
}
404 si no existe una factura con ese CUFE en tu cuenta. Sin cufe, revalida el paquete tal cual (sin cambiar a con factura).

Crear documento soporte

El documento soporte se emite en compras a proveedores no obligados a facturar. Antes: ten el tercero/proveedor (su id), los ítems y el numbering_range_id del rango de documento soporte. Se envía a la DIAN y responde con el número y el CUDS.
Requisito de la cuenta: la cuenta dueña de la API Key debe estar habilitada en la DIAN, con credenciales y un rango de numeración de documento soporte autorizado.
POST//qa.wardian.com.co/dist/api/document_support/generate.php

Genera un documento soporte electrónico. Acepta application/x-www-form-urlencoded o multipart/form-data. Responde JSON con el resultado DIAN. El documento soporte no lleva IVA (compra a no obligado).

Cabecera

CampoDescripción
customerreqID del proveedor (tercero, de api/third)
numbering_range_idreqRango de numeración de documento soporte
payment_formreq1 Contado · 2 Crédito
payment_method_codereqMétodo de pago (catálogo)
issue_dateopcFecha de emisión (por defecto hoy)
payment_due_dateopcFecha de vencimiento (si crédito)
observationopcNota / observación
cuenta_bancaria_id, cuenta_cxp_codigo, cost_center_idopcCuenta bancaria (pago), CxP (crédito), centro de costo
save_draftopc1 = guardar como Borrador (no se envía a la DIAN)

Ítems — products[]

CampoDescripción
code_reference, namereqCódigo y nombre del ítem
quantity, pricereqCantidad y precio unitario
discount_ratereq% descuento (ej. 0)
unit_measure_id, standard_code_idreqCatálogos (ver Relaciones)
ret_fuente_rate, ret_ica_rate, withholding_config_idopcRetenciones (ReteFuente / ReteICA)

Ejemplo

Request (JSON)
{
  "customer": "48",
  "numbering_range_id": "100",
  "payment_form": "1",
  "payment_method_code": "47",
  "issue_date": "2026-07-14",
  "observation": "Compra a proveedor no obligado",
  "products": [
    {
      "code_reference": "SERV-01",
      "name": "Servicio de mantenimiento",
      "quantity": "1",
      "price": "500000",
      "discount_rate": "0",
      "unit_measure_id": "70",
      "standard_code_id": "1",
      "ret_fuente_rate": "4"
    }
  ]
}
Response (emitido)
{
  "status": "success",
  "success": true,
  "data": {
    "document_id": 618,
    "code_reference": "INV6a46c29683f15fdc6",
    "number": "DS-1",
    "cuds": "a1b2c3d4e5f6...",
    "api_status": "Created"
  }
}
Response (save_draft=1)
{
  "status": "success",
  "success": true,
  "message": "Borrador guardado",
  "data": { "document_id": 618, "estado": "Borrador" }
}
Con save_draft=1 el documento queda en Borrador (no va a la DIAN) para revisar/emitir después desde el panel. Un borrador se puede convertir en documento soporte emitido.

Qué es el RDA

El RDA (Resumen Digital de Atención) es un reporte distinto e independiente del RIPS. La Resolución 1888 de 2025 obliga a enviar, por cada atención, un documento HL7 FHIR R4 a la plataforma de interoperabilidad (IHCE) del Ministerio de Salud. Una misma atención puede deber ambos: RIPS y RDA.

El flujo

#PasoDónde
1Cargar las credenciales que emitió MinSalud (por prestador y por entorno)Ajustes → RDA (IHCE)
2Registrar el profesional con documento y registro RETHUSAjustes → Prestadores (es_profesional=1)
3Completar una atención clínica con diagnóstico CIE-10Historia clínica → Eventos
4Se construye el Bundle, se valida local y se envíaautomático si auto_enviar está activo, o POST manual
5IHCE devuelve el identificador del RDA, que se persisteHistoria clínica → RDA (IHCE)

Lo que hay que saber del contrato

AspectoValor
EstructuraBundle con type: "document". entry[0] debe ser la Composition, y solo puede haber una.
ReferenciasIds planos, sin # y sin fullUrl: "subject": {"reference": "CC-80189301"}. Personas usan TipoDoc-NumDoc; la IPS, su código de habilitación pelado.
Tipo de documentoComposition.type = LOINC 51845-6 (Outpatient Consult note) para el RDA ambulatorio.
SeccionesNueve obligatorias. Las que no tengan datos igual se envían, con emptyReason = nilknown.
Obligatorios en el BundleComposition, Patient, Practitioner y DocumentReference son 1..1. La Organization de la IPS es 0..1.
TransporteOAuth2 client_credentials contra Azure AD. Cada llamada lleva Authorization: Bearer, Ocp-Apim-Subscription-Key y Content-Type: application/fhir+json.
DuplicadosIHCE responde 409 si coinciden Encounter.subject + period + serviceProvider + participant. Wardian lo detecta localmente antes de enviar.
La URL base no es pública. MinSalud la emite junto con el client_id, el client_secret y la Ocp-Apim-Subscription-Key al asignar credenciales. Se solicitan por la Mesa de Servicios del micrositio IHCE.
Estado de las secciones. Hoy llevan datos reales Diagnósticos (11450-4, desde el CIE-10 del evento) y Pagadores (48768-6, si el paciente tiene código EAPB). Las otras siete viajan con emptyReason porque su perfil exige datos que el sistema aún no captura de forma codificada. El Bundle es estructuralmente válido en cualquier caso.
El CUPS del evento no tiene sección en el RDA ambulatorio. Procedimientos (47519-4) solo existe en los RDA de hospitalización y urgencias; en consulta externa el CUPS viaja en Encounter.serviceType.

Credenciales IHCE

Una credencial por tenant y por entorno: QA, preproducción y producción coexisten sin pisarse. Los secretos se guardan cifrados y nunca se devuelven completos — solo enmascarados.
POST//qa.wardian.com.co/dist/api/settings/rda_credenciales/save.php

Cuerpo

CampoDescripción
entornoreqqa | preproduccion | produccion
base_urlreqLa URL que emitió MinSalud. Debe ser https://.
tenant_idreqTenant de Azure AD contra el que se pide el token.
client_idreq
client_secretreqObligatorio al crear. Al editar, envíalo vacío para conservar el guardado.
subscription_keyreqEl Ocp-Apim-Subscription-Key. Mismo criterio que el secreto.
scopereqScope OAuth2, normalmente api://…/.default.
prestador_idopcIPS a la que pertenece la credencial, si el tenant opera varias.
auto_enviaropc0 por defecto. Con 1, cada atención completada dispara el envío.
op_enviar_ambulatorioopcRuta de la operación. Configurable porque el Manual documenta menos operaciones que la guía FHIR.
Request (JSON)
{
  "entorno": "qa",
  "base_url": "https://<la-que-emitio-minsalud>",
  "tenant_id": "00000000-0000-0000-0000-000000000000",
  "client_id": "<client-id>",
  "client_secret": "<client-secret>",
  "subscription_key": "<ocp-apim-subscription-key>",
  "scope": "api://rda/.default",
  "auto_enviar": 0
}
POST .../rda_credenciales/test.php con {"entorno":"qa"} pide un token real a Azure AD. Un success confirma tenant/client/secret/scope, pero no valida la subscription key ni la URL base: eso se prueba en el primer envío.
GET .../rda_credenciales/list.php devuelve las credenciales del tenant con los secretos enmascarados, y POST .../delete.php con {"id":N} elimina una.

Previsualizar Bundle

Construye y valida el Bundle de un evento sin enviarlo y sin crear registros. Útil para revisar la estructura antes de tener credenciales.
GET//qa.wardian.com.co/dist/api/clinical_history/rda/preview.php?evento_id=4242
Response (200)
{
  "evento_id": 4242,
  "entorno": "qa",
  "valido": true,
  "errores": [],
  "bundle": {
    "resourceType": "Bundle",
    "type": "document",
    "identifier": { "value": "…uuid…" },
    "entry": [
      { "resource": { "resourceType": "Composition", "id": "Composition-0" } },
      { "resource": { "resourceType": "Patient", "id": "CC-1000200300" } },
      { "resource": { "resourceType": "Practitioner", "id": "CC-79123456" } },
      { "resource": { "resourceType": "Organization", "id": "230010255201" } },
      { "resource": { "resourceType": "Location", "id": "230010255201-01" } },
      { "resource": { "resourceType": "Encounter", "id": "Encounter-0" } },
      { "resource": { "resourceType": "DocumentReference", "id": "DocumentReference-0" } },
      { "resource": { "resourceType": "Condition", "id": "Condition-0" } }
    ]
  }
}
Responde 422 con un mensaje legible cuando faltan datos estructurales: sin diagnóstico CIE-10 (el Encounter.diagnosis es 1..4), sin profesional registrado, o sin código de habilitación en la IPS.

Enviar RDA

Construye, valida, persiste y envía. Si la validación local falla, no se toca la red: el paquete queda en borrador con los errores.
POST//qa.wardian.com.co/dist/api/clinical_history/rda/send.php

Cuerpo

CampoDescripción
evento_idreqEvento clínico a reportar.
entornoopcqa por defecto.
forzaropcReenvía aunque el contenido sea idéntico a un envío ya aceptado.
confirmar_produccionopcObligatorio si entorno es produccion. Salvaguarda contra envíos accidentales.
Response (200 — aceptado)
{
  "estado": "aceptado",
  "paquete_id": 17,
  "http_code": 200,
  "rda_id": "RDA-000123",
  "mensaje": "RDA aceptado por IHCE.",
  "errores": []
}

Estados y códigos

EstadoHTTPSignificado
aceptado200IHCE devolvió el identificador del RDA.
duplicado200El encuentro ya se había reportado con el mismo contenido. No se reenvía.
enviado202Respondió 200 pero sin identificador reconocible.
borrador422No pasó la validación local. No se envió.
rechazado422IHCE devolvió 400. Los issue del OperationOutcome vienen en errores.
error502Fallo de red o HTTP inesperado. Reintentable.
dist/cron/rda_retry_pending.php reintenta solo error y enviado, con espera creciente (5/15/60/240 min) y techo de 5 intentos. Nunca reintenta rechazado ni borrador: son defectos de contenido y reintentarlos da el mismo 400.

Consultar envíos

GET//qa.wardian.com.co/dist/api/clinical_history/rda/list.php?estado=aceptado&entorno=qa

Devuelve los paquetes del tenant, el conteo por estado y un bloque aptitud con lo que falta para que los envíos pasen la validación de registros de MinSalud (EVOL, RETHUS, REPS, DIVIPOLA).

Response (200, recortado)
{
  "paquetes": [
    { "id": 17, "estado": "aceptado", "entorno": "qa", "rda_id": "RDA-000123",
      "fecha_evento": "2026-07-20", "diagnostico_codigo": "J00", "intentos": 1 }
  ],
  "por_estado": { "aceptado": 12, "rechazado": 1 },
  "aptitud": {
    "pacientes_total": 340,
    "pacientes_sin_fecha_nac": 0,
    "pacientes_sin_sexo_biologico": 12,
    "profesionales": 3,
    "ips_con_habilitacion": 1,
    "eventos_completados": 512,
    "eventos_sin_diagnostico": 4,
    "credenciales": { "qa": "lista", "preproduccion": "sin configurar", "produccion": "sin configurar" }
  }
}
list.php no devuelve el Bundle: es información clínica y pesa. Para el detalle completo (Bundle enviado, OperationOutcome y bitácora) usa GET .../rda/data.php?id=17.