Tareas — Alta, Actualización y Cancelación
Escribí tareas desde tus propios sistemas (CRM, call-center, IoT). Tres operaciones cubren todo el ciclo de escritura:
POSTcrea una tarea o un lote de hasta 50.PUTaplica una actualización parcial a una tarea existente.DELETEcancela una tarea.
Cada operación acepta un objeto único o un contenedor de lote { "items": [...] } (de 1 a 50 ítems) y devuelve un resultado por ítem: un ítem puede tener éxito mientras otro falla, así que el lote nunca es todo-o-nada una vez que pasa la validación de forma.
Todos los endpoints requieren un token JWT válido, una clave de API y el encabezado tenant. Consultá Autenticación. La compañía (ciaid) y el usuario que actúa se toman de tus credenciales, nunca del cuerpo de la solicitud.
Los IDs son strings opacos (BigInt); no los interpretes como números. Las marcas de tiempo se envían y devuelven sin zona horaria (p. ej., "2026-04-04T14:32:00"). No agregues Z ni apliques conversión a UTC. Todos los campos del request usan snake_case.
Los tres identificadores en cada respuesta
Toda escritura exitosa devuelve los tres identificadores que lleva una tarea:
| Campo | Tipo | Descripción |
|---|---|---|
serid | string | Identificador interno de la tarea (BigInt como string). |
service_number | string | Número de servicio, asignado por el sistema al crear. |
assistance_number | string | Número de asistencia (vincula tareas hijas con su tarea padre). |
El external_id que enviás no se devuelve en el ítem de resultado: es tu propia clave. Para actualizar o cancelar luego, podés identificar la tarea por serid, service_number o external_id (ver Identificar una tarea).
Clasificación — Motivo O prestación+causa+subcausa
Una tarea se clasifica por dos ejes paralelos. Para cada eje elegís uno de dos caminos:
| Eje | Camino A | Camino B |
|---|---|---|
| Producto | procedence + product | motive |
| Prestación | provision + origin_cause + origin_subcause | motive |
Cuando enviás motive, la prestación, causa y subcausa correspondientes se completan automáticamente con lo configurado en el motivo; no hace falta enviarlas. Si enviás tanto motive como una prestación/causa/subcausa explícitas, gana el motivo (sobreescribe a las demás).
coverage es siempre opcional.
Si ningún camino se cumple en un eje, el ítem falla con MOTIVE_OR_CLASSIFICATION_REQUIRED.
Los campos de catálogo y geográficos aceptan un id (string opaco) o un nombre. El sistema resuelve el nombre a su id (p. ej., el nombre de un motivo a su motivo, el nombre de un país a su país). Cuando un nombre no se puede resolver, el ítem falla (duro) o continúa con una advertencia, según el campo; ver Errores.
Crear tarea
/apidev/v1/tasksCrea una tarea en estado inicial SA (o ASI cuando se envía un bloque assignment). Un lote cuenta como una solicitud para el límite de solicitudes.
Cuerpo de la solicitud — campos de nivel raíz
| Campo | Tipo | Requerido | Máx | Descripción |
|---|---|---|---|---|
contact | string | Sí | 200 | Nombre de quien solicita la tarea. |
external_id | string | No | 200 | Tu propio identificador de la tarea. |
service_number | string | No | 40 | Número de servicio (string numérico). Omitir o 0 para autonumerar. |
assistance_number | string | No | 40 | Número de asistencia (string numérico). Un valor vincula esta tarea con una tarea padre. |
phone_mobile | string | No | 50 | Celular del contacto. |
phone | string | No | 50 | Teléfono fijo del contacto. |
priority | string | No | 200 | Id o valor de prioridad. Se resuelve contra la tabla de prioridades de la compañía; omitido → prioridad por defecto. |
detail | string | No | — | Detalle de texto libre del pedido. |
notes | string | No | — | Notas internas. |
scheduled_at | string | No | 40 | Fecha/hora programada (ISO sin zona horaria). |
scheduled_until | string | No | 40 | Fecha/hora programada hasta (ISO sin zona horaria). |
automate | boolean | No | — | Si la tarea es automatizada. |
pending_unconfirmed | boolean | No | — | Marcar como pendiente / sin confirmar. |
computes | boolean | No | — | Por defecto true. false → no consume cupo de cobertura. |
delay_minutes | string | No | 20 | Tolerancia de demora GPS, en minutos enteros. |
communication_medium | string | No | 200 | Plantilla de comunicación (id o nombre). No resuelve → advertencia. |
shift | string | No | 200 | Turno (id o nombre). No resuelve → advertencia. |
telephonist_email | string | No | 200 | Email del telefonista. Por defecto, el usuario de tus credenciales; no resuelve → falla dura. |
no_notify_mobile | boolean | No | — | Suprime la notificación al móvil (relevante sobre todo en la actualización). |
assignment_alert | string | No | 2000 | Texto de alerta de asignación guardado en la tarea. |
vehicle_types | string[] | No | 200 c/u | Tipos de móvil solicitados (ids o nombres). Uno inválido hace fallar el ítem. |
classification | object | Sí | — | Ver regla de clasificación y campos de clasificación. |
origin | object | Sí | — | Dirección del origen. country + department + street son obligatorios. Ver campos geográficos. |
destination | object | Condicional | — | Obligatorio u opcional según el producto (p. ej., productos de grúa / mudanza lo exigen). |
reserve | object | No | — | Reserva un recurso sin asignar. Ver campos de reserva. |
assignment | object | No | — | Asigna la tarea al crearla (estado ASI; notificación al móvil solo cuando notify_mobile es true). Ver campos de asignación. |
account | object | Sí | — | Cuenta del solicitante. Se auto-crea con la dirección del origen si no existe. Ver campos de cuenta. |
dynamic_fields | array | Condicional | — | Campos dinámicos OAV. Obligatorios cuando el producto tiene OAV obligatorios. Ver campos dinámicos. |
attachments | array | No | — | Adjuntos por URL — se guardan como un enlace externo (la URL se guarda tal cual para abrirla desde la web/app; no se descarga). Ver campos de adjunto. |
load | object | No | — | Datos de carga (peso, volumen, bultos, requisitos de manipulación). Gateado por el perfil de carga del producto. Ver load. |
Campos de classification
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
procedence | string | Condicional | Procedencia (id o nombre). Requerido con product salvo que se envíe motive. |
product | string | Condicional | Producto (id, línea o nombre). Requiere procedence. |
coverage | string | No | Cobertura (id o nombre). |
motive | string | Condicional | Motivo (id o nombre). Completa prestación/causa/subcausa automáticamente. |
provision | string | Condicional | Prestación (id o nombre). Requerido con las dos causas salvo que se envíe motive. |
origin_cause | string | Condicional | Causa de origen (id o nombre). |
origin_subcause | string | Condicional | Subcausa de origen (id o nombre). |
destination_cause | string | No | Causa de destino (id o nombre). |
destination_subcause | string | No | Subcausa de destino (id o nombre). |
Campos de origin / destination
origin y destination comparten la misma forma. Los campos geográficos y de lugar especial aceptan un id o un nombre.
| Campo | Tipo | Requerido (origin) | Descripción |
|---|---|---|---|
country | string | Sí | País (id o nombre). |
department | string | Sí | Departamento / provincia (id o nombre). |
city | string | No | Ciudad (id o nombre). |
zone | string | No | Zona (id o nombre). No resuelve → advertencia. |
street | string | Sí | Calle. Obligatoria en el origen (salvo que se herede de la cuenta). |
corner | string | No | Esquina. Máx 500. |
corner2 | string | No | Segunda esquina. Máx 500. |
door_number | string | No | Número de puerta (texto — admite "1234", "S/N", "12-A"). Máx 50. |
apartment | string | No | Apartamento. Máx 50. |
facing | string | No | Referencia de hacia dónde mira. Máx 200. |
special_place | string | No | Lugar especial (id o nombre). No resuelve → advertencia. |
lat | string | No | Latitud. 0 u omitida → resolución de geocoding. |
lng | string | No | Longitud. 0 u omitida → resolución de geocoding. |
Cuando lat/lng faltan o son 0, la tarea se ubica usando la infraestructura geográfica propia de la compañía (georreferencia de la cuenta → geocodificación de la dirección → centroide geográfico). Si nada resuelve, la tarea se crea sin coordenadas (no falla) y se devuelve una advertencia.
Campos de reserve
Reservar un recurso mantiene la tarea en estado SA (no la asigna).
| Campo | Tipo | Descripción |
|---|---|---|
personnel | string | Personal a reservar (id o nombre). No resuelve → advertencia. |
provider | string | Prestador a reservar (id o nombre). No resuelve → falla dura. |
mobile | string | Móvil a reservar (id o nombre). No resuelve → falla dura. |
user_email | string | Usuario a reservar. No resuelve → falla dura. |
notify_mobile | boolean | Notifica al móvil al reservar (por defecto: no). Si es true, se ejecuta el flujo de notificación de reserva. |
Campos de assignment
Asignar mueve la tarea al estado ASI y fija la fecha de asignación. Al móvil se le notifica solo cuando notify_mobile es true (por defecto no notifica). Asigná por móvil o por prestador (son alternativas).
| Campo | Tipo | Descripción |
|---|---|---|
assign_vehicle | string | Móvil a asignar (id o nombre). Resuelve la jornada laboral activa del conductor. No resuelve → falla dura. |
assign_driver | string | Conductor a asignar (id o nombre). No resuelve → falla dura. |
assign_provider | string | Prestador a asignar (id o nombre), como alternativa a un móvil. No resuelve → falla dura. |
assign_template | string | Plantilla de comunicación de la asignación. Por defecto, la plantilla del recurso; una plantilla que no pertenece al recurso → advertencia + se usa la por defecto. |
notify_mobile | boolean | Notifica al móvil al asignar (por defecto: no). |
Campos de account
La cuenta del solicitante es obligatoria. Si external_code no coincide con una cuenta existente y se envía name, la cuenta se auto-crea con la dirección del origen de la tarea.
| Campo | Tipo | Descripción |
|---|---|---|
external_code | string | Resuelve la cuenta por código externo. Máx 200. |
name | string | Nombre de la cuenta (usado al auto-crear). Máx 200. |
update_if_exists | boolean | Si es true, actualiza los campos no vacíos de la cuenta existente. |
document | string | Número de documento (clave de búsqueda). |
phone | string | Teléfono (clave de búsqueda). |
mobile | string | Celular (clave de búsqueda). |
email | string | Email (clave de búsqueda). |
notes | string | Notas de la cuenta. Máx 2000. |
address | object | Dirección de la cuenta. Sobreescribe la dirección heredada del origen. Subconjunto de origin: street, corner, door_number, country, department, city, lat, lng. |
dynamic_fields (OAV)
Los campos dinámicos (OAV) se definen por producto. Su obligatoriedad y tipo vienen de la definición OAV del producto:
- Si el producto tiene campos OAV obligatorios,
dynamic_fieldsdebe incluirlos con unvalueno vacío, o el ítem falla conOAV_REQUIRED_MISSING. - Cada
valuese valida contra el tipo del campo (número, sí/no, fecha, opción de lista). Un formato equivocado →OAV_TYPE_MISMATCH; un valor fuera de la lista permitida →OAV_LIST_VALUE_INVALID. - Un
labelque no coincide con ningún campo del producto se ignora con una advertencia (no hace fallar el ítem).
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
label | string | Sí | Etiqueta del campo. Se compara sin distinguir mayúsculas contra los nombres de los campos OAV del producto. |
value | string | No | Valor, tipado según el campo. Máx 4000. |
Campos de attachments
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | No | Nombre de archivo a mostrar. Máx 300. |
url | string | Sí | URL HTTPS que se guarda tal cual como un enlace externo (se abre desde la web/app; no se descarga). Máx 2000. |
notes | string | No | Notas del adjunto. Máx 2000. |
Cada adjunto se registra como un enlace externo. Si el enlace no se puede registrar, la tarea igual se crea y el adjunto se informa en warnings[].
load (datos de carga)
Datos de carga del envío de la tarea: peso, volumen, cantidad de bultos y requisitos especiales de manipulación. Cada campo está gateado por el perfil de carga del producto — cada producto declara qué dimensiones de carga maneja.
| Campo | Tipo | Descripción |
|---|---|---|
weightKg | number | Peso total en kilogramos (≥ 0). |
volumeM3 | number | Volumen total en metros cúbicos (≥ 0). |
packages | integer | Cantidad de bultos (≥ 0). |
requiresCold | boolean | Requiere manipulación refrigerada. |
requiresFragile | boolean | Contiene elementos frágiles. |
requiresHeavy | boolean | Requiere manipulación de carga pesada. |
Si enviás una dimensión de load que el producto no maneja, el ítem falla con LOAD_DIMENSION_NOT_SUPPORTED. Qué dimensiones maneja un producto es parte de su configuración. En la actualización, el producto se lee de la tarea existente (nunca del cuerpo). Omití una dimensión para dejarla sin cambios; enviá null para borrarla.
Ejemplo de código
- cURL
- JavaScript
- Python
curl -s -X POST "https://$TENANT/apidev/v1/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"contact": "Maria Gomez",
"external_id": "CRM-90021",
"phone_mobile": "+59899123456",
"classification": {
"procedence": "Call Center",
"product": "Roadside Assistance"
},
"origin": {
"country": "Uruguay",
"department": "Montevideo",
"city": "Montevideo",
"street": "Av. 18 de Julio",
"door_number": "1234"
},
"account": {
"external_code": "ACC-5587",
"name": "Maria Gomez"
},
"dynamic_fields": [
{ "label": "Vehicle Plate", "value": "ABC1234" }
]
}'
const res = await fetch(
`https://${TENANT}/apidev/v1/tasks`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'X-API-Key': apiKey,
'tenant': TENANT,
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact: 'Maria Gomez',
external_id: 'CRM-90021',
phone_mobile: '+59899123456',
classification: { procedence: 'Call Center', product: 'Roadside Assistance' },
origin: {
country: 'Uruguay',
department: 'Montevideo',
city: 'Montevideo',
street: 'Av. 18 de Julio',
door_number: '1234',
},
account: { external_code: 'ACC-5587', name: 'Maria Gomez' },
dynamic_fields: [{ label: 'Vehicle Plate', value: 'ABC1234' }],
}),
}
);
const { data, meta } = await res.json();
console.log(`Created ${meta.created}, failed ${meta.failed}. serid: ${data[0].serid}`);
import requests
response = requests.post(
f"https://{TENANT}/apidev/v1/tasks",
headers={"Authorization": f"Bearer {token}", "X-API-Key": api_key, "tenant": TENANT},
json={
"contact": "Maria Gomez",
"external_id": "CRM-90021",
"phone_mobile": "+59899123456",
"classification": {"procedence": "Call Center", "product": "Roadside Assistance"},
"origin": {
"country": "Uruguay",
"department": "Montevideo",
"city": "Montevideo",
"street": "Av. 18 de Julio",
"door_number": "1234",
},
"account": {"external_code": "ACC-5587", "name": "Maria Gomez"},
"dynamic_fields": [{"label": "Vehicle Plate", "value": "ABC1234"}],
},
)
result = response.json()
print(f"Created task: {result['data'][0]['serid']}")
Ejemplo por lote
Enviá { "items": [...] } con hasta 50 tareas. La respuesta mantiene el mismo orden mediante el index de cada ítem.
curl -s -X POST "https://$TENANT/apidev/v1/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "contact": "Maria Gomez", "classification": { "motive": "Breakdown" },
"origin": { "country": "Uruguay", "department": "Montevideo", "street": "Av. 18 de Julio" },
"account": { "external_code": "ACC-5587", "name": "Maria Gomez" } },
{ "contact": "Juan Perez", "classification": { "procedence": "Call Center", "product": "Tow" },
"origin": { "country": "Uruguay", "department": "Canelones", "street": "Ruta 8 km 25" },
"account": { "external_code": "ACC-9912", "name": "Juan Perez" } }
]
}'
Respuesta de ejemplo
Un alta individual exitosa devuelve data como un array de un ítem. HTTP 200 cuando al menos un ítem tiene éxito; meta.failed cuenta el resto.
{
"success": true,
"meta": { "created": 2, "failed": 1 },
"data": [
{
"index": 0,
"success": true,
"serid": "728193045120004001",
"service_number": "103878",
"assistance_number": "55012",
"status": "SA",
"warnings": []
},
{
"index": 1,
"success": true,
"serid": "728193045120004002",
"service_number": "103879",
"assistance_number": "55013",
"status": "SA",
"warnings": [
{
"index": 1,
"field": "origin.zone",
"code": "GEO_ZONE_IGNORED",
"message": "We couldn't find the zone you provided; the task was created without a zone.",
"hint": "Check the valid zones in the geographic catalogs."
}
]
},
{
"index": 2,
"success": false,
"errors": [
{
"index": 2,
"field": "classification.product",
"code": "PRODUCT_NOT_FOUND",
"message": "We couldn't find the product in the origin you provided.",
"hint": "Check GET /apidev/v1/catalogs/origins/{originId}/products."
}
]
}
]
}
Campos del ítem de resultado
| Campo | Tipo | Presencia | Descripción |
|---|---|---|---|
index | number | Siempre | Posición 0-based en el lote (0 para un objeto único). |
success | boolean | Siempre | Si este ítem tuvo éxito. |
serid | string | Si success | Id interno de la tarea. |
service_number | string | Si success | Número de servicio. |
assistance_number | string | Si success | Número de asistencia. |
status | string | Si success | Estado de comportamiento. Alta: SA (o ASI si nació asignada). |
warnings | array | Si success | Avisos no bloqueantes. [] si no hubo. Ver forma del aviso. |
errors | array | Si !success | Errores del ítem. Ver forma del aviso. |
meta lleva created + failed para el alta, updated + failed para la actualización y cancelled + failed para la cancelación.
Actualizar tarea
/apidev/v1/tasksAplica una actualización parcial: solo se cambian los campos que enviás; los omitidos conservan su valor actual. Acepta un objeto único o { "items": [...] }. Consultá Actualizaciones parciales para el patrón general.
Identificar una tarea
Enviá al menos uno de estos. Se resuelven en este orden hasta que uno coincida con una tarea de tu compañía:
| Campo | Tipo | Descripción |
|---|---|---|
serid | string | Identidad preferida. |
service_number | string | Segundo fallback. |
external_id | string | Tercer fallback (tu propia clave). |
Si ninguno resuelve, el ítem falla con TASK_NOT_FOUND. Una tarea que ya está en estado FIN o CAN falla con TASK_ALREADY_TERMINAL.
Cuerpo de la solicitud
Se aceptan todos los campos de negocio de Crear tarea (todos opcionales). Notas específicas de la actualización:
- Solo se aplican los campos presentes en el cuerpo.
- En OAV, solo se actualizan los
dynamic_fieldsque enviás (se comparan porlabel); los que no mencionás quedan como están. El conjunto completo de campos OAV obligatorios no se vuelve a verificar en la actualización; solo se validan los tipos de los que enviás. - No se acepta
service_number = 0/ autonumeración (la tarea ya existe). assignment_alertyno_notify_mobileaplican en la actualización.
Ejemplo de código
- cURL
- JavaScript
- Python
curl -s -X PUT "https://$TENANT/apidev/v1/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"external_id": "CRM-90021",
"phone_mobile": "+59899765432",
"detail": "Customer added a second contact number",
"dynamic_fields": [
{ "label": "Vehicle Plate", "value": "XYZ9876" }
]
}'
const res = await fetch(
`https://${TENANT}/apidev/v1/tasks`,
{
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'X-API-Key': apiKey,
'tenant': TENANT,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_id: 'CRM-90021',
phone_mobile: '+59899765432',
detail: 'Customer added a second contact number',
dynamic_fields: [{ label: 'Vehicle Plate', value: 'XYZ9876' }],
}),
}
);
const { data, meta } = await res.json();
console.log(`Updated ${meta.updated}, failed ${meta.failed}`);
import requests
response = requests.put(
f"https://{TENANT}/apidev/v1/tasks",
headers={"Authorization": f"Bearer {token}", "X-API-Key": api_key, "tenant": TENANT},
json={
"external_id": "CRM-90021",
"phone_mobile": "+59899765432",
"detail": "Customer added a second contact number",
"dynamic_fields": [{"label": "Vehicle Plate", "value": "XYZ9876"}],
},
)
result = response.json()
print(f"Updated: {result['meta']['updated']}")
Respuesta de ejemplo
{
"success": true,
"meta": { "updated": 1, "failed": 0 },
"data": [
{
"index": 0,
"success": true,
"serid": "728193045120004001",
"service_number": "103878",
"assistance_number": "55012",
"status": "SA",
"warnings": []
}
]
}
La forma del ítem de resultado es idéntica a la del alta. En la actualización, status refleja el estado actual de la tarea tras el cambio.
Cancelar tarea
/apidev/v1/tasksCancela una tarea (estado CAN) con un motivo. Si la tarea estaba asignada, se notifica al móvil. Acepta un objeto único o { "items": [...] }.
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
serid | string | Uno de los tres | Identidad (preferida). |
service_number | string | Uno de los tres | Identidad (segundo fallback). |
external_id | string | Uno de los tres | Identidad (tercer fallback). |
reason | string | Sí | Motivo de la cancelación. No puede estar vacío. Máx 2000. |
La identidad se resuelve en el orden serid → service_number → external_id. Una tarea que ya está en estado FIN o CAN falla con TASK_ALREADY_TERMINAL.
Ejemplo de código
- cURL
- JavaScript
- Python
curl -s -X DELETE "https://$TENANT/apidev/v1/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"external_id": "CRM-90021",
"reason": "Customer cancelled the request"
}'
const res = await fetch(
`https://${TENANT}/apidev/v1/tasks`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`,
'X-API-Key': apiKey,
'tenant': TENANT,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_id: 'CRM-90021',
reason: 'Customer cancelled the request',
}),
}
);
const { data, meta } = await res.json();
console.log(`Cancelled ${meta.cancelled}, failed ${meta.failed}`);
import requests
response = requests.delete(
f"https://{TENANT}/apidev/v1/tasks",
headers={"Authorization": f"Bearer {token}", "X-API-Key": api_key, "tenant": TENANT},
json={
"external_id": "CRM-90021",
"reason": "Customer cancelled the request",
},
)
result = response.json()
print(f"Cancelled: {result['meta']['cancelled']}")
Respuesta de ejemplo
{
"success": true,
"meta": { "cancelled": 1, "failed": 0 },
"data": [
{
"index": 0,
"success": true,
"serid": "728193045120004001",
"service_number": "103878",
"assistance_number": "55012",
"status": "CAN"
}
]
}
El ítem de resultado de cancelación lleva index, success, los tres identificadores y status (CAN cuando hay éxito), o errors[] en caso de fallo.
Errores
Dos capas de validación
La API valida en dos momentos distintos. No los confundas:
| Capa | Qué detecta | Respuesta |
|---|---|---|
| Forma | Campo desconocido, tipo equivocado, campo requerido faltante, largo inválido, lote vacío, lote de más de 50. | 400 VALIDATION_ERROR sin data; el cuerpo no se procesa y no se crea ningún ítem. |
| Negocio | Catálogo no resuelto, OAV obligatorio/tipo/lista, cupo de cobertura, recurso a asignar/reservar, identidad no encontrada. | Por ítem en data[].errors. HTTP 200 con meta.failed; 400 solo si todos los ítems fallan (el data + meta con los fallos igual se incluyen). |
Forma del aviso
Cada entrada de errors[] y warnings[] tiene la misma forma:
| Campo | Tipo | Descripción |
|---|---|---|
index | number | Posición 0-based en el lote. |
field | string | Ruta dot-path al campo del request (p. ej., classification.product, origin.country, dynamic_fields.<label>). |
code | string | Código estable de error/aviso (ver abajo). |
message | string | Explicación legible. |
hint | string | Próximo paso concreto (qué catálogo consultar / qué campo corregir). |
Los errores se acumulan: un mismo ítem puede devolver varios a la vez.
Códigos de error por ítem (falla dura — bloquean el ítem)
| Código | Campo típico | Descripción |
|---|---|---|
CONTACT_REQUIRED | contact | Falta el nombre del solicitante. |
ORIGIN_COUNTRY_REQUIRED | origin.country | Falta el país del origen. |
ORIGIN_DEPARTMENT_REQUIRED | origin.department | Falta el departamento / provincia del origen. |
STREET_REQUIRED | origin.street | Falta la calle del origen. |
MOTIVE_OR_CLASSIFICATION_REQUIRED | classification | Falta el motivo, o la prestación junto con su causa y subcausa. |
PROCEDENCE_NOT_FOUND | classification.procedence | No se encontró la procedencia. |
PRODUCT_NOT_FOUND | classification.product | No se encontró el producto en la procedencia indicada. |
COVERAGE_NOT_FOUND | classification.coverage | No se encontró la cobertura. |
MOTIVE_NOT_FOUND | classification.motive | No se encontró el motivo. |
PROVISION_NOT_FOUND | classification.provision | No se encontró la prestación. |
CAUSE_NOT_FOUND | classification.origin_cause / destination_cause | No se encontró la causa. |
SUBCAUSE_NOT_FOUND | classification.origin_subcause / destination_subcause | No se encontró la subcausa. |
GEO_NOT_FOUND | origin.city / destination.* | No se encontró la localidad geográfica. |
VEHICLE_TYPE_INVALID | vehicle_types | Uno de los tipos de móvil indicados no existe. |
OAV_REQUIRED_MISSING | dynamic_fields.<label> | Falta un campo dinámico obligatorio para este producto. |
OAV_TYPE_MISMATCH | dynamic_fields.<label> | El valor del campo dinámico no tiene el formato esperado. |
OAV_LIST_VALUE_INVALID | dynamic_fields.<label> | El valor no está entre las opciones permitidas del campo. |
ACCOUNT_NOT_RESOLVED | account.external_code | No se pudo resolver ni crear la cuenta. |
COVERAGE_QUOTA_EXCEEDED | classification.coverage | La cobertura agotó su cupo de servicios. |
RESERVE_PROVIDER_INVALID | reserve.provider | No se encontró el prestador a reservar. |
RESERVE_MOBILE_INVALID | reserve.mobile | No se encontró el móvil a reservar. |
RESERVE_USER_INVALID | reserve.user_email / telephonist_email | No se encontró el usuario. |
ASSIGN_VEHICLE_INVALID | assignment.assign_vehicle | No se encontró el móvil a asignar. |
ASSIGN_DRIVER_INVALID | assignment.assign_driver | No se encontró el conductor a asignar. |
ASSIGN_PROVIDER_INVALID | assignment.assign_provider | No se encontró el prestador a asignar. |
ASSIGN_TEMPLATE_INVALID | assignment.assign_template | No se encontró la plantilla de comunicación. |
TASK_NOT_FOUND | (identidad) | Ninguna tarea coincidió con serid / service_number / external_id. |
TASK_ALREADY_TERMINAL | (identidad) | La tarea ya está finalizada o cancelada y no puede modificarse. |
LOAD_DIMENSION_NOT_SUPPORTED | load.<dimensión> | El producto de la tarea no maneja este dato de carga (peso/volumen/bultos/frío/frágil/carga pesada). |
LOAD_VALUE_INVALID | load.<dimensión> | El valor de carga no tiene el formato esperado (peso/volumen deben ser números ≥ 0; bultos, un entero ≥ 0). |
Códigos de aviso (no bloqueantes — van a warnings[])
| Código | Campo típico | Significado |
|---|---|---|
GEO_ZONE_IGNORED | origin.zone | No se encontró la zona; la tarea se creó sin ella. |
SPECIAL_PLACE_IGNORED | origin.special_place | No se encontró el lugar especial; se ignoró. |
RESERVE_PERSONNEL_IGNORED | reserve.personnel | No se encontró el personal a reservar; se ignoró. |
COMM_MEDIUM_IGNORED | communication_medium | No se encontró la plantilla de comunicación; se ignoró. |
SHIFT_IGNORED | shift | No se encontró el turno; se ignoró. |
ATTACHMENT_LINK_FAILED | attachments | No se pudo registrar el enlace del adjunto. |
OAV_FIELD_UNKNOWN_IGNORED | dynamic_fields.<label> | La etiqueta no coincide con un campo del producto; se ignoró. |
ASSIGN_TEMPLATE_IGNORED | assignment.assign_template | La plantilla no pertenece al recurso; se usó la por defecto del recurso. |
Errores de transporte / forma / auth (envelope de fallo total)
| HTTP | Código | Descripción |
|---|---|---|
400 | VALIDATION_ERROR | Falló la validación de forma (campo desconocido, tipo equivocado, requerido faltante, largo, lote vacío o de más de 50). Detalle en error.details[]. |
401 | UNAUTHORIZED / TOKEN_EXPIRED | tenant / Authorization / X-API-Key ausente, inválido o expirado. |
403 | FORBIDDEN | La clave de API no tiene APICLI_TASKS_CREATE / APICLI_TASKS_UPDATE / APICLI_TASKS_CANCEL. |
404 | NOT_FOUND | La tarea no existe (actualización/cancelación de objeto único). |
429 | RATE_LIMITED | Se superaron 20 solicitudes/min. |
500 | INTERNAL_ERROR | Error inesperado del servidor. |
No hay upsert en este carril. Reenviar un POST con el mismo external_id crea una segunda tarea. Para cambiar una tarea existente, usá PUT.