{"openapi":"3.1.0","info":{"title":"Trazia Platform API","version":"1.0.0","description":"API pública de la plataforma Trazia. Cadena de custodia, tracking y antifraude para aseguradoras de LATAM.\n\nCasi todos los endpoints están versionados bajo `/api/v1`. Las rutas próximas a sunset llevan los headers `Sunset` y `Deprecation` (RFC 8594) en cada respuesta.","contact":{"name":"Equipo Trazia","email":"platform@trazia.io","url":"https://trazia.io"},"license":{"name":"Privado · uso bajo contrato"}},"servers":[{"url":"https://app.trazia.io","description":"Producción"},{"url":"http://localhost:3000","description":"Local dev"}],"tags":[{"name":"Events","description":"Activación + ciclo de vida de siniestros."},{"name":"Tracking","description":"Checkpoints + arribos automáticos."},{"name":"Auth","description":"Tokens de ajustador para la PWA."},{"name":"Notifications","description":"Bandeja in-app."},{"name":"Reports","description":"PDFs operativos / ejecutivos."},{"name":"Webhooks","description":"Disparadores de prueba."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"Per-tenant API key (`tk_live_...`) with explicit scopes."},"AdjusterBearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Short-lived adjuster JWT issued by `POST /api/v1/auth/adjuster-token`. Used together with `X-Api-Key` for the PWA activation flow."},"SessionCookie":{"type":"apiKey","in":"cookie","name":"next-auth.session-token","description":"Auth.js session cookie. Required for the in-app notifications API and for browser-side report downloads."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Invalid body"},"details":{}},"required":["code","message"]}},"required":["error"]},"ActivateEventBody":{"type":"object","properties":{"stickerQrCode":{"type":"string","minLength":4,"maxLength":160,"description":"QR code value printed on the sticker.","example":"QR-MX-A1B2C3"},"externalSinisterNumber":{"type":["string","null"],"description":"Carrier-side sinister identifier (optional)."},"vehicleData":{"type":"object","additionalProperties":{},"description":"Free-form vehicle attributes."},"insuredData":{"type":"object","additionalProperties":{}},"incidentData":{"type":"object","additionalProperties":{}},"location":{"type":"object","properties":{"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"accuracy":{"type":"number","minimum":0},"address":{"type":"string"}},"required":["latitude","longitude"]},"expectedWorkshopId":{"type":["string","null"]},"evidence":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"fileName":{"type":"string"},"fileUrl":{"type":"string","format":"uri"},"fileSize":{"type":"integer","minimum":0},"mimeType":{"type":"string"},"hashSha256":{"type":"string"}},"required":["type","fileName","fileUrl","fileSize","mimeType","hashSha256"]}}},"required":["stickerQrCode","vehicleData","location"]},"ActivateEventResponse":{"type":"object","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"stickerId":{"type":"string"},"activatedAt":{"type":"string","format":"date-time"},"tenantId":{"type":"string"}},"required":["id","status","stickerId","activatedAt","tenantId"]}},"required":["event"]},"CheckpointBody":{"type":"object","properties":{"stickerQrCode":{"type":"string","minLength":4,"maxLength":160},"source":{"type":"string","enum":["GOOGLE_FIND_MY","APPLE_FIND_MY","WORKSHOP_GATEWAY","MANUAL","CARRIER_API"]},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"accuracy":{"type":"number","minimum":0},"detectedAt":{"type":"string","format":"date-time"},"rawData":{"type":"object","additionalProperties":{}}},"required":["stickerQrCode","source","latitude","longitude"]},"CheckpointResponse":{"type":"object","properties":{"checkpoint":{"type":"object","properties":{"id":{"type":"string"},"eventId":{"type":"string"},"receivedAt":{"type":"string","format":"date-time"}},"required":["id","eventId","receivedAt"]},"transitions":{"type":"object","properties":{"toInTransit":{"type":"boolean"},"autoArrival":{"type":"boolean"},"unauthorizedArrival":{"type":"boolean"}},"required":["toInTransit","autoArrival","unauthorizedArrival"]},"alerts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"severity":{"type":"string","enum":["LOW","MEDIUM","HIGH","CRITICAL"]}},"required":["id","type","severity"]}}},"required":["checkpoint","transitions","alerts"]},"AdjusterTokenBody":{"type":"object","properties":{"adjusterId":{"type":"string","minLength":1},"ttlSeconds":{"type":"integer","exclusiveMinimum":0,"maximum":28800}},"required":["adjusterId"]},"AdjusterTokenResponse":{"type":"object","properties":{"token":{"type":"string"},"tokenType":{"type":"string","enum":["Bearer"]},"expiresAt":{"type":"string","format":"date-time"},"adjusterId":{"type":"string"}},"required":["token","tokenType","expiresAt","adjusterId"]},"InAppListResponse":{"type":"object","properties":{"unread":{"type":"integer","minimum":0},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"severity":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"url":{"type":["string","null"]},"readAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","severity","title","body","url","readAt","createdAt"]}}},"required":["unread","items"]}},"parameters":{}},"paths":{"/api/v1/events/activate":{"post":{"summary":"Activar un sticker","description":"Crea un evento (siniestro) ligado al sticker indicado, transiciona el sticker a ACTIVATED y dispara el webhook `event.activated`.","tags":["Events"],"security":[{"ApiKeyAuth":[],"AdjusterBearer":[]},{"SessionCookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateEventBody"}}}},"responses":{"201":{"description":"Evento creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateEventResponse"}}}},"400":{"description":"Sticker no elegible","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Autenticación faltante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Permiso insuficiente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Sticker no encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Sticker ya activado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Body inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit superado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/checkpoints":{"post":{"summary":"Reportar un checkpoint","description":"Ingresa un punto de ubicación para el evento ligado al sticker QR. Dispara la evaluación de geofence + el motor de alertas.","tags":["Tracking"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointBody"}}}},"responses":{"201":{"description":"Checkpoint registrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointResponse"}}}},"401":{"description":"Falta X-Api-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Scope checkpoints.write requerido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Evento no encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Body inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit superado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/auth/adjuster-token":{"post":{"summary":"Mint adjuster JWT","description":"Acuña un JWT de corta duración para que un ajustador pueda activar stickers desde la PWA sin crearle cuenta de Auth.js.","tags":["Auth"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjusterTokenBody"}}}},"responses":{"200":{"description":"Token emitido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjusterTokenResponse"}}}},"401":{"description":"X-Api-Key requerido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Scope adjusters.mint requerido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Body inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit superado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/in-app-notifications":{"get":{"summary":"Listar notificaciones in-app","description":"Bandeja de notificaciones del usuario autenticado para el tenant indicado. Usado por el bell icon del header.","tags":["Notifications"],"security":[{"SessionCookie":[]}],"parameters":[{"schema":{"type":"string","description":"Tenant slug"},"required":true,"description":"Tenant slug","name":"tenant","in":"query"},{"schema":{"type":"string"},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["0","1"]},"required":false,"name":"unread","in":"query"}],"responses":{"200":{"description":"Lista + contador","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InAppListResponse"}}}},"401":{"description":"Sesión requerida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Sin membresía en el tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tenant no existe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"summary":"Marcar notificaciones como leídas","description":"Marca como leídas las notificaciones del usuario autenticado. Si el body trae `ids`, solo esas; si no, todas.","tags":["Notifications"],"security":[{"SessionCookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tenant":{"type":"string"},"ids":{"type":"array","items":{"type":"string"}}},"required":["tenant"]}}}},"responses":{"200":{"description":"Resultado del marcado","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer","minimum":0}},"required":["updated"]}}}},"401":{"description":"Sesión requerida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/reports/{type}":{"get":{"summary":"Generar PDF de reporte","description":"Streamea un PDF marca Trazia con los números reales del periodo. Tipos: `executive`, `operational`, `antifraud`. Ventanas: `currentMonth`, `priorMonth`, `last7`, `last30`, `last90`.","tags":["Reports"],"security":[{"SessionCookie":[]}],"parameters":[{"schema":{"type":"string","enum":["executive","operational","antifraud"]},"required":true,"name":"type","in":"path"},{"schema":{"type":"string"},"required":true,"name":"tenant","in":"query"},{"schema":{"type":"string","enum":["currentMonth","priorMonth","last7","last30","last90"]},"required":false,"name":"window","in":"query"}],"responses":{"200":{"description":"PDF stream (`application/pdf`).","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"Sesión requerida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Permiso insuficiente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tenant o tipo no existe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Ventana inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/webhooks/test/{id}":{"post":{"summary":"Disparar evento de prueba","description":"Envía un payload `webhook.test` firmado al webhook indicado y registra la respuesta en `WebhookDelivery`.","tags":["Webhooks"],"security":[{"SessionCookie":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":true,"name":"tenant","in":"query"}],"responses":{"200":{"description":"Test enviado","content":{"application/json":{"schema":{"type":"object","properties":{"deliveryId":{"type":"string"},"status":{"type":"string","enum":["SUCCESS","FAILED"]},"responseStatus":{"type":["integer","null"]}},"required":["deliveryId","status","responseStatus"]}}}},"401":{"description":"Sesión requerida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Falta MANAGE_WEBHOOKS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook no encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit superado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"webhooks":{}}