Saltar al contenido principal

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:

  • POST crea una tarea o un lote de hasta 50.
  • PUT aplica una actualización parcial a una tarea existente.
  • DELETE cancela 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.

Requisitos previos

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.

IDs y fechas

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:

CampoTipoDescripción
seridstringIdentificador interno de la tarea (BigInt como string).
service_numberstringNúmero de servicio, asignado por el sistema al crear.
assistance_numberstringNú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:

EjeCamino ACamino B
Productoprocedence + productmotive
Prestaciónprovision + origin_cause + origin_subcausemotive

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.

Resolución por nombre

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

POST/apidev/v1/tasks
PermisoAPICLI_TASKS_CREATE
Límite de solicitudes20 solicitudes/min (ventana deslizante)
CachéNinguna

Crea 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

CampoTipoRequeridoMáxDescripción
contactstring200Nombre de quien solicita la tarea.
external_idstringNo200Tu propio identificador de la tarea.
service_numberstringNo40Número de servicio (string numérico). Omitir o 0 para autonumerar.
assistance_numberstringNo40Número de asistencia (string numérico). Un valor vincula esta tarea con una tarea padre.
phone_mobilestringNo50Celular del contacto.
phonestringNo50Teléfono fijo del contacto.
prioritystringNo200Id o valor de prioridad. Se resuelve contra la tabla de prioridades de la compañía; omitido → prioridad por defecto.
detailstringNoDetalle de texto libre del pedido.
notesstringNoNotas internas.
scheduled_atstringNo40Fecha/hora programada (ISO sin zona horaria).
scheduled_untilstringNo40Fecha/hora programada hasta (ISO sin zona horaria).
automatebooleanNoSi la tarea es automatizada.
pending_unconfirmedbooleanNoMarcar como pendiente / sin confirmar.
computesbooleanNoPor defecto true. false → no consume cupo de cobertura.
delay_minutesstringNo20Tolerancia de demora GPS, en minutos enteros.
communication_mediumstringNo200Plantilla de comunicación (id o nombre). No resuelve → advertencia.
shiftstringNo200Turno (id o nombre). No resuelve → advertencia.
telephonist_emailstringNo200Email del telefonista. Por defecto, el usuario de tus credenciales; no resuelve → falla dura.
no_notify_mobilebooleanNoSuprime la notificación al móvil (relevante sobre todo en la actualización).
assignment_alertstringNo2000Texto de alerta de asignación guardado en la tarea.
vehicle_typesstring[]No200 c/uTipos de móvil solicitados (ids o nombres). Uno inválido hace fallar el ítem.
classificationobjectVer regla de clasificación y campos de clasificación.
originobjectDirección del origen. country + department + street son obligatorios. Ver campos geográficos.
destinationobjectCondicionalObligatorio u opcional según el producto (p. ej., productos de grúa / mudanza lo exigen).
reserveobjectNoReserva un recurso sin asignar. Ver campos de reserva.
assignmentobjectNoAsigna la tarea al crearla (estado ASI; notificación al móvil solo cuando notify_mobile es true). Ver campos de asignación.
accountobjectCuenta del solicitante. Se auto-crea con la dirección del origen si no existe. Ver campos de cuenta.
dynamic_fieldsarrayCondicionalCampos dinámicos OAV. Obligatorios cuando el producto tiene OAV obligatorios. Ver campos dinámicos.
attachmentsarrayNoAdjuntos 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.
loadobjectNoDatos de carga (peso, volumen, bultos, requisitos de manipulación). Gateado por el perfil de carga del producto. Ver load.

Campos de classification

CampoTipoRequeridoDescripción
procedencestringCondicionalProcedencia (id o nombre). Requerido con product salvo que se envíe motive.
productstringCondicionalProducto (id, línea o nombre). Requiere procedence.
coveragestringNoCobertura (id o nombre).
motivestringCondicionalMotivo (id o nombre). Completa prestación/causa/subcausa automáticamente.
provisionstringCondicionalPrestación (id o nombre). Requerido con las dos causas salvo que se envíe motive.
origin_causestringCondicionalCausa de origen (id o nombre).
origin_subcausestringCondicionalSubcausa de origen (id o nombre).
destination_causestringNoCausa de destino (id o nombre).
destination_subcausestringNoSubcausa 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.

CampoTipoRequerido (origin)Descripción
countrystringPaís (id o nombre).
departmentstringDepartamento / provincia (id o nombre).
citystringNoCiudad (id o nombre).
zonestringNoZona (id o nombre). No resuelve → advertencia.
streetstringCalle. Obligatoria en el origen (salvo que se herede de la cuenta).
cornerstringNoEsquina. Máx 500.
corner2stringNoSegunda esquina. Máx 500.
door_numberstringNoNúmero de puerta (texto — admite "1234", "S/N", "12-A"). Máx 50.
apartmentstringNoApartamento. Máx 50.
facingstringNoReferencia de hacia dónde mira. Máx 200.
special_placestringNoLugar especial (id o nombre). No resuelve → advertencia.
latstringNoLatitud. 0 u omitida → resolución de geocoding.
lngstringNoLongitud. 0 u omitida → resolución de geocoding.
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).

