Autenticación
Todas las peticiones se autentican con la API key de tu empresa. La clave identifica a la empresa: no hace falta enviar el nombre de la empresa en el cuerpo, y no es posible escribir datos de otra empresa con tu clave.
Cabeceras
Envía la clave en Authorization o, si tu sistema sólo admite cabeceras simples, en x-api-key. Las dos formas son equivalentes.
Authorization: Bearer fmk_a1b2c3d4e5f6...
Content-Type: application/json
# alternativa
x-api-key: fmk_a1b2c3d4e5f6...
Content-Type: application/jsonCuida la clave
La clave da acceso de escritura a los datos de tu empresa. Guárdala en el gestor de secretos de tu servidor, nunca en el navegador ni en una app móvil, y no la publiques en repositorios. Si se filtra, pide su revocación y una nueva clave.Cómo obtener la clave
Solicita tu API key al equipo de marcayliquida indicando el nombre de tu empresa. La clave se muestra una única vez al generarla: guárdala en ese momento, porque después sólo queda registrado su prefijo (por ejemplo fmk_a1b2c3d4) y ya no se puede recuperar. Puedes pedir varias claves (una por integración) y revocarlas de forma independiente.
Convenciones
Reglas comunes a los tres endpoints.
URL base
https://marcayliquida.com/api/v1Formato
- Todos los endpoints son
POSTcon cuerpo JSON yContent-Type: application/json. - Las fechas van en formato
YYYY-MM-DD(por ejemplo2026-08-05). - Los importes son números sin separadores de miles:
1300000, no"1.300.000". - Se rechazan los campos desconocidos con
422: así un nombre mal escrito no pasa desapercibido. Revisaerror.detallespara ver qué campo sobra. - Los campos opcionales aceptan
nullo cadena vacía; ambos se interpretan como "no enviado".
Respuesta correcta
Siempre incluye "ok": true. Los códigos son 201 cuando se creó algo y 200 cuando la petición se procesó sin crear registros nuevos (por ejemplo una actualización, un validar_solo o un lote con filas omitidas).
Respuesta de error
{
"ok": false,
"error": {
"codigo": "datos_invalidos",
"mensaje": "Los datos del trabajador no son válidos.",
"detalles": [
{ "campo": "salario_base", "mensaje": "El salario base debe ser mayor que cero." },
{ "campo": "fecha_ingreso", "mensaje": "Usa el formato YYYY-MM-DD, por ejemplo 2026-08-05." }
]
}
}Modo de prueba
Los tres endpoints aceptan "validar_solo": true: validan el cuerpo y responden lo que harían, sin escribir nada. Es la forma recomendada de probar una integración nueva.
Códigos de error
| codigo | HTTP | Significado |
|---|---|---|
| no_autenticado | 401 | No se envió la API key. |
| clave_invalida | 401 | La API key no existe, fue revocada o está inactiva. |
| json_invalido | 400 | El cuerpo no es JSON válido o falta el Content-Type. |
| datos_invalidos | 422 | Algún campo no cumple el formato. Revisa "detalles". |
| documento_duplicado | 409 | Ya existe un trabajador con ese documento. |
| nombre_duplicado | 409 | Ya existe un trabajador con ese nombre completo exacto. |
| limite_plan | 409 | El plan contratado no admite más trabajadores. |
| sede_no_encontrada | 422 | La sede enviada no existe en la empresa. |
| motivo_no_encontrado | 422 | El motivo de falta no existe o está inactivo. |
| conflicto_fechas | 409 | La falta se cruza con otra ya registrada del mismo trabajador. |
| trabajador_no_encontrado | 404 | Ningún trabajador de la empresa coincide con los identificadores. |
| lote_demasiado_grande | 422 | El lote supera el máximo de 200 trabajadores. |
| error_interno | 500 | Error inesperado. Reintenta; si persiste, contacta a soporte. |
1. Agregar un trabajador
Crea un trabajador con sus datos laborales y, si los tienes, los datos de nómina electrónica.
El trabajador queda sin foto
La API crea al trabajador sin foto biométrica (photo_status: "pendiente"). Para que pueda marcar con reconocimiento facial hay que capturarle el rostro una vez desde la cámara del panel; ese paso es el que registra la cara. Mientras no se haga, el trabajador existe, aparece en los listados y puede tener faltas, pero no marca asistencia.Ejemplo mínimo
Sólo cuatro campos son obligatorios:
curl -X POST https://marcayliquida.com/api/v1/trabajadores \
-H "Authorization: Bearer $MARCAYLIQUIDA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"numero_documento": "1098765432",
"primer_nombre": "Laura",
"primer_apellido": "Gómez",
"salario_base": 1600000
}'Respuesta 201
{
"ok": true,
"trabajador": {
"estado": "creado",
"id_trabajador": 481,
"info_id": 92,
"nombre_completo": "LAURA GÓMEZ",
"tipo_documento": "CC",
"numero_documento": "1098765432",
"cargo": null,
"sede_id": null,
"dias_dominicales": ["Domingo"],
"foto_pendiente": true,
"advertencias": [
"El trabajador queda sin foto biométrica: captúrala desde la cámara del panel para que pueda marcar por reconocimiento facial.",
"Sin cargo asignado: las horas no se valorizan hasta que el trabajador tenga un cargo con tarifas configuradas."
]
}
}Guarda id_trabajador: es el identificador que puedes usar después en /api/v1/faltas (aunque también sirve el número de documento).
Ejemplo completo
{
"tipo_documento": "CC",
"numero_documento": "1098765432",
"primer_nombre": "Laura",
"segundo_nombre": "Andrea",
"primer_apellido": "Gómez",
"segundo_apellido": "Ríos",
"cargo": "Operario",
"sede_nombre": "Planta Norte",
"salario_base": 1600000,
"valor_hora_ordinaria": 6667,
"fecha_ingreso": "2026-08-01",
"tipo_contrato": "INDEFINIDO",
"dias_dominicales": ["Domingo", "Sábado"],
"fecha_nacimiento": "1995-03-12",
"sexo": "F",
"email": "laura.gomez@empresa.com",
"celular": "3001234567",
"departamento_residencia": "Santander",
"municipio_residencia": "Bucaramanga",
"direccion_residencia": "Calle 45 # 12-30",
"departamento_trabajo": "Santander",
"municipio_trabajo": "Girón",
"periodicidad_pago": "MENSUAL",
"forma_pago": "TRANSFERENCIA",
"auxilio_transporte_aplica": true,
"salario_integral": false,
"alto_riesgo": false,
"subtipo_cotizante": "01",
"eps_codigo": "EPS037",
"afp_codigo": "230301",
"arl_codigo": "14-1",
"arl_nivel_riesgo": 3,
"caja_compensacion_codigo": "CCF23",
"fondo_cesantias_codigo": "230301",
"banco": "Bancolombia",
"tipo_cuenta": "AHORROS",
"numero_cuenta": "12345678901",
"estado": "ACTIVO",
"actualizar_si_existe": false
}Identificación
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| numero_documentoobligatorio | string | — | Número de documento. Letras, números, puntos y guiones (3 a 20 caracteres). Identifica al trabajador en el resto de la API. |
| primer_nombreobligatorio | string | — | Primer nombre. |
| primer_apellidoobligatorio | string | — | Primer apellido. |
| tipo_documento | enum | "CC" | CC, CE, PA, PEP, PPT, TI, RC o NIT. |
| segundo_nombre | string | — | Segundo nombre. |
| segundo_apellido | string | — | Segundo apellido. |
Datos laborales
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| salario_baseobligatorio | number | — | Salario base mensual en pesos. Debe ser mayor que cero. |
| cargo | string | — | Cargo del trabajador. Es el que conecta con las tarifas de Configuración de horas: si el cargo no tiene tarifas, las horas no se valorizan (se avisa en "advertencias"). |
| valor_hora_ordinaria | number | — | Valor de la hora ordinaria, si se liquida por hora en lugar de por cargo. |
| fecha_ingreso | date | hoy | Fecha de ingreso a la empresa. |
| tipo_contrato | enum | "INDEFINIDO" | INDEFINIDO, FIJO, OBRA_LABOR, APRENDIZAJE_LECTIVA, APRENDIZAJE_PRODUCTIVA, PRACTICANTE_SENA o PRESTACION_SERVICIOS. |
| dias_dominicales | string[] | ["Domingo"] | Días con recargo dominical (75 % en Colombia). Se aceptan con o sin tilde: "Sabado" o "Sábado". Envía [] si no aplica ninguno. |
| sede_id | number | — | Id de una sede de la empresa. Excluyente con sede_nombre. |
| sede_nombre | string | — | Nombre de la sede, tal como está registrada en el panel (sin distinguir mayúsculas). Útil cuando tu sistema no conoce los ids. |
| estado | enum | "ACTIVO" | ACTIVO, SUSPENDIDO, LICENCIA o RETIRADO. |
| fecha_retiro | date | — | Fecha de retiro. No puede ser anterior a fecha_ingreso. |
| motivo_retiro | string | — | Motivo del retiro. |
Datos personales y ubicación
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| fecha_nacimiento | date | — | Fecha de nacimiento. |
| sexo | enum | — | M, F o X. |
| string | — | Correo del trabajador. | |
| celular | string | — | Celular de contacto. |
| pais_residencia | string(2) | "CO" | Código ISO del país de residencia. |
| departamento_residencia | string | — | Departamento de residencia. |
| municipio_residencia | string | — | Municipio de residencia. |
| direccion_residencia | string | — | Dirección de residencia. |
| departamento_trabajo | string | — | Departamento donde labora (obligatorio para nómina electrónica). |
| municipio_trabajo | string | — | Municipio donde labora (obligatorio para nómina electrónica). |
| direccion_trabajo | string | — | Dirección del lugar de trabajo. |
Nómina, seguridad social y banco
Son opcionales para crear el trabajador, pero la nómina electrónica los exige: si los tienes en tu sistema, mándalos y te ahorras completarlos a mano en el panel.
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| periodicidad_pago | enum | "MENSUAL" | SEMANAL, DECADAL, QUINCENAL o MENSUAL. |
| forma_pago | enum | "TRANSFERENCIA" | EFECTIVO, TRANSFERENCIA o CHEQUE. |
| salario_integral | boolean | false | Marca si el salario es integral. |
| auxilio_transporte_aplica | boolean | true | Si el trabajador tiene derecho a auxilio de transporte. |
| alto_riesgo | boolean | false | Actividad de alto riesgo para pensión. |
| subtipo_cotizante | string | — | Subtipo de cotizante PILA (01, 02, 12, 19, 30, 31, 51, 58…). |
| eps_codigo | string | — | Código de la EPS. |
| afp_codigo | string | — | Código del fondo de pensiones. |
| arl_codigo | string | — | Código de la ARL. |
| arl_nivel_riesgo | number | — | Nivel de riesgo ARL, entero de 1 a 5. |
| caja_compensacion_codigo | string | — | Código de la caja de compensación. |
| fondo_cesantias_codigo | string | — | Código del fondo de cesantías. |
| banco | string | — | Banco donde se consigna el pago. |
| tipo_cuenta | enum | — | AHORROS o CORRIENTE. |
| numero_cuenta | string | — | Número de cuenta bancaria. |
Opciones
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| actualizar_si_existe | boolean | false | Si el trabajador ya existe (mismo tipo y número de documento en la empresa), actualiza sus datos en lugar de responder 409. La foto biométrica ya capturada no se toca. |
| validar_solo | boolean | false | Valida el cuerpo y responde sin crear nada. |
Errores frecuentes
documento_duplicado(409): ya hay un trabajador con ese documento. Reenvía con"actualizar_si_existe": truesi quieres actualizarlo.nombre_duplicado(409): otro trabajador tiene exactamente el mismo nombre completo. Agrega el segundo nombre o el segundo apellido para diferenciarlos.limite_plan(409): el plan contratado no admite más trabajadores.sede_no_encontrada(422): la sede debe existir antes; créala en el panel, en Información de la empresa.
2. Agregar varios trabajadores
Carga masiva: hasta 200 trabajadores por petición, con reporte fila por fila.
Cada elemento de trabajadores acepta los mismos campos que POST /api/v1/trabajadores. Las filas se procesan en orden y la respuesta trae un indice que apunta a la posición en el arreglo que enviaste, para que puedas casar cada resultado con tu propia fuente de datos.
Cuerpo de la petición
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| trabajadoresobligatorio | objeto[] | — | Lista de trabajadores. Cada elemento admite exactamente los mismos campos del endpoint individual. Entre 1 y 200 por petición. |
| modo | enum | "parcial" | "parcial" crea todo lo que pueda y reporta fila por fila. "estricto" exige que las 200 filas sean correctas: si una falla, no queda ninguna creada. |
| actualizar_si_existe | boolean | false | Aplica a todas las filas: actualiza los trabajadores que ya existan. |
| validar_solo | boolean | false | Valida las filas y responde el conteo de válidas e inválidas, sin escribir. |
Ejemplo
curl -X POST https://marcayliquida.com/api/v1/trabajadores/lote \
-H "Authorization: Bearer $MARCAYLIQUIDA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"modo": "parcial",
"actualizar_si_existe": false,
"trabajadores": [
{
"numero_documento": "1098765432",
"primer_nombre": "Laura",
"primer_apellido": "Gómez",
"cargo": "Operario",
"salario_base": 1600000,
"sede_nombre": "Planta Norte"
},
{
"numero_documento": "1102233445",
"primer_nombre": "Carlos",
"segundo_nombre": "Andrés",
"primer_apellido": "Peña",
"cargo": "Supervisor",
"salario_base": 2400000,
"dias_dominicales": ["Domingo", "Sábado"]
}
]
}'Respuesta
201 si todas las filas se crearon; 200 si hubo errores, actualizaciones u omisiones. Revisa siempre resumen.errores: en modo parcial una respuesta 200 puede traer filas fallidas.
{
"ok": true,
"resumen": { "total": 3, "creados": 2, "actualizados": 0, "errores": 1 },
"resultados": [
{
"indice": 0,
"estado": "creado",
"id_trabajador": 481,
"info_id": 92,
"nombre_completo": "LAURA GÓMEZ",
"tipo_documento": "CC",
"numero_documento": "1098765432",
"cargo": "Operario",
"sede_id": 3,
"dias_dominicales": ["Domingo"],
"foto_pendiente": true,
"advertencias": ["El trabajador queda sin foto biométrica: …"]
},
{
"indice": 1,
"estado": "creado",
"id_trabajador": 482,
"info_id": 93,
"nombre_completo": "CARLOS ANDRÉS PEÑA",
"tipo_documento": "CC",
"numero_documento": "1102233445",
"cargo": "Supervisor",
"sede_id": null,
"dias_dominicales": ["Domingo", "Sábado"],
"foto_pendiente": true,
"advertencias": []
},
{
"indice": 2,
"estado": "error",
"numero_documento": "900",
"codigo": "datos_invalidos",
"mensaje": "Los datos del trabajador no son válidos.",
"detalles": [
{ "campo": "salario_base", "mensaje": "El salario base debe ser mayor que cero." }
]
}
]
}Modos de procesamiento
parcial(por defecto): las filas correctas se crean y las que fallan se reportan con sucodigoymensaje. Útil para cargas grandes donde prefieres avanzar y corregir después.estricto: todo o nada. Si alguna fila viene mal formada, responde422sin escribir nada; si una escritura falla a mitad de camino, se deshacen las altas de esa misma petición. Útil para sincronizar contra tu sistema de nómina sin dejar estados intermedios.
Documentos repetidos en el mismo lote
Si dos filas traen el mismo tipo y número de documento, la primera se procesa y las siguientes se reportan condocumento_duplicado indicando la posición del duplicado. El límite del plan se valida antes de escribir, contando sólo los documentos que aún no existen en la empresa.3. Registrar un motivo de falta por rango de fechas
Justifica la ausencia de uno o varios trabajadores desde una fecha hasta otra: incapacidades, vacaciones, licencias o permisos.
Una falta cubre el rango completo [fecha_inicio, fecha_fin], ambos días incluidos: no hace falta enviar un registro por día. En el panel, los días cubiertos pasan de Sin justificar a Justificada.
A quién se aplica
Envía una de estas cuatro formas de identificación. Si combinas varias, se unen sin duplicar trabajadores.
| Campo | Tipo | Descripción |
|---|---|---|
| documento | string | Número de documento del trabajador. La forma más común. |
| documentos | string[] | Varios documentos: aplica la misma falta y el mismo rango a todos (hasta 200). |
| id_trabajador | number | Id devuelto al crear el trabajador (campo id_trabajador). |
| id_trabajadores | number[] | Varios ids. |
Datos de la falta
| Campo | Tipo | Por defecto | Descripción |
|---|---|---|---|
| motivo | string | — | Código del motivo, por ejemplo INCAPACIDAD_EPS. No distingue mayúsculas. Obligatorio si no envías tipo_falta_id. |
| tipo_falta_id | number | — | Alternativa a motivo: el id del tipo de falta. |
| fecha_inicioobligatorio | date | — | Primer día de la ausencia. |
| fecha_fin | date | fecha_inicio | Último día de la ausencia, incluido. Si se omite, la falta cubre un solo día. Máximo 366 días de rango. |
| observaciones | string | — | Nota libre (hasta 1000 caracteres): número de incapacidad, quién autorizó, etc. |
| en_conflicto | enum | "error" | "error" falla si ya hay una falta que se cruza; "omitir" deja la existente intacta; "reemplazar" borra las faltas cruzadas (y sus comprobantes) y crea la nueva. |
| validar_solo | boolean | false | Valida y responde a quién se aplicaría, sin registrar nada. |
Ejemplo: incapacidad de un trabajador
curl -X POST https://marcayliquida.com/api/v1/faltas \
-H "Authorization: Bearer $MARCAYLIQUIDA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"documento": "1098765432",
"motivo": "INCAPACIDAD_EPS",
"fecha_inicio": "2026-08-10",
"fecha_fin": "2026-08-15",
"observaciones": "Incapacidad 4471 - Sanitas"
}'{
"ok": true,
"motivo": {
"id": 1,
"codigo": "INCAPACIDAD_EPS",
"nombre": "Incapacidad EPS",
"remunerada": true,
"requiere_soporte": true
},
"periodo": { "fecha_inicio": "2026-08-10", "fecha_fin": "2026-08-15", "dias": 6 },
"resumen": {
"total": 1,
"creadas": 1,
"reemplazadas": 0,
"omitidas": 0,
"errores": 0,
"no_encontrados": 0
},
"resultados": [
{
"estado": "creada",
"id_trabajador": 481,
"nombre": "LAURA GÓMEZ",
"documento": "1098765432",
"falta_id": 55
}
],
"advertencias": [
"El motivo \"Incapacidad EPS\" requiere comprobante: súbelo desde Faltas en el panel para que la ausencia quede soportada."
]
}Ejemplo: vacaciones colectivas de varios trabajadores
{
"documentos": ["1098765432", "1102233445", "1103344556"],
"motivo": "VACACIONES",
"fecha_inicio": "2026-12-20",
"fecha_fin": "2027-01-05",
"observaciones": "Cierre de fin de año",
"en_conflicto": "omitir"
}Con varios trabajadores la respuesta trae una entrada por persona en resultados, con su estado (creada, reemplazada, omitida o error). Los documentos que no existen en la empresa no rompen la petición: se listan en advertencias y se cuentan en resumen.no_encontrados. Si ninguno de los identificadores corresponde a un trabajador de la empresa, la respuesta es 404.
Cruces de fechas
Un trabajador no puede tener dos faltas que se crucen. Cuando el rango que envías se solapa con una falta existente, en_conflicto decide el comportamiento:
error(por defecto): responde409 conflicto_fechasindicando los rangos que estorban. Nada se modifica.omitir: respeta la falta existente y marca a esa persona comoomitida. Es lo recomendable en procesos que se reejecutan (idempotencia).reemplazar: borra las faltas cruzadas junto con sus comprobantes y crea la nueva. Devuelve los ids borrados enfaltas_reemplazadas.
reemplazar borra comprobantes
Los archivos de soporte de las faltas reemplazadas se eliminan del almacenamiento y no se pueden recuperar. Úsalo sólo cuando tu sistema sea la fuente de verdad de las ausencias.Motivos disponibles
Envía el codigo tal cual aparece en esta tabla. Si tu empresa tiene motivos propios configurados en el panel, también funcionan con su código.
| Código (motivo) | Nombre | Remunerada | Requiere comprobante |
|---|---|---|---|
| AUSENCIA_INJUSTIFICADA | Ausencia injustificada | No | No |
| CALAMIDAD_DOMESTICA | Calamidad doméstica | Sí | No |
| INCAPACIDAD_ARL | Incapacidad ARL | Sí | Sí |
| INCAPACIDAD_EPS | Incapacidad EPS | Sí | Sí |
| LICENCIA_LUTO | Licencia por luto | Sí | Sí |
| LICENCIA_MATERNIDAD | Licencia de maternidad | Sí | Sí |
| LICENCIA_PATERNIDAD | Licencia de paternidad | Sí | Sí |
| PERMISO_NO_REMUNERADO | Permiso no remunerado | No | No |
| PERMISO_REMUNERADO | Permiso remunerado | Sí | No |
| SUSPENSION | Suspensión | No | Sí |
| VACACIONES | Vacaciones | Sí | No |
Comprobantes
Los motivos conrequiere_soporte necesitan un archivo de respaldo (incapacidad, licencia…). La API registra la falta, pero el comprobante se sube desde la sección Faltas del panel: mientras no exista, la falta aparece marcada como sin soporte.Ejemplos de integración
Dos formas típicas de llamar la API desde tu servidor.
Node.js
const API = 'https://marcayliquida.com/api/v1';
const CLAVE = process.env.MARCAYLIQUIDA_API_KEY;
async function llamar(ruta, cuerpo) {
const respuesta = await fetch(API + ruta, {
method: 'POST',
headers: {
Authorization: `Bearer ${CLAVE}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(cuerpo),
});
const datos = await respuesta.json();
if (!respuesta.ok) {
// datos.error.codigo es estable; datos.error.detalles dice qué campo falló.
throw new Error(`${datos.error.codigo}: ${datos.error.mensaje}`);
}
return datos;
}
// Alta de un trabajador
const { trabajador } = await llamar('/trabajadores', {
numero_documento: '1098765432',
primer_nombre: 'Laura',
primer_apellido: 'Gómez',
cargo: 'Operario',
salario_base: 1600000,
});
// Vacaciones de ese trabajador
await llamar('/faltas', {
id_trabajador: trabajador.id_trabajador,
motivo: 'VACACIONES',
fecha_inicio: '2026-12-20',
fecha_fin: '2027-01-05',
en_conflicto: 'omitir',
});Python
import os
import requests
API = "https://marcayliquida.com/api/v1"
CABECERAS = {
"Authorization": f"Bearer {os.environ['MARCAYLIQUIDA_API_KEY']}",
"Content-Type": "application/json",
}
def llamar(ruta: str, cuerpo: dict) -> dict:
respuesta = requests.post(API + ruta, json=cuerpo, headers=CABECERAS, timeout=30)
datos = respuesta.json()
if not respuesta.ok:
error = datos["error"]
raise RuntimeError(f"{error['codigo']}: {error['mensaje']}")
return datos
# Carga masiva desde tu nómina, en bloques de 200
def cargar(trabajadores: list[dict]) -> None:
for inicio in range(0, len(trabajadores), 200):
bloque = trabajadores[inicio : inicio + 200]
datos = llamar(
"/trabajadores/lote",
{"trabajadores": bloque, "modo": "parcial", "actualizar_si_existe": True},
)
for fila in datos["resultados"]:
if fila["estado"] == "error":
print(inicio + fila["indice"], fila["codigo"], fila["mensaje"])Recomendaciones
- Prueba primero con
"validar_solo": truey revisa la respuesta antes de escribir datos reales. - Para procesos que se reejecutan (sincronizaciones nocturnas), usa
"actualizar_si_existe": trueen trabajadores y"en_conflicto": "omitir"en faltas: así repetir la petición no duplica ni rompe nada. - Guarda el
id_trabajadorque devuelve la API junto al identificador de tu sistema: simplifica las llamadas posteriores. - Ante un
500o un corte de red, reintenta con espera progresiva; los errores4xxno se resuelven reintentando, hay que corregir el cuerpo.
Soporte
¿Necesitas una clave, un motivo de falta propio o un endpoint que no está aquí? Escríbenos desde la página de contacto indicando el nombre de tu empresa y lo que quieres automatizar.