Multimedia y PDFs de la tarea
Obtené las evidencias adjuntas a una tarea — fotos, firmas, croquis, audios y el PDF de un formulario completado en campo. Tres operaciones, todas de solo lectura:
- Listar los metadatos de los adjuntos de una tarea (nombre, tipo, tamaño, fecha, notas, proveedor de almacenamiento) — sin contenido pesado.
- Descargar un archivo puntual por
media_id, como enlace firmado (link, por defecto) o comobase64(on-demand). - Generar el PDF de un formulario como base64, on-demand.
Todos los endpoints requieren un token JWT válido, una clave de API y el encabezado tenant. Consultá Autenticación.
Una credencial solo alcanza las tareas que vería su usuario técnico en el panel web. Aquí aplican las mismas reglas de visibilidad por tarea (móvil/vehículo, aislamiento de procedencia y visibilidad por grupo). Si una tarea existe pero está fuera de ese alcance, recibís 403 FORBIDDEN — no un 404.
Listar adjuntos
Obtiene los metadatos de los adjuntos directos de una tarea. El contenido nunca se incluye — usá el endpoint de descarga para traer un archivo.
/apidev/v1/tasks/{id}/attachmentsParámetros de ruta
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | Identificador de la tarea. Acepta el ID interno de la tarea, el número de servicio o el ID externo (ver Resolución multi-identificador). |
Parámetros de consulta
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
type | string | No | Filtra por la clase del adjunto: signature, image, sketch, audio, qr, barcode u other. Omitir para no filtrar. |
form_id | string | No | Identificador del formulario (BigInt opaco). Reservado para adjuntos de formulario. Longitud máxima 40. Ver la nota de abajo. |
El listado por defecto devuelve solo los adjuntos directos de la tarea, por lo que form_id y form_name salen siempre null aquí. Filtrar por form_id apunta a los adjuntos que pertenecen a un formulario — un camino aún no implementado, así que ese filtro hoy devuelve una lista vacía.
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
serid | string | ID de la tarea resuelta (BigInt como string) |
service_number | string | null | Número de servicio (BigInt como string) |
assistance_number | string | null | Número de asistencia (BigInt como string) |
attachments | array | Metadatos de los adjuntos — sin el contenido del archivo |
attachments[].media_id | string | Identificador del archivo para el endpoint de descarga |
attachments[].name | string | null | Nombre visible del archivo |
attachments[].type | string | signature, image, sketch, audio, qr, barcode u other |
attachments[].raw_type | string | null | Solo presente cuando type es other — el código de captura original |
attachments[].mime_type | string | null | Inferido por la extensión del archivo; null si no se reconoce |
attachments[].size | number | null | Tamaño del archivo en bytes |
attachments[].date | string | null | Marca de tiempo de la captura (sin zona horaria) |
attachments[].notes | string | null | Notas del adjunto |
attachments[].form_id | string | null | ID del formulario — siempre null en el listado directo |
attachments[].form_name | string | null | Nombre del formulario — siempre null en el listado directo |
attachments[].provider | string | null | Etiqueta del proveedor de almacenamiento (p. ej., azure, s3) |
meta.count | number | Cantidad de adjuntos devueltos |
El listado nunca expone la ruta de almacenamiento del archivo, el contenedor, la referencia del proveedor ni ningún enlace firmado. El contenido se trae por el endpoint de descarga.
Ejemplo de código
- cURL
- JavaScript
- Python
curl -s "https://$TENANT/apidev/v1/tasks/103878/attachments?type=image" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/tasks/103878/attachments?type=image`,
{
headers: {
"Authorization": `Bearer ${token}`,
"X-API-Key": API_KEY,
"tenant": TENANT,
},
}
);
const { data, meta } = await response.json();
console.log(`Task ${data.service_number} has ${meta.count} attachment(s)`);
response = requests.get(
f"https://{TENANT}/apidev/v1/tasks/103878/attachments",
headers=headers,
params={"type": "image"},
)
result = response.json()
for media in result["data"]["attachments"]:
print(f"{media['media_id']}: {media['name']} ({media['type']})")
Respuesta de ejemplo
{
"success": true,
"data": {
"serid": "1284773829100",
"service_number": "103878",
"assistance_number": "5567",
"attachments": [
{
"media_id": "9981273645",
"name": "foto_siniestro_1.jpg",
"type": "image",
"mime_type": "image/jpeg",
"size": 482113,
"date": "2026-06-22T14:31:07",
"notes": "Frente del vehículo",
"form_id": null,
"form_name": null,
"provider": "azure"
},
{
"media_id": "9981273988",
"name": "conformidad_firma.png",
"type": "signature",
"mime_type": "image/png",
"size": 18422,
"date": "2026-06-22T15:02:44",
"notes": null,
"form_id": null,
"form_name": null,
"provider": "s3"
}
]
},
"meta": { "count": 2 }
}
Descargar adjunto
Trae un archivo puntual por media_id. Por defecto obtenés una URL firmada de corta duración (mode=link); pasá mode=base64 para recibir el contenido completo en línea.
/apidev/v1/tasks/{id}/attachments/{media_id}Parámetros de ruta
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | Identificador de la tarea (ID de la tarea, número de servicio o ID externo) |
media_id | string | Sí | Identificador del adjunto, tomado de la respuesta de Listar adjuntos |
Parámetros de consulta
| Parámetro | Tipo | Requerido | Por defecto | Descripción |
|---|---|---|---|---|
mode | string | No | link | link devuelve una URL firmada con expiración. base64 devuelve el contenido completo del archivo. |
Campos de la respuesta
| Campo | Tipo | Presente en | Descripción |
|---|---|---|---|
serid | string | ambos | ID de la tarea resuelta |
service_number | string | null | ambos | Número de servicio |
assistance_number | string | null | ambos | Número de asistencia |
media_id | string | ambos | Eco del identificador del adjunto solicitado |
name | string | null | ambos | Nombre del archivo |
type | string | ambos | Clase del adjunto (ver Listar adjuntos) |
mime_type | string | null | ambos | Tipo MIME. Con base64, se prefiere el tipo informado por el proveedor de almacenamiento por sobre el inferido por la extensión. |
size | number | null | ambos | Tamaño del archivo en bytes |
mode | string | ambos | Eco del modo — link o base64 |
download_url | string | solo link | URL firmada de corta duración |
expires_at | string | null | solo link | Momento en que la URL firmada deja de servir (sin zona horaria) |
file_base64 | string | solo base64 | Contenido completo del archivo |
Una URL de link es efímera. Descargá el contenido antes de expires_at. Para archivado masivo, volvé a llamar a este endpoint para refrescar la URL. Nunca se devuelve un enlace expirado — si no se puede refrescar, recibís 409 ATTACHMENT_UNAVAILABLE en lugar de una URL muerta.
link para volumenbase64 carga el archivo completo en memoria. Usalo para archivos chicos o descargas puntuales; para archivos grandes o descargas masivas, preferí mode=link.
Ejemplo de código
- cURL
- JavaScript
- Python
# Por defecto — enlace firmado
curl -s "https://$TENANT/apidev/v1/tasks/103878/attachments/9981273645" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
# Contenido base64, on-demand
curl -s "https://$TENANT/apidev/v1/tasks/103878/attachments/9981273988?mode=base64" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/tasks/103878/attachments/9981273645?mode=link`,
{ headers }
);
const { data } = await response.json();
console.log(`Download ${data.name} before ${data.expires_at}: ${data.download_url}`);
response = requests.get(
f"https://{TENANT}/apidev/v1/tasks/103878/attachments/9981273988",
headers=headers,
params={"mode": "base64"},
)
data = response.json()["data"]
print(f"{data['name']}: {data['size']} bytes, {len(data['file_base64'])} base64 chars")
Respuesta de ejemplo — mode=link
{
"success": true,
"data": {
"serid": "1284773829100",
"service_number": "103878",
"assistance_number": "5567",
"media_id": "9981273645",
"name": "foto_siniestro_1.jpg",
"type": "image",
"mime_type": "image/jpeg",
"size": 482113,
"download_url": "https://geotareasstore.blob.core.windows.net/cia-42/9981273645.jpg?sv=2024-08&se=2026-06-25T16%3A10%3A00Z&sig=Rb9...",
"expires_at": "2026-06-25T16:10:00",
"mode": "link"
}
}
Respuesta de ejemplo — mode=base64
{
"success": true,
"data": {
"serid": "1284773829100",
"service_number": "103878",
"assistance_number": "5567",
"media_id": "9981273988",
"name": "conformidad_firma.png",
"type": "signature",
"mime_type": "image/png",
"size": 18422,
"file_base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
"mode": "base64"
}
}
PDF del formulario
Genera el PDF de un formulario completado en la tarea. El PDF se produce on-demand y se devuelve como base64 — no se almacena.
/apidev/v1/tasks/{id}/forms/{form_id}/pdfParámetros de ruta
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | Sí | Identificador de la tarea (ID de la tarea, número de servicio o ID externo) |
form_id | string | Sí | Identificador del formulario completado (BigInt opaco) |
Parámetros de consulta
| Parámetro | Tipo | Requerido | Por defecto | Descripción |
|---|---|---|---|---|
mode | string | No | base64 | Modo de entrega. Por ahora solo se admite base64. |
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
serid | string | ID de la tarea resuelta |
service_number | string | null | Número de servicio |
assistance_number | string | null | Número de asistencia |
form_id | string | Eco del identificador del formulario solicitado |
form_name | string | null | Nombre legible del formulario |
filename | string | Nombre de archivo sugerido para el PDF |
mime_type | string | Siempre application/pdf |
file_base64 | string | El contenido del PDF generado |
mode | string | Siempre base64 |
Ejemplo de código
- cURL
- JavaScript
- Python
curl -s "https://$TENANT/apidev/v1/tasks/103878/forms/77120033/pdf" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT"
const response = await fetch(
`https://${TENANT}/apidev/v1/tasks/103878/forms/77120033/pdf`,
{ headers }
);
const { data } = await response.json();
// Decode and persist on your side
const bytes = Buffer.from(data.file_base64, "base64");
console.log(`${data.filename}: ${bytes.length} bytes`);
import base64
response = requests.get(
f"https://{TENANT}/apidev/v1/tasks/103878/forms/77120033/pdf",
headers=headers,
)
data = response.json()["data"]
with open(data["filename"], "wb") as f:
f.write(base64.b64decode(data["file_base64"]))
print(f"Saved {data['filename']}")
Respuesta de ejemplo
{
"success": true,
"data": {
"serid": "1284773829100",
"service_number": "103878",
"assistance_number": "5567",
"form_id": "77120033",
"form_name": "Acta de conformidad",
"filename": "acta_conformidad_103878.pdf",
"mime_type": "application/pdf",
"file_base64": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50...",
"mode": "base64"
}
}
Resolución multi-identificador
El parámetro de ruta {id} acepta cualquiera de tres identificadores, intentados en este orden:
- ID de la tarea (
serid) - Número de servicio (
service_number) - ID externo (
external_id)
El mismo valor se prueba contra cada candidato dentro de tu tenant hasta que uno coincida con una tarea. Se buscan tanto las tareas activas como las históricas, así que una tarea finalizada igual resuelve. Si ninguno de los tres coincide, recibís 404 TASK_NOT_FOUND.
Esto significa que podés llamar al mismo endpoint con el identificador que tengas a mano — el ID interno de la tarea, el número de servicio impreso en un ticket o el ID externo de tu propio sistema.
Errores
| Código | HTTP | Aplica a | Descripción |
|---|---|---|---|
UNAUTHORIZED | 401 | Todos | tenant / Authorization / X-API-Key ausente, inválido o expirado |
FORBIDDEN | 403 | Todos | La credencial no tiene APICLI_TASKS_READ, o la tarea está fuera del alcance del usuario técnico |
TASK_NOT_FOUND | 404 | Todos | Ninguna tarea coincide con el identificador enviado en {id} |
ATTACHMENT_NOT_FOUND | 404 | Descarga | La tarea no tiene un adjunto con ese media_id |
FORM_NOT_FOUND | 404 | PDF del formulario | La tarea no tiene un formulario con ese form_id |
INVALID_MODE | 400 | Descarga, PDF del formulario | mode no es uno de los valores admitidos (link/base64 para descarga, base64 para PDF) |
ATTACHMENT_UNAVAILABLE | 409 | Descarga | El archivo existe en la base pero no se pudo resolver en el almacenamiento (enlace expirado que no se pudo refrescar, o el archivo fue movido/eliminado) |
PDF_GENERATION_FAILED | 422 | PDF del formulario | El formulario existe pero no se pudo generar el PDF |
RATE_LIMITED | 429 | Todos | Se superaron 30 solicitudes/min |
INTERNAL_ERROR | 500 | Todos | Error inesperado del servidor |
Ejemplo de error — tarea fuera de alcance
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Esta credencial no tiene acceso a los archivos de esta tarea.",
"hint": "Usá una credencial con acceso a esa tarea, o pedí el permiso de lectura de tareas."
}
}
Ejemplo de error — archivo no disponible en almacenamiento
{
"success": false,
"error": {
"code": "ATTACHMENT_UNAVAILABLE",
"message": "El archivo existe pero no se pudo recuperar del almacenamiento en este momento.",
"hint": "Reintentá más tarde; si persiste, el archivo puede haberse eliminado del almacenamiento."
}
}
Relacionado
- Tareas — Listado y detalle — Lee tareas e inspecciona sus formularios
- Autenticación
- Límites de solicitudes
- Manejo de errores