CampoTipoDescripción
personnelstringPersonal a reservar (id o nombre). No resuelve → advertencia.
providerstringPrestador a reservar (id o nombre). No resuelve → falla dura.
mobilestringMóvil a reservar (id o nombre). No resuelve → falla dura.
user_emailstringUsuario a reservar. No resuelve → falla dura.
notify_mobilebooleanNotifica 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).

CampoTipoDescripción
assign_vehiclestringMóvil a asignar (id o nombre). Resuelve la jornada laboral activa del conductor. No resuelve → falla dura.
assign_driverstringConductor a asignar (id o nombre). No resuelve → falla dura.
assign_providerstringPrestador a asignar (id o nombre), como alternativa a un móvil. No resuelve → falla dura.
assign_templatestringPlantilla 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_mobilebooleanNotifica 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.

CampoTipoDescripción
external_codestringResuelve la cuenta por código externo. Máx 200.
namestringNombre de la cuenta (usado al auto-crear). Máx 200.
update_if_existsbooleanSi es true, actualiza los campos no vacíos de la cuenta existente.
documentstringNúmero de documento (clave de búsqueda).
phonestringTeléfono (clave de búsqueda).
mobilestringCelular (clave de búsqueda).
emailstringEmail (clave de búsqueda).
notesstringNotas de la cuenta. Máx 2000.
addressobjectDirecció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_fields debe incluirlos con un value no vacío, o el ítem falla con OAV_REQUIRED_MISSING.
  • Cada value se 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 label que no coincide con ningún campo del producto se ignora con una advertencia (no hace fallar el ítem).
CampoTipoRequeridoDescripción
labelstringEtiqueta del campo. Se compara sin distinguir mayúsculas contra los nombres de los campos OAV del producto.
valuestringNoValor, tipado según el campo. Máx 4000.

Campos de attachments

CampoTipoRequeridoDescripción
namestringNoNombre de archivo a mostrar. Máx 300.
urlstringURL HTTPS que se guarda tal cual como un enlace externo (se abre desde la web/app; no se descarga). Máx 2000.
notesstringNoNotas del adjunto. Máx 2000.
Un enlace fallido no hace fallar la tarea

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.

CampoTipoDescripción
weightKgnumberPeso total en kilogramos (≥ 0).
volumeM3numberVolumen total en metros cúbicos (≥ 0).
packagesintegerCantidad de bultos (≥ 0).
requiresColdbooleanRequiere manipulación refrigerada.
requiresFragilebooleanContiene elementos frágiles.
requiresHeavybooleanRequiere manipulación de carga pesada.
Solo las dimensiones que el producto maneja

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 -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" }
]
}'

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

CampoTipoPresenciaDescripción
indexnumberSiemprePosición 0-based en el lote (0 para un objeto único).
successbooleanSiempreSi este ítem tuvo éxito.
seridstringSi successId interno de la tarea.
service_numberstringSi successNúmero de servicio.
assistance_numberstringSi successNúmero de asistencia.
statusstringSi successEstado de comportamiento. Alta: SA (o ASI si nació asignada).
warningsarraySi successAvisos no bloqueantes. [] si no hubo. Ver forma del aviso.
errorsarraySi !successErrores 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

PUT/apidev/v1/tasks
PermisoAPICLI_TASKS_UPDATE
Límite de solicitudes20 solicitudes/min (ventana deslizante)
CachéNinguna

Aplica 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:

CampoTipoDescripción
seridstringIdentidad preferida.
service_numberstringSegundo fallback.
external_idstringTercer 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_fields que enviás (se comparan por label); 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_alert y no_notify_mobile aplican en la actualización.

Ejemplo de código

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" }
]
}'

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

DELETE/apidev/v1/tasks
PermisoAPICLI_TASKS_CANCEL
Límite de solicitudes20 solicitudes/min (ventana deslizante)
CachéNinguna

Cancela 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

CampoTipoRequeridoDescripción
seridstringUno de los tresIdentidad (preferida).
service_numberstringUno de los tresIdentidad (segundo fallback).
external_idstringUno de los tresIdentidad (tercer fallback).
reasonstringMotivo de la cancelación. No puede estar vacío. Máx 2000.

La identidad se resuelve en el orden seridservice_numberexternal_id. Una tarea que ya está en estado FIN o CAN falla con TASK_ALREADY_TERMINAL.

Ejemplo de código

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"
}'

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:

CapaQué detectaRespuesta
FormaCampo 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.
NegocioCatá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:

