← Documentación / Guías
Convenciones de la API
Estructura de las solicitudes, ámbitos de autenticación, consultas de listados, importes monetarios, errores, idempotencia y límites de frecuencia.
Estructura de las solicitudes
Cada operación es una petición POST de estilo RPC:
POST /v1/{module}/{resource}/{action}
Módulos: reference, partners, catalog, sales, purchases, ledger, bank, declarations, files, webhooks, audit. Las acciones son verbos: create, get, update, delete, list, además de acciones de dominio como issue, register, match, apply-advance, generate.
Autenticación y ámbitos
Authorization: Bearer <api key>. Las claves incorporan ámbitos (scopes) que se comprueban en cada acción:
{module}:read- acciones de lectura y listado{module}:write- modificaciones{module}:*o*- comodines
Si falta el ámbito, se devuelve un error 403 forbidden. Si la clave no es válida o no se proporciona, se devuelve un error 401 unauthorized.
Consultas de listados
Todas las acciones de tipo list comparten un contrato común:
{
"page": 1,
"pageSize": 50,
"sort": [{ "field": "createdAt", "dir": "desc" }],
"filter": [{ "field": "paymentStatus", "op": "eq", "value": "unpaid" }]
}
Operadores de filtrado: eq (igual a), ne (distinto de), contains (coincidencia de texto sin distinguir mayúsculas y minúsculas, solo para campos de texto), gte (mayor o igual que), lte (menor o igual que), in (cualquiera de los valores de una lista de hasta 500 elementos). Los campos en los que se puede ordenar y filtrar están predefinidos en una lista blanca para cada extremo (endpoint) (consulte la especificación OpenAPI); los campos desconocidos devuelven un error 400. Añada totals: ["field", …] a la solicitud para sumar campos numéricos de todas las filas coincidentes; cuando los registros tienen una divisa asociada, totalsByCurrency proporciona las mismas sumas desglosadas por código de divisa. Respuestas: { rows, total, page, pageSize, totals?, totalsByCurrency? }.
Importes monetarios y fechas
Los valores monetarios son cadenas de texto decimales con un máximo de 4 decimales ("121.0000") y nunca números de coma flotante (floats). El IVA se calcula línea por línea aplicando el redondeo al alza a la mitad (half-up). Las fechas tienen el formato YYYY-MM-DD y las marcas de tiempo (timestamps) siguen el estándar ISO 8601 en UTC.
Errores
Se utiliza una estructura unificada en todas partes:
{
"error": {
"code": "validation",
"message": "Request validation failed",
"requestId": "k1x…",
"key": "request_invalid",
"fieldErrors": { "lines.0.unitPriceExclVat": ["Invalid value"] }
}
}
Códigos: validation (400/422, y 413 cuando un archivo subido o el cuerpo de la solicitud es demasiado grande), unauthorized (401), payment_required (402, el periodo de prueba o el saldo prepago ha finalizado; el mensaje indica cómo continuar), forbidden (403), not_found (404), conflict (409), idempotency_key_reuse (422), idempotency_in_progress (409), rate_limited (429), internal (5xx). Cuando el mensaje es uno de los mensajes fijos, la propiedad key lo identifica para que el cliente pueda mostrar su propia traducción, y params contiene los valores necesarios para completarlo (por ejemplo, { "period": "2026-09" } para un periodo contable cerrado). Incluya el identificador requestId al informar de incidencias.
Idempotencia
Añada la cabecera Idempotency-Key: <any string ≤255 chars> a cualquier llamada que modifique datos:
- Reintentar con la misma clave y carga útil (payload): se vuelve a reproducir la respuesta almacenada byte a byte con la cabecera
x-idempotent-replay: true. - Misma clave, carga útil diferente: error 422
idempotency_key_reuse. - Duplicado simultáneo mientras la primera solicitud está en curso: error 409
idempotency_in_progress. - Las claves pertenecen a la clave de API o al usuario que las envía, dentro de la empresa para la cual actúa la llamada, de modo que dos integraciones de una misma empresa pueden utilizar la misma clave. Las llamadas realizadas antes de que exista una empresa y las llamadas a
account/*mantienen las claves por usuario, por lo que una llamada repetida aaccount/companies/createcreará una sola empresa. - La respuesta almacenada solo se devuelve una vez que el emisor supera de nuevo las comprobaciones de permisos pertinentes (ámbito, rol, empresa y estado de facturación); de lo contrario, la llamada recibe el error actual.
- Las claves caducan transcurridas 24 horas. Las respuestas de error (4xx) también se reproducen; las respuestas 5xx no se almacenan, por lo que los reintentos vuelven a ejecutar la operación.
Límites de frecuencia
300 solicitudes por minuto por clave de API (según las credenciales presentadas; las solicitudes sin autenticar se limitan por dirección IP). Ante un error 429, respete la cabecera retry-after. Las cabeceras x-ratelimit-* informan sobre su cupo disponible.
Webhooks
Los eventos se escriben en una bandeja de salida transaccional (transactional outbox) dentro de la misma transacción de base de datos que el cambio; un documento revertido nunca emite un evento y ningún evento se pierde. Entregas:
- Una solicitud
POSTa su URL con el evento en formato JSON x-nordlet-timestamp: <unix seconds>, la hora en que se firmó la entregax-nordlet-signature-v2: t=<timestamp>,v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>">utilizando su secreto de suscripciónx-nordlet-signature: sha256=<hex HMAC-SHA256 of the raw body>, que se mantiene sin cambios para los receptores existentesx-nordlet-deliverycontiene el identificador de entrega, el cual se mantiene idéntico en cada reintento de una misma entrega- Una respuesta que no sea de tipo 2xx o una redirección se reintenta transcurridos 30 segundos, 2 minutos, 10 minutos, 30 minutos, 1 hora, 3 horas, 6 horas y 12 horas (aproximadamente 24 horas en total) antes de que la entrega se marque como fallida
- Cada entrega es enviada por un único servidor a la vez, por lo que ejecutar varias instancias de la API no provocará envíos duplicados
Verifique la cabecera x-nordlet-signature-v2 mediante una comparación de tiempo constante antes de confiar en la carga útil, y rechace cualquier entrega cuya marca de tiempo difiera en más de 5 minutos de su reloj interno. La marca de tiempo forma parte del texto firmado, por lo que una entrega interceptada no se puede reproducir más tarde con una marca de tiempo reciente. Almacene los identificadores de x-nordlet-delivery que ya haya procesado para ignorar duplicados dentro de esa ventana temporal. Una entrega fallida se puede volver a enviar mediante webhooks/deliveries/redeliver.
Auditoría
Cada modificación queda registrada (actor, action, entity, diff) y se puede consultar a través de audit/list.
Garantías contables
- Los asientos en el libro diario están siempre cuadrados; esto se aplica mediante un disparador de base de datos diferido (deferred database trigger) en el momento de la confirmación (commit), no solo mediante el código de la aplicación.
- Los números de documento son secuenciales sin saltos por serie y año; la asignación es segura frente a la concurrencia.
- Los periodos contables cerrados rechazan cualquier asiento fechado en su interior (error 409).
- Los documentos eliminados de forma lógica (soft-deleted) conservan su pista de auditoría; los documentos emitidos o registrados no se pueden eliminar.