CampoTipoDescripción
indexnumberPosición 0-based en el lote.
fieldstringRuta dot-path al campo del request (p. ej., classification.product, origin.country, dynamic_fields.<label>).
codestringCódigo estable de error/aviso (ver abajo).
messagestringExplicación legible.
hintstringPró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ódigoCampo típicoDescripción
CONTACT_REQUIREDcontactFalta el nombre del solicitante.
ORIGIN_COUNTRY_REQUIREDorigin.countryFalta el país del origen.
ORIGIN_DEPARTMENT_REQUIREDorigin.departmentFalta el departamento / provincia del origen.
STREET_REQUIREDorigin.streetFalta la calle del origen.
MOTIVE_OR_CLASSIFICATION_REQUIREDclassificationFalta el motivo, o la prestación junto con su causa y subcausa.
PROCEDENCE_NOT_FOUNDclassification.procedenceNo se encontró la procedencia.
PRODUCT_NOT_FOUNDclassification.productNo se encontró el producto en la procedencia indicada.
COVERAGE_NOT_FOUNDclassification.coverageNo se encontró la cobertura.
MOTIVE_NOT_FOUNDclassification.motiveNo se encontró el motivo.
PROVISION_NOT_FOUNDclassification.provisionNo se encontró la prestación.
CAUSE_NOT_FOUNDclassification.origin_cause / destination_causeNo se encontró la causa.
SUBCAUSE_NOT_FOUNDclassification.origin_subcause / destination_subcauseNo se encontró la subcausa.
GEO_NOT_FOUNDorigin.city / destination.*No se encontró la localidad geográfica.
VEHICLE_TYPE_INVALIDvehicle_typesUno de los tipos de móvil indicados no existe.
OAV_REQUIRED_MISSINGdynamic_fields.<label>Falta un campo dinámico obligatorio para este producto.
OAV_TYPE_MISMATCHdynamic_fields.<label>El valor del campo dinámico no tiene el formato esperado.
OAV_LIST_VALUE_INVALIDdynamic_fields.<label>El valor no está entre las opciones permitidas del campo.
ACCOUNT_NOT_RESOLVEDaccount.external_codeNo se pudo resolver ni crear la cuenta.
COVERAGE_QUOTA_EXCEEDEDclassification.coverageLa cobertura agotó su cupo de servicios.
RESERVE_PROVIDER_INVALIDreserve.providerNo se encontró el prestador a reservar.
RESERVE_MOBILE_INVALIDreserve.mobileNo se encontró el móvil a reservar.
RESERVE_USER_INVALIDreserve.user_email / telephonist_emailNo se encontró el usuario.
ASSIGN_VEHICLE_INVALIDassignment.assign_vehicleNo se encontró el móvil a asignar.
ASSIGN_DRIVER_INVALIDassignment.assign_driverNo se encontró el conductor a asignar.
ASSIGN_PROVIDER_INVALIDassignment.assign_providerNo se encontró el prestador a asignar.
ASSIGN_TEMPLATE_INVALIDassignment.assign_templateNo 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_SUPPORTEDload.<dimensión>El producto de la tarea no maneja este dato de carga (peso/volumen/bultos/frío/frágil/carga pesada).
LOAD_VALUE_INVALIDload.<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ódigoCampo típicoSignificado
GEO_ZONE_IGNOREDorigin.zoneNo se encontró la zona; la tarea se creó sin ella.
SPECIAL_PLACE_IGNOREDorigin.special_placeNo se encontró el lugar especial; se ignoró.
RESERVE_PERSONNEL_IGNOREDreserve.personnelNo se encontró el personal a reservar; se ignoró.
COMM_MEDIUM_IGNOREDcommunication_mediumNo se encontró la plantilla de comunicación; se ignoró.
SHIFT_IGNOREDshiftNo se encontró el turno; se ignoró.
ATTACHMENT_LINK_FAILEDattachmentsNo se pudo registrar el enlace del adjunto.
OAV_FIELD_UNKNOWN_IGNOREDdynamic_fields.<label>La etiqueta no coincide con un campo del producto; se ignoró.
ASSIGN_TEMPLATE_IGNOREDassignment.assign_templateLa plantilla no pertenece al recurso; se usó la por defecto del recurso.

Errores de transporte / forma / auth (envelope de fallo total)

HTTPCódigoDescripción
400VALIDATION_ERRORFalló 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[].
401UNAUTHORIZED / TOKEN_EXPIREDtenant / Authorization / X-API-Key ausente, inválido o expirado.
403FORBIDDENLa clave de API no tiene APICLI_TASKS_CREATE / APICLI_TASKS_UPDATE / APICLI_TASKS_CANCEL.
404NOT_FOUNDLa tarea no existe (actualización/cancelación de objeto único).
429RATE_LIMITEDSe superaron 20 solicitudes/min.
500INTERNAL_ERRORError inesperado del servidor.
POST siempre crea

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.