{"openapi":"3.1.0","info":{"title":"OZ Storage API","version":"1.0.0","summary":"Almacenamiento propio de Agencia OZ (espacios, archivos, subidas directas, links, auditoría).","description":"API v1 de OZ Storage. El contrato está en español (nombres de campos, códigos de error y mensajes).\n\n**EN:** OZ Storage public API v1. Field names, error codes and messages are in Spanish; descriptions include an\nEnglish line for the most common operations.\n\n## Reglas que no cambian\n- **Nada se borra para siempre** desde la API: lo que va a la papelera se recupera durante 90 días.\n- **Los archivos nunca pasan por la API**: subidas y bajadas van directo al proveedor (B2) con URLs firmadas de pocos minutos.\n- **Acciones delicadas en dos pasos**: la API responde `202` con `confirmacion_requerida` y un código `OZS-XXXXXX`.\n  **Una llave nunca confirma**: la persona confirma en la web (passkey) o en OZ Storage para Mac (Touch ID).\n- **Gastos que pasan un tope**: `202` con `aprobacion_requerida` (o `confirmacion_requerida` con `tipo: aprobacion`).\n  Lo aprueba un dueño o admin con passkey; ninguna llave aprueba.\n- Cada cambio queda en el registro de auditoría con su `motivo` (obligatorio para llaves `mcp`).\n\n## Errores\nSiempre `{ \"error\": { \"codigo\": \"...\", \"mensaje\": \"...\" } }`. Códigos: `no_autenticado` 401, `reautenticar` 401,\n`sin_permiso` 403, `alcance_insuficiente` 403 (con `scope_requerido`), `aprobacion_rechazada` 403, `no_existe` 404,\n`conflicto` 409, `conflicto_version` 409 (con `nodo`), `en_frio` 409, `no_en_frio` 409, `cursor_vencido` 410,\n`solo_entrada` 403 (conexión limitada a la carpeta «Entrada IA»), `invalido` 422, `edicion_abierta` 422,\n`limite` 429 y `cupo_diario` 429 (con `Retry-After`), `interno` 500.\nPlan (docs/saas.md): `cuenta_solo_lectura` 402 (la organización no pagó: se ve, se baja y se comparte lo que hay, pero\nno se sube, no se crean links ni se manda a frío; con `plan`) y `cupo_excedido` 402 (no cabe en lo contratado; con\n`cupo`). No se reintentan solos: los resuelve un dueño o admin en la web, «Plan y pagos».\n\n## Idempotencia\nToda escritura acepta `Idempotency-Key` (1 a 200 caracteres). La API guarda la respuesta 24 h: repetir el pedido con\nla misma clave devuelve la misma respuesta (otro cuerpo con la misma clave → 422; un reintento simultáneo → 409).\nLos SDK mandan una clave nueva por llamada y la misma en cada reintento.\n\n## Paginación\nLos listados aceptan `?cursor=&limite=` (por defecto 50, máximo 200) y responden `{ items, siguiente }`. El cursor\nes opaco (puede pasar de 1 KB): se pasa tal cual. `siguiente: null` = no hay más.\n","contact":{"name":"Agencia OZ","email":"jose@agenciaoz.com"}},"servers":[{"url":"https://api.ozstorage.app","description":"Producción"},{"url":"http://localhost:8710","description":"Pila local (scripts/pila-local.sh)"}],"tags":[{"name":"identidad"},{"name":"espacios"},{"name":"archivos"},{"name":"subidas"},{"name":"links"},{"name":"equipo"},{"name":"auditoria"},{"name":"confirmaciones"},{"name":"costos"},{"name":"cambios"},{"name":"llaves"},{"name":"oauth"}],"security":[{"llave":[]}],"paths":{"/salud":{"get":{"operationId":"salud","tags":["identidad"],"summary":"¿La API responde?","description":"Sin autenticación. EN: liveness probe, no auth.","security":[],"x-oz-global":"publica","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["ok","version"],"properties":{"ok":{"type":"boolean"},"version":{"type":"string"}}}}}}}}},"/auth/yo":{"get":{"operationId":"yo","tags":["identidad"],"summary":"Quién soy (persona, organización y llave)","description":"Con una llave responde la persona, la organización a la que está atada la llave y la llave misma. Úsalo para\nsaber el `orgId` de todas las demás rutas.\nEN: with a key, returns the person, the key's organization (use its `id` as `orgId`) and the key.\n","x-oz-global":"cualquiera","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"Identidad de la llave","content":{"application/json":{"schema":{"$ref":"#/components/schemas/YoLlave"}}}},"401":{"$ref":"#/components/responses/NoAutenticado"}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"metadatosOAuth","tags":["oauth"],"summary":"Metadatos del servidor de autorización (RFC 8414)","security":[],"x-oz-global":"publica","responses":{"200":{"description":"Metadatos","content":{"application/json":{"schema":{"type":"object","required":["issuer","authorization_endpoint","token_endpoint"],"properties":{"issuer":{"type":"string"},"authorization_endpoint":{"type":"string"},"token_endpoint":{"type":"string"},"registration_endpoint":{"type":"string"},"scopes_supported":{"type":"array","items":{"type":"string"}},"code_challenge_methods_supported":{"type":"array","items":{"type":"string"}},"service_documentation":{"type":"string","description":"Guía pública para conectar una IA"},"op_policy_uri":{"type":"string","description":"Política de privacidad pública (borrador)"},"op_tos_uri":{"type":"string","description":"Términos de uso públicos (borrador)"}},"additionalProperties":true}}}}}}},"/oauth/register":{"post":{"operationId":"registrarClienteOAuth","tags":["oauth"],"summary":"Registro dinámico de un cliente OAuth público (RFC 7591)","description":"Solo acepta `redirect_uris` de la lista permitida: los callbacks de IAs conocidas y loopback\n(`http://127.0.0.1:*`, `http://localhost:*`, `http://[::1]:*`) para apps nativas como la CLI `oz`.\n","security":[],"x-oz-global":"publica","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect_uris"],"properties":{"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"grant_types":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string","enum":["none"]}}}}}},"responses":{"201":{"description":"Cliente registrado","content":{"application/json":{"schema":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string"},"oz_verificado":{"type":"boolean"}},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/ErrorOAuth"}}}},"/oauth/authorize":{"get":{"operationId":"autorizarOAuth","tags":["oauth"],"summary":"Autorización (código + PKCE S256), se abre en el navegador","description":"Redirige a la web para entrar con passkey y aprobar los permisos. `resource` es obligatorio y tiene que ser la URL\ndel MCP (`https://mcp.ozstorage.app/mcp`): el token que sale sirve para el MCP y para esta API con los\nscopes concedidos.\n","security":[],"x-oz-global":"publica","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","enum":["S256"]}},{"name":"state","in":"query","required":true,"schema":{"type":"string"}},{"name":"resource","in":"query","required":true,"schema":{"type":"string"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirección a la web (entrar o aprobar) o de vuelta al cliente con `code` o `error`"},"400":{"$ref":"#/components/responses/ErrorOAuth"}}}},"/oauth/token":{"post":{"operationId":"tokenOAuth","tags":["oauth"],"summary":"Canjear el código o renovar (refresh rota en cada uso)","security":[],"x-oz-global":"publica","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/PedidoToken"}},"application/json":{"schema":{"$ref":"#/components/schemas/PedidoToken"}}}},"responses":{"200":{"description":"Llave `mcp` de 24 h y refresh de 90 días","content":{"application/json":{"schema":{"type":"object","required":["access_token","token_type","expires_in","scope"],"properties":{"access_token":{"type":"string","pattern":"^ozk_"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer"},"refresh_token":{"type":"string","pattern":"^ozr_"},"scope":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/ErrorOAuth"}}}},"/v1/orgs/{orgId}/espacios":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarEspacios","tags":["espacios"],"summary":"Espacios que puedo ver","description":"EN: list the spaces (projects/clients) visible to the key's person.","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"$ref":"#/components/responses/PaginaEspacios"},"default":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"crearEspacio","tags":["espacios"],"summary":"Crear un espacio (dueño o admin de la organización)","x-oz-llaves":["api","dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","maxLength":200},"dias_para_frio":{"type":"integer","minimum":7,"maximum":3650},"confidencial":{"type":"boolean"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Espacio creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Espacio"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"verEspacio","tags":["espacios"],"summary":"Un espacio","x-oz-llaves":["api"],"responses":{"200":{"description":"Espacio","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Espacio"}}}},"default":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"cambiarEspacio","tags":["espacios"],"summary":"Renombrar, marcar entregado o cambiar la regla de frío (esto último en dos pasos)","x-oz-llaves":["api","dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string","maxLength":200},"estado":{"type":"string","enum":["activo","entregado"]},"dias_para_frio":{"type":"integer","minimum":7,"maximum":3650},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Espacio cambiado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Espacio"}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/raiz":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"raizEspacio","tags":["espacios","archivos"],"summary":"Lo que hay en la raíz de un espacio (carpetas primero)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"$ref":"#/components/responses/PaginaNodos"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/manifiesto":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"manifiestoEspacio","tags":["espacios"],"summary":"Manifiesto del espacio: todos sus archivos con ruta, tamaño, SHA-256, fecha y nivel","description":"Para llevarse un espacio (la salida de 60 días en solo lectura) o revisar una copia. CSV por defecto\n(`ruta,tamano_bytes,sha256,modificado_en_utc,nivel,id`, UTF-8 con BOM) o JSON con `?formato=json`. Quien puede\nbajar del espacio; también en solo lectura. Más de 200 000 archivos: `413 manifiesto_grande` (usa `oz export`).\nQueda en el registro (`espacio.manifiesto`).\n","x-oz-llaves":["api","dispositivo"],"parameters":[{"name":"formato","in":"query","required":false,"schema":{"type":"string","enum":["csv","json"]}}],"responses":{"200":{"description":"El manifiesto","content":{"text/csv":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","required":["espacio","archivos","bytes","items"],"properties":{"espacio":{"type":"string"},"archivos":{"type":"integer"},"bytes":{"type":"integer"},"items":{"type":"array","items":{"type":"object","required":["ruta","id","tamano","sha256","modificado_en","nivel"],"properties":{"ruta":{"type":"string"},"id":{"type":"string","format":"uuid"},"tamano":{"type":"integer"},"sha256":{"type":["string","null"]},"modificado_en":{"type":"string","format":"date-time"},"nivel":{"type":"string","enum":["caliente","frio"]}}}}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/archivar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"archivarEspacio","tags":["espacios"],"summary":"Pasar un espacio a frío (admins del espacio)","description":"Antes, el aviso: `GET …/archivar/vista-previa`. `409 nivel_en_curso` si una carpeta o un archivo del espacio se\nestá mandando a frío o despertando.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivoObligatorio"}}}},"responses":{"202":{"description":"Tarea encolada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TareaEncolada"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/despertar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"despertarEspacio","tags":["espacios","costos"],"summary":"Traer un espacio de frío a caliente (puede pedir aprobación de gasto)","description":"`202` con `tarea_id` si se encoló. Si cuesta (más de 200 GB, desde la bóveda o pasa un tope), `202` con\n`confirmacion_requerida` (tipo `aprobacion`) o `aprobacion_requerida`: no se hizo nada todavía.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivoObligatorio"}}}},"responses":{"202":{"description":"Encolado, o espera confirmación / aprobación","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/TareaEncolada"},{"$ref":"#/components/schemas/ConfirmacionRequerida"},{"$ref":"#/components/schemas/AprobacionRequerida"}]}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/pedir-despertar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"pedirDespertarEspacio","tags":["espacios"],"summary":"Pedir a los admins que despierten un espacio (avisa por WhatsApp; uno por hora)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"202":{"description":"Pedido","content":{"application/json":{"schema":{"type":"object","required":["pedido","repetido"],"properties":{"pedido":{"type":"boolean"},"repetido":{"type":"boolean"}}}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/archivar/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoArchivarEspacio","tags":["espacios"],"summary":"Aviso antes de mandar a frío un espacio entero (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de confirmar: archivos y bytes, costo al mes en frío y en caliente (lista de precios),\nhasta cuándo se cobra al menos (90 días), cuánto tarda despertar y su cargo pasado el 5 % gratis, cupo frío y si\nquien pregunta puede hacerlo (o pedirlo). `textos.es` y `textos.en` vienen listos para mostrar tal cual.\nLo ve quien ve el espacio. EN: preview before sending to cold or waking up.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoFrio"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/despertar/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoDespertarEspacio","tags":["espacios"],"summary":"Aviso antes de despertar un espacio entero (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de confirmar: archivos y bytes, costo al mes en frío y en caliente (lista de precios),\nhasta cuándo se cobra al menos (90 días), cuánto tarda despertar y su cargo pasado el 5 % gratis, cupo frío y si\nquien pregunta puede hacerlo (o pedirlo). `textos.es` y `textos.en` vienen listos para mostrar tal cual.\nLo ve quien ve el espacio. EN: preview before sending to cold or waking up.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoFrio"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/al-subir/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoAlSubirEspacio","tags":["espacios"],"summary":"Aviso antes de poner «al subir, mandar a frío» en un espacio entero (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de poner la regla: «todo lo que subas aquí se manda a frío al terminar de subir»,\n90 días mínimos, ~1 h para despertar, lo que cuesta despertar, la espera (`espera_min`), lo que ya está adentro\n(no se toca), el cupo frío y si quien pregunta puede ponerla. `textos.es` / `textos.en` listos para mostrar.\nLo ve quien ve el espacio. EN: preview before setting the “send to cold on upload” rule.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoAlSubir"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/al-subir":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"put":{"operationId":"alSubirEspacio","tags":["espacios"],"summary":"Poner o quitar «al subir, mandar a frío» en un espacio entero","description":"`al_subir: \"frio\"`: cada archivo que termina de subir adentro (a cualquier profundidad, por cualquier camino) pasa\na frío solo, pasada la espera (OZ_FRIO_AL_SUBIR_ESPERA_MIN, 10 min). Lo que ya estaba adentro no cambia. Lo\npueden poner los admins del espacio (como mandar a frío); con `motivo`. No se puede en solo lectura (402\n`cuenta_solo_lectura`) ni sin lugar en frío (402 `cupo_excedido`). `al_subir: null` la quita (gratis; también en\nsolo lectura). Registro `espacio.al_subir`.\nEN: set or remove the “send to cold on upload” rule.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["al_subir"],"properties":{"al_subir":{"$ref":"#/components/schemas/AlSubir"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"El espacio con su regla","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Espacio"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/entrada":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"entradaEspacio","tags":["espacios","archivos"],"summary":"La carpeta «Entrada IA» del espacio (se crea la primera vez)","description":"Donde va lo que guarda una IA o un agente si no dice carpeta. Pedirla dos veces devuelve la misma.\nEN: the space's \"AI inbox\" folder (created on first use).\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:save","x-oz-idempotente":true,"security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"La carpeta de entrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/equipo":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarEquipo","tags":["equipo"],"summary":"Personas de la organización (no para externos)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página de personas","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Miembro"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/equipo/invitar":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"invitarPersona","tags":["equipo"],"summary":"Invitar a alguien (con llave, solo como miembro o externo)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["correo","nombre"],"properties":{"correo":{"type":"string","format":"email"},"nombre":{"type":"string","minLength":1,"maxLength":120},"rol":{"type":"string","enum":["miembro","externo"],"default":"miembro"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Invitación enviada por correo (7 días)","content":{"application/json":{"schema":{"type":"object","required":["persona_id","correo","nombre","rol","invitacion_vence_en"],"properties":{"persona_id":{"$ref":"#/components/schemas/Uuid"},"correo":{"type":"string"},"nombre":{"type":"string"},"rol":{"type":"string"},"invitacion_vence_en":{"$ref":"#/components/schemas/Fecha"}}}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"verNodo","tags":["archivos"],"summary":"Un archivo o carpeta con sus versiones, copias y links activos","description":"EN: file or folder details, with versions, storage copies and active links.","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"Nodo con detalle","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodoDetalle"}}}},"default":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"cambiarNodo","tags":["archivos"],"summary":"Renombrar o mover (también a otro espacio; mover un árbol grande va en dos pasos)","description":"El id no cambia (los links y el historial siguen). Con `si_version` distinto de la versión actual → 409\n`conflicto_version` con el `nodo` actual. Llaves `mcp`: solo dentro del mismo espacio.\nEN: rename or move; same id. Moving a large tree to another space needs confirmation.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:organize","security":[{"llave":[]},{"oauth":["storage:organize"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string","maxLength":1000},"padre_id":{"$ref":"#/components/schemas/UuidONulo"},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"si_version":{"$ref":"#/components/schemas/Uuid"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Nodo cambiado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"409":{"description":"Conflicto (`conflicto`, `conflicto_version` con `nodo`, `en_frio`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/hijos":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"hijosNodo","tags":["archivos"],"summary":"Contenido de una carpeta (carpetas primero, por nombre)","description":"Sin los archivos que son el proxy subido de otro (`proxies_ocultos` dice cuántos hay en la primera página);\n`con_proxies=1` los muestra.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"},{"name":"con_proxies","in":"query","schema":{"type":"string","enum":["0","1"]}}],"responses":{"200":{"$ref":"#/components/responses/PaginaNodos"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/buscar":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"buscar","tags":["archivos"],"summary":"Buscar por nombre (más reciente primero)","description":"EN: search files and folders by name, newest first.","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":200}},{"name":"espacio_id","in":"query","schema":{"$ref":"#/components/schemas/Uuid"}},{"name":"tipo","in":"query","schema":{"type":"string","enum":["carpeta","archivo"]}},{"name":"nivel","in":"query","schema":{"$ref":"#/components/schemas/Nivel"}},{"name":"modificado_desde","in":"query","schema":{"$ref":"#/components/schemas/Fecha"}},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"$ref":"#/components/responses/PaginaNodos"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/carpetas":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"crearCarpeta","tags":["archivos"],"summary":"Crear una carpeta","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["espacio_id","nombre"],"properties":{"espacio_id":{"$ref":"#/components/schemas/Uuid"},"padre_id":{"$ref":"#/components/schemas/UuidONulo"},"destino":{"$ref":"#/components/schemas/DestinoEntrada"},"nombre":{"type":"string","maxLength":1000},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Carpeta creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/papelera":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"papeleraNodo","tags":["archivos"],"summary":"Mandar a la papelera (se recupera 90 días; más de 20 archivos o 50 GB va en dos pasos)","description":"EN: move to trash (recoverable for 90 days). Large trees need confirmation.","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:organize","security":[{"llave":[]},{"oauth":["storage:organize"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"En la papelera","content":{"application/json":{"schema":{"type":"object","required":["nodo","archivos","bytes"],"properties":{"nodo":{"$ref":"#/components/schemas/Nodo"},"archivos":{"type":"integer"},"bytes":{"type":"integer"}}}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/archivar/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoArchivarNodo","tags":["archivos"],"summary":"Aviso antes de mandar a frío una carpeta (con lo de adentro) o un archivo (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de confirmar: archivos y bytes, costo al mes en frío y en caliente (lista de precios),\nhasta cuándo se cobra al menos (90 días), cuánto tarda despertar y su cargo pasado el 5 % gratis, cupo frío y si\nquien pregunta puede hacerlo (o pedirlo). `textos.es` y `textos.en` vienen listos para mostrar tal cual.\nLo ve quien ve el espacio. EN: preview before sending to cold or waking up.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoFrio"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/despertar/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoDespertarNodo","tags":["archivos"],"summary":"Aviso antes de despertar una carpeta (con lo de adentro) o un archivo (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de confirmar: archivos y bytes, costo al mes en frío y en caliente (lista de precios),\nhasta cuándo se cobra al menos (90 días), cuánto tarda despertar y su cargo pasado el 5 % gratis, cupo frío y si\nquien pregunta puede hacerlo (o pedirlo). `textos.es` y `textos.en` vienen listos para mostrar tal cual.\nLo ve quien ve el espacio. EN: preview before sending to cold or waking up.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoFrio"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/al-subir/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoAlSubirNodo","tags":["archivos"],"summary":"Aviso antes de poner «al subir, mandar a frío» en una carpeta (cifras y textos es/en)","description":"Lo que hay que mostrar ANTES de poner la regla: «todo lo que subas aquí se manda a frío al terminar de subir»,\n90 días mínimos, ~1 h para despertar, lo que cuesta despertar, la espera (`espera_min`), lo que ya está adentro\n(no se toca), el cupo frío y si quien pregunta puede ponerla. `textos.es` / `textos.en` listos para mostrar.\nLo ve quien ve el espacio. EN: preview before setting the “send to cold on upload” rule.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvisoAlSubir"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/al-subir":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"put":{"operationId":"alSubirNodo","tags":["archivos"],"summary":"Poner o quitar «al subir, mandar a frío» en una carpeta","description":"`al_subir: \"frio\"`: cada archivo que termina de subir adentro (a cualquier profundidad, por cualquier camino) pasa\na frío solo, pasada la espera (OZ_FRIO_AL_SUBIR_ESPERA_MIN, 10 min). Lo que ya estaba adentro no cambia. Lo\npueden poner los admins del espacio (como mandar a frío); con `motivo`. No se puede en solo lectura (402\n`cuenta_solo_lectura`) ni sin lugar en frío (402 `cupo_excedido`). `al_subir: null` la quita (gratis; también en\nsolo lectura). Registro `nodo.al_subir`.\nEN: set or remove the “send to cold on upload” rule.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["al_subir"],"properties":{"al_subir":{"$ref":"#/components/schemas/AlSubir"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"La carpeta con su regla (y `al_subir_efectivo`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodoConRegla"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/archivar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"archivarNodo","tags":["archivos"],"summary":"Mandar a frío una carpeta (con todo lo de adentro) o un archivo (admins del espacio)","description":"Solo los archivos calientes que no están en la papelera; la tarea `archivar_espacio` (con `nodo_id`) mueve los\nbytes. Más de 20 archivos o 50 GB: `202 confirmacion_requerida` (dos pasos). `409 ya_en_frio` si no hay nada\ncaliente; `409 nivel_en_curso` si esto (o la carpeta donde está, o el espacio) ya está cambiando de nivel.\nEN: send a folder or a file to cold.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivoObligatorio"}}}},"responses":{"202":{"description":"Encolado, o espera confirmación (dos pasos)","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/TareaNivel"},{"$ref":"#/components/schemas/ConfirmacionRequerida"}]}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/despertar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"despertarNodo","tags":["archivos","costos"],"summary":"Traer de frío a caliente una carpeta o un archivo (puede pedir aprobación de gasto)","description":"Como `despertarEspacio`: `202` con `tarea_id` si se encoló; si cuesta (más de 200 GB, desde la bóveda, pasa un\ntope o el 5 % gratis del mes), `202` con `confirmacion_requerida` (tipo `aprobacion`) o `aprobacion_requerida`.\n`409 no_en_frio` si no hay nada en frío. EN: wake up a folder or a file.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivoObligatorio"}}}},"responses":{"202":{"description":"Encolado, o espera confirmación / aprobación","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/TareaNivel"},{"$ref":"#/components/schemas/ConfirmacionRequerida"},{"$ref":"#/components/schemas/AprobacionRequerida"}]}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/pedir-despertar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"pedirDespertarNodo","tags":["archivos"],"summary":"Pedir a los admins que despierten una carpeta o un archivo (avisa por WhatsApp; uno por hora)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"202":{"description":"Pedido","content":{"application/json":{"schema":{"type":"object","required":["pedido","repetido"],"properties":{"pedido":{"type":"boolean"},"repetido":{"type":"boolean"}}}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/proxy/regenerar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"regenerarProxy","tags":["archivos"],"summary":"Regenerar el proxy de un video (editores y más; idempotente)","description":"Marca el proxy, la miniatura y la tira de la versión actual como `error` (nunca los borra) y encola `proxy_generar`.\nCon una ya abierta para esa versión no hace nada más (`repetido: true`). 409 `en_frio` si el original está en frío;\n409 `proxy_subido` si usa un proxy subido por una persona.\n","x-oz-llaves":["api","dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["motivo"],"properties":{"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"202":{"description":"Encolado (o ya estaba)","content":{"application/json":{"schema":{"type":"object","required":["tarea_id","repetido","proxy"],"properties":{"tarea_id":{"type":["string","null"]},"repetido":{"type":"boolean"},"proxy":{"$ref":"#/components/schemas/Proxy"}}}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/proxy":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"agregarProxy","tags":["archivos"],"summary":"«Agregar proxy…» — ese archivo (un video caliente) pasa a ser el proxy del original y se esconde de las listas","x-oz-llaves":["api","dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nodo_proxy_id"],"properties":{"nodo_proxy_id":{"$ref":"#/components/schemas/Uuid"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"El original, con su `proxy`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/proxy/quitar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"quitarProxy","tags":["archivos"],"summary":"«Quitar proxy» — el proxy subido vuelve a ser un archivo normal (se ve otra vez; nada se borra)","x-oz-llaves":["api","dispositivo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"El original, con su `proxy`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/proxy/express/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoProxyExpress","tags":["archivos"],"summary":"Precio del proxy express (US$0,10 por GB entero del original, mínimo US$1) y cuándo lo haría OZ gratis; textos es/en","x-oz-llaves":["dispositivo"],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"type":"object","required":["nodo","bytes","gb","usd","exenta","puede","ya_tiene_proxy","plazo_gratis_dias","textos"],"properties":{"nodo":{"type":"object"},"version_id":{"type":["string","null"]},"bytes":{"type":"integer"},"gb":{"type":"integer"},"usd":{"type":"number"},"exenta":{"type":"boolean"},"puede":{"type":"boolean"},"motivo_no_puede":{"type":["string","null"]},"ya_tiene_proxy":{"type":"boolean"},"plazo_gratis_dias":{"type":"integer"},"listo_antes_gratis":{"$ref":"#/components/schemas/FechaONula"},"textos":{"type":"object","description":"`{ es, en }`, cada uno `{ titulo, resumen, puntos[], boton }`"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/proxy/express":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"pedirProxyExpress","tags":["archivos"],"summary":"Pedir el proxy express (dueños y admins; con costo, en dos pasos)","description":"Con costo: 202 `confirmacion_requerida` con el precio en el resumen (se confirma con passkey o Touch ID); al confirmar,\nun cargo extra para la próxima factura y el proxy al frente de la cola. Organización exenta: directo y sin cargo.\n409 `ya_tiene_proxy` o `no_disponible` (sin plan pagado, en frío); 403 si no es dueño o admin.\n","x-oz-llaves":["dispositivo"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"202":{"description":"Pedido (o la confirmación con el código)","content":{"application/json":{"schema":{"type":"object","properties":{"tarea_id":{"type":"string"},"repetido":{"type":"boolean"},"usd":{"type":"number"},"error":{"type":"object"},"confirmacion":{"type":"object"}}}}}},"409":{"description":"Ya tiene proxy o no se puede (`ya_tiene_proxy`, `no_disponible`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/pedir-original/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"avisoPedirOriginal","tags":["archivos"],"summary":"Aviso antes de pedir el original de un archivo en frío (cuánto pesa y tarda, el proxy para bajar ya; textos es/en)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"El aviso","content":{"application/json":{"schema":{"type":"object","required":["nodo","bytes","horas_aprox","disponible_horas","puede","textos"],"properties":{"nodo":{"type":"object"},"bytes":{"type":"integer"},"horas_aprox":{"type":"integer"},"disponible_horas":{"type":"integer"},"proveedor":{"type":["string","null"],"enum":["oracle","aws",null]},"proxy":{"type":["object","null"]},"puede":{"type":"boolean"},"motivo_no_puede":{"type":["string","null"]},"compartido":{"type":"boolean"},"pedido":{"oneOf":[{"$ref":"#/components/schemas/PedidoOriginal"},{"type":"null"}]},"despertar":{"type":"object"},"textos":{"type":"object","description":"`{ es, en }`, cada uno `{ titulo, resumen, puntos[], boton, boton_proxy }`"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/pedir-original":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"pedirOriginal","tags":["archivos"],"summary":"Pedir el original de un archivo en frío sin despertarlo (restauración temporal; aviso por correo y WhatsApp)","description":"Oracle restaura el objeto por `OZ_ORIGINAL_HORAS` (72) sin copiarlo a caliente. Cuando está listo llega un correo con\nun link a una página de OZ que lo baja directo de Oracle. Cuenta para el 5 % gratis del mes y la aprobación como\ndespertar (202 `confirmacion_requerida` / `aprobacion_requerida`, con `pedido`). 409 `no_en_frio` si está caliente.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"202":{"description":"Pedido (o el mismo de antes, `repetido`), o esperando la aprobación del gasto","content":{"application/json":{"schema":{"type":"object","properties":{"pedido":{"$ref":"#/components/schemas/PedidoOriginal"},"repetido":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/original/bajar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"bajarOriginalRestaurado","tags":["archivos"],"summary":"URL firmada (5 min) directo de Oracle para la copia restaurada, mientras dure (410 `vencido` después)","x-oz-llaves":["api","dispositivo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"La URL","content":{"application/json":{"schema":{"type":"object","required":["url","vence_en","nombre","tamano","disponible_hasta"],"properties":{"url":{"type":"string","format":"uri"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"nombre":{"type":"string"},"tamano":{"type":"integer"},"disponible_hasta":{"$ref":"#/components/schemas/Fecha"},"disponible_hasta_texto":{"type":"string","description":"En hora de Guayaquil"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/papelera":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarPapelera","tags":["archivos"],"summary":"Lo que está en la papelera (solo las raíces)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"name":"espacio_id","in":"query","schema":{"$ref":"#/components/schemas/Uuid"}},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página de la papelera","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NodoPapelera"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/restaurar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"restaurarNodo","tags":["archivos"],"summary":"Sacar de la papelera (con lo que cayó con él)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:organize","security":[{"llave":[]},{"oauth":["storage:organize"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Restaurado","content":{"application/json":{"schema":{"type":"object","required":["nodo","archivos"],"properties":{"nodo":{"$ref":"#/components/schemas/Nodo"},"archivos":{"type":"integer"}}}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/versiones/{versionId}/restaurar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"},{"name":"versionId","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Uuid"}}],"post":{"operationId":"restaurarVersion","tags":["archivos"],"summary":"Volver a una versión anterior (crea una versión nueva; no borra ninguna)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:organize","security":[{"llave":[]},{"oauth":["storage:organize"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Nodo con la versión nueva","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/volver-a-fecha/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"vistaPreviaVolverAFecha","tags":["archivos"],"summary":"Antes de volver una carpeta a una fecha, cuántos archivos vuelven, cuántos van a la papelera y cuántos quedan igual","description":"Lo mismo que haría `volverAFecha`, sin hacer nada. `fecha` en ISO 8601 con zona (hora de Guayaquil: `-05:00`).\nLo ve quien puede mandar a la papelera en ese espacio (editor). EN: dry run of a folder rewind.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"name":"fecha","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"example":"2026-10-20T15:30:00-05:00"}],"responses":{"200":{"description":"Las cuentas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolverAFecha"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/volver-a-fecha":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"volverAFecha","tags":["archivos"],"summary":"Volver una carpeta entera a como estaba en una fecha («Rewind»; más de 20 archivos o 50 GB va en dos pasos)","description":"Cada archivo que cambió vuelve a su última versión de antes de `fecha` (versión nueva; no se borra ninguna); lo que\nse mandó a la papelera después vuelve; lo creado después va a la papelera (90 días). No deshace nombres ni lugares,\nni toca archivos en frío (`en_frio`). Idempotente: repetirlo no cambia nada más. EN: rewind a folder to a date.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fecha"],"properties":{"fecha":{"type":"string","format":"date-time"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Hecho (o nada que hacer)","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/VolverAFecha"},{"type":"object","required":["hecho","nodo"],"properties":{"hecho":{"const":true},"nodo":{"$ref":"#/components/schemas/Nodo"}}}]}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/volver-a-fecha/vista-previa":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"vistaPreviaVolverEspacioAFecha","tags":["archivos"],"summary":"Antes de volver un proyecto entero a una fecha, cuántos archivos vuelven, cuántos van a la papelera y cuántos quedan igual","description":"Como `vistaPreviaVolverAFecha`, para todo el proyecto (también lo de su raíz). Sin hacer nada. Lo ve quien puede\nmandar a la papelera en ese espacio. Una conexión «solo en la carpeta de entrada» no puede. EN: dry run of a project rewind.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"name":"fecha","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"example":"2026-10-20T15:30:00-05:00"}],"responses":{"200":{"description":"Las cuentas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolverEspacioAFecha"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/espacios/{id}/volver-a-fecha":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"volverEspacioAFecha","tags":["archivos"],"summary":"Volver un proyecto entero a como estaba en una fecha («Rewind»; más de 20 archivos o 50 GB va en dos pasos)","description":"Lo mismo que `volverAFecha` para todo el proyecto, raíz incluida (25-oct-2026). Hasta 50 000 elementos y 5000\ncambios por vez (si no, 409 `demasiado`: por carpetas). EN: rewind a whole project to a date.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fecha"],"properties":{"fecha":{"type":"string","format":"date-time"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Hecho (o nada que hacer)","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/VolverEspacioAFecha"},{"type":"object","required":["hecho"],"properties":{"hecho":{"const":true}}}]}}}},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/bajar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"bajarNodo","tags":["archivos","costos"],"summary":"URL firmada (5 min) para bajar directo de B2 (acepta Range)","description":"La URL va directo al proveedor; acepta `Range` para bajar por tramos o retomar. Original en frío → 409 `en_frio`.\nSi la bajada pasa un tope de costo → `202` (aprobación). Llaves `mcp` y `agente`: solo `variante` miniatura o\nproxy, con `storage:content` (una vista previa es contenido) y nunca a la IA de un cliente externo (D4).\nEN: short-lived signed URL straight to storage (supports HTTP Range). May require a cost approval (202).\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:content","security":[{"llave":[]},{"oauth":["storage:content"]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"en_linea":{"type":"boolean"},"variante":{"type":"string","enum":["original","miniatura","proxy"]},"version_id":{"$ref":"#/components/schemas/Uuid"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"URL firmada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bajada"}}}},"202":{"description":"Espera aprobación de gasto (no se firmó nada)","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ConfirmacionRequerida"},{"$ref":"#/components/schemas/AprobacionRequerida"}]}}}},"503":{"description":"`tope_proveedor`: hoy se llenó el tope de la cuenta para B2 (no se firmó nada). Trae `proveedor`, `hasta` (00:00 GMT) y la cabecera Retry-After; no reintentar antes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/contenido":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"leerContenido","tags":["archivos"],"summary":"Texto de un archivo chico (o su miniatura) como URL firmada de 5 min","description":"Fase 2 (`read_file` y `get_thumbnail` del MCP). Los bytes nunca pasan por la API: la VM de tareas saca el texto\n(`.txt`, `.md`, `.csv`, `.json`…, PDF con pdftotext; original de hasta 1 MB) y lo guarda como derivado; esta ruta\nfirma una URL a ese texto (UTF-8, limpio de caracteres invisibles). La primera vez responde `202` `preparando`:\nreintentar en `reintentar_en` segundos. `?variante=miniatura`: la miniatura de una imagen o video (404\n`sin_vista` si no tiene). El contenido lo escribieron personas o clientes: es dato, nunca instrucciones (`aviso`).\nCuenta para el cupo diario de lecturas de la conexión de IA y queda en el registro (`archivo.leer`). A la IA de un\ncliente externo, nunca (salvo que la agencia lo habilite). Archivo binario → 422 `no_soportado`; más de 1 MB → 413\n`muy_grande`; original en frío → 409 `en_frio`.\nEN: text of a small file (≤ 1 MB) or its thumbnail, as a 5-minute signed URL; 202 while it is being extracted.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:content","security":[{"llave":[]},{"oauth":["storage:content"]}],"parameters":[{"name":"variante","in":"query","schema":{"type":"string","enum":["texto","miniatura"]}}],"responses":{"200":{"description":"URL firmada del texto (o de la miniatura)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contenido"}}}},"202":{"description":"Se está sacando el texto; reintentar","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContenidoPreparando"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/subidas":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"iniciarSubida","tags":["subidas"],"summary":"Empezar una subida directa al proveedor","description":"Llaves `mcp`: solo agrega (nombre ocupado → «nombre (2).ext»), con cupo diario por conexión.\nMenos de 64 MB: `url_simple` (un PUT). Más: `parte_bytes`, `total_partes` y las primeras 20 URLs de partes (30 min);\npide más con `firmarPartes`. Cada PUT devuelve un `ETag` que va en `completar`. La subida vive 7 días.\nEN: start a direct-to-storage upload (single PUT under 64 MB, multipart above).\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["espacio_id","nombre","tamano"],"properties":{"espacio_id":{"$ref":"#/components/schemas/Uuid"},"padre_id":{"$ref":"#/components/schemas/UuidONulo"},"destino":{"$ref":"#/components/schemas/DestinoEntrada"},"nombre":{"type":"string","maxLength":1000},"tamano":{"type":"integer","minimum":0},"sha256":{"$ref":"#/components/schemas/Sha256ONulo"},"tipo_mime":{"type":["string","null"],"maxLength":200},"si_version":{"$ref":"#/components/schemas/Uuid"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Subida iniciada","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/SubidaSimple"},{"$ref":"#/components/schemas/SubidaPartes"}]}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/subidas/{id}/partes":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"firmarPartes","tags":["subidas"],"summary":"Más URLs de partes (para seguir o retomar)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"x-oz-idempotente":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["numeros"],"properties":{"numeros":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"integer","minimum":1,"maximum":10000}}}}}}},"responses":{"200":{"description":"URLs","content":{"application/json":{"schema":{"type":"object","required":["subida_id","parte_bytes","total_partes","partes"],"properties":{"subida_id":{"$ref":"#/components/schemas/Uuid"},"parte_bytes":{"type":"integer"},"total_partes":{"type":"integer"},"partes":{"type":"array","items":{"$ref":"#/components/schemas/ParteFirmada"}}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/subidas/{id}/completar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"completarSubida","tags":["subidas"],"summary":"Cerrar la subida (idempotente)","description":"Crea el archivo o una versión nueva si el nombre ya existía. Repetirlo devuelve el mismo `Nodo`.\nEl `sha256` se guarda como declarado; la bóveda calcula el verificado después.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"x-oz-idempotente":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"partes":{"type":"array","maxItems":10000,"items":{"type":"object","required":["numero","etag"],"properties":{"numero":{"type":"integer","minimum":1,"maximum":10000},"etag":{"type":"string","minLength":1,"maxLength":200}}}},"sha256":{"$ref":"#/components/schemas/Sha256ONulo"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Archivo guardado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Nodo"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/subidas/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"delete":{"operationId":"cancelarSubida","tags":["subidas"],"summary":"Cancelar una subida abierta","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"responses":{"200":{"description":"Cancelada","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/operaciones/traer-url":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"traerUrl","tags":["subidas"],"summary":"Guardar un archivo desde una URL https (asíncrono; host desconocido → dos pasos)","description":"La API crea una operación y la VM baja el archivo con el lector seguro (solo https:443, IPs públicas, tamaño máximo)\ny lo sube por partes. Consulta el resultado con `verOperacion`. Si el host no es de una IA conocida ni está en la\nlista de la organización, responde `202 confirmacion_requerida` (la persona ve la URL completa y confirma).\nEN: save a file from an https URL (async); unknown hosts need human confirmation.\n","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:save","security":[{"llave":[]},{"oauth":["storage:save"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"Solo https, puerto 443, sin usuario ni clave"},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"carpeta_id":{"$ref":"#/components/schemas/Uuid","description":"Sin carpeta: la «Entrada IA» del espacio"},"nombre":{"type":"string","maxLength":255},"tipo_mime":{"type":"string","maxLength":200},"archivo_id":{"type":"string","maxLength":200,"description":"Id del archivo en la IA de origen (p. ej. ChatGPT)"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"202":{"description":"Operación creada, o espera confirmación","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ConfirmacionRequerida"},{"$ref":"#/components/schemas/OperacionCreada"}]}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/operaciones/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"verOperacion","tags":["subidas","confirmaciones"],"summary":"Estado de una operación (guardar desde URL o una confirmación pedida por una llave)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"Operación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Operacion"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarLinks","tags":["links"],"summary":"Links (más nuevos primero)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"name":"nodo_id","in":"query","schema":{"$ref":"#/components/schemas/Uuid"}},{"name":"estado","in":"query","schema":{"$ref":"#/components/schemas/EstadoLink"}},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página de links","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LinkConVisita"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"crearLink","tags":["links"],"summary":"Crear un link (la URL se muestra una sola vez)","description":"EN: create a share link; the URL is returned only once (only its hash is stored).","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:share","security":[{"llave":[]},{"oauth":["storage:share"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nodo_id"],"properties":{"nodo_id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"type":"string","enum":["descarga","vista","subida"],"default":"descarga"},"dias":{"type":"integer","minimum":1,"maximum":3650},"vence_en":{"$ref":"#/components/schemas/Fecha"},"clave":{"type":"string","minLength":8,"maxLength":200},"max_descargas":{"type":"integer","minimum":1,"maximum":1000000},"avisar":{"type":"boolean"},"pedir_datos":{"type":"boolean"},"verificar_correo":{"type":"boolean","default":true,"description":"Con pedir_datos, el correo se verifica con un código de 6 dígitos antes de bajar"},"nota":{"type":"string","maxLength":500},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"201":{"description":"Link creado","content":{"application/json":{"schema":{"type":"object","required":["link","url"],"properties":{"link":{"$ref":"#/components/schemas/Link"},"url":{"type":"string","format":"uri"}}}}}},"402":{"$ref":"#/components/responses/PlanNoAlcanza"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"verLink","tags":["links"],"summary":"Un link con su resumen de visitas","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"responses":{"200":{"description":"Link con resumen","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkDetalle"}}}},"default":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"cambiarLink","tags":["links"],"summary":"Ajustar vencimiento, clave, tope, avisos o nota","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:share","security":[{"llave":[]},{"oauth":["storage:share"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"vence_en":{"$ref":"#/components/schemas/Fecha"},"clave":{"type":["string","null"],"minLength":8,"maxLength":200},"max_descargas":{"type":["integer","null"],"minimum":1,"maximum":1000000},"avisar":{"type":"boolean"},"pedir_datos":{"type":"boolean"},"verificar_correo":{"type":"boolean"},"nota":{"type":["string","null"],"maxLength":500},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Link cambiado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/{id}/eventos":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"get":{"operationId":"eventosLink","tags":["links"],"summary":"Visitas y descargas de un link (más nuevas primero)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página de eventos","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EventoLink"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/{id}/pausar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"pausarLink","tags":["links"],"summary":"Pausar un link","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:share","x-oz-idempotente":true,"security":[{"llave":[]},{"oauth":["storage:share"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/{id}/reactivar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"reactivarLink","tags":["links"],"summary":"Reactivar un link pausado","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:share","x-oz-idempotente":true,"security":[{"llave":[]},{"oauth":["storage:share"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/{id}/cortar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"cortarLink","tags":["links"],"summary":"Cortar un link (definitivo)","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:share","security":[{"llave":[]},{"oauth":["storage:share"]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Link cortado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/links/cortar":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"cortarLinks","tags":["links"],"summary":"Cortar varios links (más de 5, en dos pasos)","x-oz-llaves":["api"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"link_ids":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/Uuid"}},"nodo_id":{"$ref":"#/components/schemas/Uuid"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"$ref":"#/components/responses/LinksCortados"},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/nodos/{id}/links/cortar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"post":{"operationId":"cortarLinksDeNodo","tags":["links"],"summary":"Cortar todos los links de una carpeta y lo de adentro (dos pasos)","x-oz-llaves":["api"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"$ref":"#/components/responses/LinksCortados"},"202":{"$ref":"#/components/responses/ConfirmacionRequerida"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/uso":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verUso","tags":["costos"],"summary":"Bytes por nivel y costo del mes (admins)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"responses":{"200":{"description":"Uso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Uso"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/uso/niveles":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verUsoNiveles","tags":["costos"],"summary":"Bytes y archivos por nivel de los espacios que ve la persona (sin costos)","description":"Caliente, archivando, frío y despertando: archivos vivos y sus bytes, en total y por espacio. Quien no es admin\nsolo suma los espacios que ve. Sin costos ni cobros (eso es `GET /uso`, solo admins). Lo usan el pie del panel de\nOZ Storage para Mac y el iPhone. EN: bytes and files per tier for the spaces the person can see.\n","x-oz-llaves":["api","dispositivo"],"responses":{"200":{"description":"Uso por nivel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsoNiveles"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/plan/aviso":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verAvisoPlan","tags":["costos"],"summary":"La franja del plan para todo el equipo (prueba, gracia, cancelada, solo lectura o bajadas del mes)","description":"Solo lectura: lo que la web, OZ Storage para Mac y el iPhone muestran arriba. `aviso` es null si no hay nada que\ndecir. `bajadas`: con plan pagado, lo bajado del mes pasó el 80 % de lo gratis (3× lo caliente). Pagar, cambiar o\ncancelar el plan es solo en la web (`url_plan`), con sesión. EN: the plan banner shown to the whole team.\n","x-oz-llaves":["dispositivo"],"responses":{"200":{"description":"La franja","content":{"application/json":{"schema":{"type":"object","required":["aviso","puede_pagar","solo_lectura","url_plan"],"properties":{"aviso":{"oneOf":[{"type":"null"},{"type":"object","required":["tipo","texto","hasta"],"properties":{"tipo":{"type":"string","enum":["prueba","en_gracia","solo_lectura","salida_cerrada","cancelada","bajadas"]},"texto":{"type":"string"},"hasta":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Fecha"}]}}}]},"puede_pagar":{"type":"boolean","description":"Dueño o admin (en la web)"},"solo_lectura":{"type":"boolean"},"url_plan":{"type":"string","description":"«Plan y pagos» en la web"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/dispositivos/push":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"put":{"operationId":"registrarPush","tags":["identidad"],"summary":"Registrar el token de APNs de esta app (OZ Storage para iPhone o Mac) para recibir avisos push","description":"Idempotente por token. Lo que la persona recibe por WhatsApp (aprobaciones, códigos por confirmar, freno de borrado,\nproyecto despertado…) le llega también como push a este equipo mientras su llave siga viva.\n","x-oz-llaves":["dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token","plataforma","apns","bundle"],"properties":{"token":{"type":"string","pattern":"^[0-9a-fA-F]{64,200}$"},"plataforma":{"type":"string","enum":["ios","macos"]},"apns":{"type":"string","enum":["sandbox","produccion"]},"bundle":{"type":"string","description":"Bundle id de la app (com.agenciaoz.…)"}}}}}},"responses":{"200":{"description":"Registrado","content":{"application/json":{"schema":{"type":"object","required":["id","registrado"],"properties":{"id":{"type":"string","format":"uuid"},"registrado":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"quitarPush","tags":["identidad"],"summary":"Dejar de recibir avisos push en esta app","x-oz-llaves":["dispositivo"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Hecho","content":{"application/json":{"schema":{"type":"object","required":["quitado"],"properties":{"quitado":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/registro":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verRegistro","tags":["auditoria"],"summary":"Registro de auditoría (admins; más nuevo primero)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"parameters":[{"name":"persona_id","in":"query","schema":{"$ref":"#/components/schemas/Uuid"}},{"name":"objeto_tipo","in":"query","schema":{"type":"string","maxLength":50}},{"name":"objeto_id","in":"query","schema":{"type":"string","maxLength":100}},{"name":"accion","in":"query","description":"Acepta prefijo con `*` (p. ej. `nodo.*`)","schema":{"type":"string","maxLength":80}},{"name":"desde","in":"query","schema":{"$ref":"#/components/schemas/Fecha"}},{"name":"hasta","in":"query","schema":{"$ref":"#/components/schemas/Fecha"}},{"name":"conexion_id","in":"query","description":"Solo lo que hizo esa conexión de IA (todas las llaves de la familia OAuth) o esa llave de agente","schema":{"$ref":"#/components/schemas/Uuid"}},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página del registro","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LineaRegistro"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/registro/verificar":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verificarRegistro","tags":["auditoria"],"summary":"Verificar la cadena de huellas del registro","x-oz-llaves":["api"],"parameters":[{"name":"completa","in":"query","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Resultado","content":{"application/json":{"schema":{"type":"object","required":["sana","primer_roto","revisadas"],"properties":{"sana":{"type":"boolean"},"primer_roto":{"type":["string","null"]},"revisadas":{"type":"integer"},"completa":{"type":"boolean"},"desde_sello":{"type":["object","null"]}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/salud":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"saludOrg","tags":["auditoria"],"summary":"Salud de la organización (base, cola, respaldos, proveedores)","x-oz-llaves":["mcp","agente","api"],"x-oz-scope":"storage:admin","security":[{"llave":[]},{"oauth":["storage:admin"]}],"responses":{"200":{"description":"Salud","content":{"application/json":{"schema":{"type":"object","required":["base","cola","respaldos","proveedores","version"],"properties":{"base":{"type":"object"},"cola":{"type":"array"},"respaldos":{"type":"array"},"proveedores":{"type":"object"},"version":{"type":"string"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/llaves":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarLlaves","tags":["llaves"],"summary":"Mis llaves (con una llave, solo las de su persona)","description":"Crear llaves es solo desde la web con passkey. Las llaves `mcp` no usan esta ruta.","x-oz-llaves":["api","dispositivo"],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limite"}],"responses":{"200":{"description":"Página de llaves","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Llave"}}}}]}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/llaves/{id}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/id"}],"delete":{"operationId":"revocarLlave","tags":["llaves"],"summary":"Revocar una llave propia (la misma llave = salir)","x-oz-llaves":["api","dispositivo"],"x-oz-idempotente":true,"responses":{"200":{"description":"Revocada","content":{"application/json":{"schema":{"type":"object","required":["id","revocada"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"revocada":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/confirmaciones":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarConfirmaciones","tags":["confirmaciones","costos"],"summary":"Lo pendiente con su botón «Aprobar» (solo OZ Storage para Mac / iPhone / sesión)","description":"Aprobaciones de gasto pendientes (`tipo: aprobacion`): a dueños y admins, todas las de la organización; a los demás,\nlas que pidieron, sin poder decidir. Con la llave `dispositivo`, además los códigos comunes de la **misma persona**\npedidos por cualquier canal (Claude, la web, la Mac, el iPhone) (`tipo: confirmacion`), para aprobarlos con\nFace ID / Touch ID (`POST /confirmaciones/{codigo}` con `assertion`). Lo más nuevo primero.\n","x-oz-llaves":["dispositivo"],"parameters":[{"name":"estado","in":"query","required":false,"schema":{"const":"pendiente"},"description":"Solo hay «pendiente»"},{"name":"limite","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"Pendientes","content":{"application/json":{"schema":{"type":"object","required":["items","siguiente"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Pendiente"}},"siguiente":{"type":"null"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/confirmaciones/{codigo}":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/codigo"}],"post":{"operationId":"confirmar","tags":["confirmaciones"],"summary":"Confirmar un código (llaves `mcp` y `api` → siempre 403)","description":"El segundo paso lo da una persona: en la web con passkey o en OZ Storage para Mac con `assertion` (Touch ID). Una llave\n`mcp` o `api` recibe **siempre** 403: los SDK no exponen esta operación para esas llaves; muestran el código y\nel enlace `https://app.ozstorage.app/confirmar?codigo=…` para que la persona confirme.\nEN: keys of type `mcp`/`api` can never confirm (always 403). A human confirms in the web app with a passkey.\n","x-oz-llaves":["mcp","agente","api","dispositivo"],"x-oz-scope":"storage:read","security":[{"llave":[]},{"oauth":["storage:read"]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"assertion":{"type":"object","description":"Aserción WebAuthn (solo OZ Storage para Mac)"},"motivo":{"$ref":"#/components/schemas/Motivo"}}}}}},"responses":{"200":{"description":"Lo que habría respondido la acción","content":{"application/json":{"schema":{"type":"object"}}}},"201":{"description":"Lo que habría respondido la acción","content":{"application/json":{"schema":{"type":"object"}}}},"202":{"description":"Lo que habría respondido la acción","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Llave que no puede confirmar, o no es quien decide","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/confirmaciones/{codigo}/rechazar":{"parameters":[{"$ref":"#/components/parameters/orgId"},{"$ref":"#/components/parameters/codigo"}],"post":{"operationId":"rechazarConfirmacion","tags":["confirmaciones"],"summary":"Rechazar un código pendiente (solo OZ Storage para Mac / sesión)","x-oz-llaves":["dispositivo"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Rechazada","content":{"application/json":{"schema":{"type":"object","required":["accion","rechazada"],"properties":{"accion":{"type":"string"},"rechazada":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/costos":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verCostos","tags":["costos"],"summary":"Gasto estimado de hoy y del mes, topes, alertas y aprobaciones (dueños y admins)","x-oz-llaves":["api","dispositivo"],"responses":{"200":{"description":"Costos (USD estimados; día y mes en hora de Guayaquil)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Costos"}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/costos/resumen":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"resumenCostos","tags":["costos"],"summary":"Alertas sin ver y aprobaciones pendientes (ceros si no es admin)","x-oz-llaves":["api","dispositivo"],"responses":{"200":{"description":"Resumen","content":{"application/json":{"schema":{"type":"object","required":["alertas_sin_ver","aprobaciones_pendientes","ultimas_alertas"],"properties":{"alertas_sin_ver":{"type":"integer"},"aprobaciones_pendientes":{"type":"integer"},"ultimas_alertas":{"type":"array","items":{"type":"object"}}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/costos/alertas/vistas":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"post":{"operationId":"marcarAlertasVistas","tags":["costos"],"summary":"Marcar las alertas de costo como vistas (OZ Storage para Mac)","x-oz-llaves":["dispositivo"],"x-oz-idempotente":true,"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConMotivo"}}}},"responses":{"200":{"description":"Cuántas","content":{"application/json":{"schema":{"type":"object","required":["vistas"],"properties":{"vistas":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/cursor":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"verCursor","tags":["cambios"],"summary":"Cursor actual del diario (pedirlo ANTES de enumerar todo)","x-oz-llaves":["agente","api","dispositivo"],"x-oz-scope":"storage:read","responses":{"200":{"description":"Cursor","content":{"application/json":{"schema":{"type":"object","required":["cursor"],"properties":{"cursor":{"type":"string"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/cambios":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"listarCambios","tags":["cambios"],"summary":"Cambios desde un cursor (410 `cursor_vencido` si es muy viejo)","description":"EN: change feed since a cursor; 410 means re-enumerate from GET /cursor.","x-oz-llaves":["agente","api","dispositivo"],"x-oz-scope":"storage:read","parameters":[{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"limite","in":"query","schema":{"type":"integer","minimum":1,"maximum":2000,"default":500}},{"name":"espacios","in":"query","description":"`1`: también los cambios de los espacios (`tipo: espacio`, con `espacio_id` y `espacio`; `nodo_id` null).","schema":{"type":"string","enum":["1","true"]}}],"responses":{"200":{"description":"Cambios","content":{"application/json":{"schema":{"type":"object","required":["cambios","cursor","hay_mas"],"properties":{"cambios":{"type":"array","items":{"type":"object","required":["seq","tipo","nodo_id"],"properties":{"seq":{"type":"string"},"tipo":{"type":"string","enum":["creado","modificado","movido","papelera","restaurado","borrado","nivel","espacio"]},"nodo_id":{"oneOf":[{"$ref":"#/components/schemas/Uuid"},{"type":"null"}]},"nodo":{"oneOf":[{"$ref":"#/components/schemas/Nodo"},{"type":"null"}]},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"espacio":{"oneOf":[{"$ref":"#/components/schemas/Espacio"},{"type":"null"}]}}}},"cursor":{"type":"string"},"hay_mas":{"type":"boolean"}}}}}},"410":{"$ref":"#/components/responses/Error"},"default":{"$ref":"#/components/responses/Error"}}}},"/v1/orgs/{orgId}/cambios/esperar":{"parameters":[{"$ref":"#/components/parameters/orgId"}],"get":{"operationId":"esperarCambios","tags":["cambios"],"summary":"Espera larga (hasta 60 s) a que haya cambios visibles","x-oz-llaves":["agente","api","dispositivo"],"x-oz-scope":"storage:read","parameters":[{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"segundos","in":"query","schema":{"type":"integer","minimum":1,"maximum":60,"default":60}}],"responses":{"200":{"description":"¿Hay cambios?","content":{"application/json":{"schema":{"type":"object","required":["hay_cambios"],"properties":{"hay_cambios":{"type":"boolean"}}}}}},"default":{"$ref":"#/components/responses/Error"}}}}},"webhooks":{"archivo.creado":{"post":{"operationId":"webhook_archivo_creado","summary":"Se creó un archivo (subida, link de subida, guardar desde URL o una IA)","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"archivo.creado"},"data":{"type":"object","required":["nodo"],"properties":{"nodo":{"$ref":"#/components/schemas/NodoEvento"},"por":{"$ref":"#/components/schemas/PorEvento"},"cambio":{"type":"string","enum":["version","nombre","ubicacion","version_restaurada"]}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"archivo.actualizado":{"post":{"operationId":"webhook_archivo_actualizado","summary":"Versión nueva, renombrado o movido","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"archivo.actualizado"},"data":{"type":"object","required":["nodo"],"properties":{"nodo":{"$ref":"#/components/schemas/NodoEvento"},"por":{"$ref":"#/components/schemas/PorEvento"},"cambio":{"type":"string","enum":["version","nombre","ubicacion","version_restaurada"]}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"archivo.papelera":{"post":{"operationId":"webhook_archivo_papelera","summary":"Algo se mandó a la papelera","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"archivo.papelera"},"data":{"type":"object","required":["nodo"],"properties":{"nodo":{"$ref":"#/components/schemas/NodoEvento"},"por":{"$ref":"#/components/schemas/PorEvento"},"cambio":{"type":"string","enum":["version","nombre","ubicacion","version_restaurada"]}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"subida.completada":{"post":{"operationId":"webhook_subida_completada","summary":"Terminó una subida","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"subida.completada"},"data":{"type":"object","required":["nodo"],"properties":{"nodo":{"$ref":"#/components/schemas/NodoEvento"},"por":{"$ref":"#/components/schemas/PorEvento"},"cambio":{"type":"string","enum":["version","nombre","ubicacion","version_restaurada"]}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"link.visitado":{"post":{"operationId":"webhook_link_visitado","summary":"Abrieron un link (agrupado por lote, sin IP ni datos del visitante)","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"link.visitado"},"data":{"type":"object","required":["link","veces"],"properties":{"link":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string"},"nodo_id":{"type":"string"},"nodo_nombre":{"type":"string"}}},"veces":{"type":"integer","description":"Cuántas en este lote"},"pais":{"type":["string","null"]},"ocurrido_en":{"type":"string"},"bytes":{"type":"integer"}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"link.descargado":{"post":{"operationId":"webhook_link_descargado","summary":"Bajaron completo un archivo de un link","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"link.descargado"},"data":{"type":"object","required":["link","veces"],"properties":{"link":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string"},"nodo_id":{"type":"string"},"nodo_nombre":{"type":"string"}}},"veces":{"type":"integer","description":"Cuántas en este lote"},"pais":{"type":["string","null"]},"ocurrido_en":{"type":"string"},"bytes":{"type":"integer"}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"aprobacion.pedida":{"post":{"operationId":"webhook_aprobacion_pedida","summary":"Se pidió aprobar un gasto","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"aprobacion.pedida"},"data":{"type":"object","required":["aprobacion"],"properties":{"aprobacion":{"type":"object","additionalProperties":true},"por":{"type":"object","additionalProperties":true}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"aprobacion.decidida":{"post":{"operationId":"webhook_aprobacion_decidida","summary":"Un admin aprobó o rechazó un gasto","description":"Firmado con Standard Webhooks: `webhook-id` (el mismo en cada reintento), `webhook-timestamp` (segundos unix del\nintento; rechazar si difiere más de 5 min) y `webhook-signature: v1,<base64 HMAC-SHA256(secreto, \"id.timestamp.cuerpo\")>`.\nResponder 2xx en menos de 10 s; si no, se reintenta (10 intentos en ~24 h) y, tras 25 fallos seguidos, se desactiva.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"aprobacion.decidida"},"data":{"type":"object","required":["aprobacion"],"properties":{"aprobacion":{"type":"object","additionalProperties":true},"por":{"type":"object","additionalProperties":true}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"proxy.listo":{"post":{"operationId":"webhook_proxy_listo","summary":"El proxy de un video quedó listo (del servidor, de la Mac de OZ o uno subido)","description":"Firmado con Standard Webhooks, como los demás (ver `archivo.creado`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"proxy.listo"},"data":{"type":"object","required":["nodo","proxy"],"properties":{"nodo":{"type":"object","additionalProperties":true},"version_id":{"type":["string","null"]},"proxy":{"type":"object","additionalProperties":true,"description":"origen (servidor | mac_oz | subido), nodo_id, duracion_seg, tamano, automatico"}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"espacio.despertado":{"post":{"operationId":"webhook_espacio_despertado","summary":"Un proyecto, una carpeta o un archivo volvió del frío: ya se puede abrir","description":"Firmado con Standard Webhooks, como los demás (ver `archivo.creado`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"espacio.despertado"},"data":{"type":"object","required":["espacio"],"properties":{"espacio":{"type":"object","additionalProperties":true},"nodo":{"type":["object","null"],"additionalProperties":true},"archivos":{"type":"integer"},"bytes":{"type":"integer"}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"espacio.archivado":{"post":{"operationId":"webhook_espacio_archivado","summary":"Un proyecto, una carpeta o un archivo pasó a frío (a mano o por «al subir: frío»)","description":"Firmado con Standard Webhooks, como los demás (ver `archivo.creado`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"espacio.archivado"},"data":{"type":"object","required":["espacio"],"properties":{"espacio":{"type":"object","additionalProperties":true},"nodo":{"type":["object","null"],"additionalProperties":true},"archivos":{"type":"integer"},"bytes":{"type":"integer"},"automatico":{"type":"boolean"}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}},"operacion.terminada":{"post":{"operationId":"webhook_operacion_terminada","summary":"Terminó una operación larga (p. ej. guardar desde una URL): hecha o fallida","description":"Firmado con Standard Webhooks, como los demás (ver `archivo.creado`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/EventoWebhook"},{"type":"object","properties":{"type":{"const":"operacion.terminada"},"data":{"type":"object","required":["operacion"],"properties":{"operacion":{"type":"object","additionalProperties":true,"description":"id, tipo, estado (hecha | fallida), error, host"},"resultado":{"type":["object","null"],"additionalProperties":true}}}}}]}}}},"responses":{"2XX":{"description":"Recibido"}}}}},"components":{"securitySchemes":{"llave":{"type":"http","scheme":"bearer","bearerFormat":"ozk_<token>","description":"Llave de OZ Storage (`Authorization: Bearer ozk_…`), atada a una persona y una organización; vence.\nTipos: `api` (integraciones; la crea un dueño o admin en la web con passkey), `dispositivo` (OZ Storage para Mac, la CLI\n`oz` cuando se conecta como dispositivo), `mcp` (IAs conectadas por OAuth, con scopes) y `agente` (fase 2: llave\nde larga vida —hasta 1 año— para agentes y automatizaciones como n8n o Zapier; la crea un dueño o admin en la web\ncon passkey, con scopes, espacios y «solo en la entrada» como una conexión de IA, y su cupo diario; sirve en esta\nAPI y como bearer en el MCP; además de lo de `mcp` lee el diario de cambios). Lo que puede cada tipo está en\n`x-oz-llaves` de cada operación y, para `mcp` y `agente`, el scope en `x-oz-scope`. Vencida o revocada → 401; en\npausa por el freno de borrado → 403.\n"},"oauth":{"type":"oauth2","description":"Código de autorización con PKCE S256 y `resource` = URL del MCP. Clientes públicos (sin secreto): registro\ndinámico o Client ID Metadata Document. El token es una llave `mcp` de 24 h con los scopes concedidos.\n","flows":{"authorizationCode":{"authorizationUrl":"https://api.ozstorage.app/oauth/authorize","tokenUrl":"https://api.ozstorage.app/oauth/token","refreshUrl":"https://api.ozstorage.app/oauth/token","scopes":{"storage:read":"Ver espacios, carpetas, archivos (metadatos), buscar, papelera y links con visitas","storage:save":"Crear carpetas y agregar archivos nuevos","storage:organize":"Mover, renombrar, papelera, restaurar y volver a una versión","storage:share":"Crear, ajustar, pausar y cortar links","storage:content":"Leer el contenido de archivos chicos (texto) y ver su miniatura, por URL firmada","storage:admin":"Uso y costos, registro, equipo, invitar, archivar y despertar"}}}}},"parameters":{"orgId":{"name":"orgId","in":"path","required":true,"description":"Organización (la de la llave; ver `GET /auth/yo`)","schema":{"$ref":"#/components/schemas/Uuid"}},"id":{"name":"id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Uuid"}},"codigo":{"name":"codigo","in":"path","required":true,"schema":{"type":"string","pattern":"^OZS-[2-9A-Z]{6}$"}},"cursor":{"name":"cursor","in":"query","description":"Cursor opaco de la página anterior (`siguiente`)","schema":{"type":"string"}},"limite":{"name":"limite","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"idempotencyKey":{"name":"Idempotency-Key","in":"header","description":"Clave de idempotencia de una escritura (la misma respuesta durante 24 h)","schema":{"type":"string","minLength":1,"maxLength":200}},"motivo":{"name":"X-OZ-Motivo","in":"header","description":"Motivo del cambio (codificado para URL). También va en el cuerpo como `motivo`.","schema":{"type":"string"}}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NoAutenticado":{"description":"Llave ausente, vencida o revocada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ErrorOAuth":{"description":"Error con forma OAuth","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}},"PlanNoAlcanza":{"description":"La organización está en solo lectura (`cuenta_solo_lectura`) o esto no cabe en su plan (`cupo_excedido`). No se hizo nada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ConfirmacionRequerida":{"description":"Acción delicada; no se hizo. La persona la confirma en la web o en OZ Storage para Mac.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmacionRequerida"}}}},"PaginaEspacios":{"description":"Página de espacios","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Espacio"}}}}]}}}},"PaginaNodos":{"description":"Página de archivos y carpetas","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Pagina"},{"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Nodo"}}}}]}}}},"LinksCortados":{"description":"Links cortados","content":{"application/json":{"schema":{"type":"object","required":["cortados","link_ids"],"properties":{"cortados":{"type":"integer"},"link_ids":{"type":"array","items":{"$ref":"#/components/schemas/Uuid"}}}}}}}},"schemas":{"Uuid":{"type":"string","format":"uuid"},"UuidONulo":{"type":["string","null"],"format":"uuid"},"Fecha":{"type":"string","format":"date-time","description":"ISO 8601 en UTC (en pantalla: hora de Guayaquil)"},"FechaONula":{"type":["string","null"],"format":"date-time"},"Sha256ONulo":{"type":["string","null"],"pattern":"^[0-9a-fA-F]{64}$"},"Motivo":{"type":"string","maxLength":1000,"description":"Por qué (queda en el registro). Obligatorio para llaves mcp."},"ConMotivo":{"type":"object","properties":{"motivo":{"$ref":"#/components/schemas/Motivo"}}},"ConMotivoObligatorio":{"type":"object","required":["motivo"],"properties":{"motivo":{"type":"string","minLength":1,"maxLength":1000}}},"Nivel":{"type":"string","enum":["caliente","archivando","frio","despertando"]},"EstadoLink":{"type":"string","enum":["activo","pausado","cortado","vencido","agotado"]},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["codigo","mensaje"],"properties":{"codigo":{"type":"string","examples":["no_autenticado","sin_permiso","no_existe","conflicto","en_frio","invalido","limite","alcance_insuficiente","cuenta_solo_lectura","cupo_excedido"]},"mensaje":{"type":"string"}}},"scope_requerido":{"type":"string","description":"Con `alcance_insuficiente`"},"plan":{"description":"Con `cuenta_solo_lectura`","type":"object","properties":{"estado":{"type":"string","enum":["solo_lectura"]},"motivo":{"type":["string","null"]}}},"cupo":{"description":"Con `cupo_excedido`: bytes usados, contratados y pedidos","type":"object","properties":{"tipo":{"type":"string","enum":["caliente","frio"]},"usado_bytes":{"type":"integer"},"contratado_bytes":{"type":"integer"},"pedido_bytes":{"type":"integer"}}},"nodo":{"description":"Con `conflicto_version`: el nodo actual","oneOf":[{"$ref":"#/components/schemas/Nodo"},{"type":"null"}]}},"additionalProperties":true},"Pagina":{"type":"object","required":["items","siguiente"],"properties":{"items":{"type":"array"},"siguiente":{"type":["string","null"],"description":"Cursor de la página siguiente; null = no hay más"}}},"ConfirmacionRequerida":{"type":"object","required":["error","confirmacion"],"properties":{"error":{"type":"object","required":["codigo","mensaje"],"properties":{"codigo":{"const":"confirmacion_requerida"},"mensaje":{"type":"string"}}},"confirmacion":{"type":"object","required":["codigo","resumen","vence_en"],"properties":{"codigo":{"type":"string","pattern":"^OZS-[2-9A-Z]{6}$"},"resumen":{"type":"string"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"tipo":{"type":"string","enum":["aprobacion"],"description":"Presente si es una aprobación de gasto"},"confirm_url":{"type":"string","format":"uri","description":"Enlace para que la persona confirme en la web con su passkey"},"operacion_id":{"$ref":"#/components/schemas/Uuid"}}},"aprobacion":{"$ref":"#/components/schemas/Aprobacion"}}},"AprobacionRequerida":{"type":"object","required":["error","aprobacion"],"properties":{"error":{"type":"object","required":["codigo","mensaje"],"properties":{"codigo":{"const":"aprobacion_requerida"},"mensaje":{"type":"string"}}},"aprobacion":{"$ref":"#/components/schemas/Aprobacion"}}},"Aprobacion":{"type":"object","required":["id","codigo","resumen","estimado_usd","motivos","vence_en","operacion","reintentar"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"codigo":{"type":"string"},"resumen":{"type":"string"},"estimado_usd":{"type":"number"},"motivos":{"type":"array","items":{"type":"string"}},"vence_en":{"$ref":"#/components/schemas/Fecha"},"operacion":{"type":"string","examples":["bajar","despertar"]},"reintentar":{"type":"boolean","description":"true: aprobada, se repite el pedido y pasa una vez"},"nueva":{"type":"boolean"},"confirm_url":{"type":"string","format":"uri"}}},"DestinoEntrada":{"type":"string","enum":["entrada"],"description":"`entrada` = la carpeta «Entrada IA» del espacio (se crea si no existe); no va junto con `padre_id`"},"Operacion":{"type":"object","required":["id","tipo","estado"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"type":"string","enum":["traer_url","confirmacion"]},"host":{"type":["string","null"],"description":"traer_url: el host de la URL (nunca la URL completa)"},"espacio_id":{"$ref":"#/components/schemas/UuidONulo"},"carpeta_id":{"$ref":"#/components/schemas/UuidONulo"},"estado":{"type":"string","enum":["esperando_confirmacion","pendiente","corriendo","hecha","fallida","rechazada","vencida"]},"accion":{"type":["string","null"]},"resumen":{"type":["string","null"]},"resultado":{"description":"Lo que hizo (p. ej. el Nodo guardado)"},"error":{"type":["string","null"]},"vence_en":{"$ref":"#/components/schemas/FechaONula"},"creada_en":{"$ref":"#/components/schemas/Fecha"},"actualizada_en":{"$ref":"#/components/schemas/Fecha"},"terminada_en":{"$ref":"#/components/schemas/FechaONula"}},"additionalProperties":true},"OperacionCreada":{"type":"object","required":["operacion"],"properties":{"operacion":{"$ref":"#/components/schemas/Operacion"}},"additionalProperties":true},"TareaEncolada":{"type":"object","required":["tarea_id","bytes"],"properties":{"tarea_id":{"type":"string"},"bytes":{"type":"integer"}}},"TareaNivel":{"type":"object","description":"Mandar a frío o despertar una carpeta o un archivo, encolado (lo hace la tarea en segundo plano)","required":["tarea_id","archivos","bytes"],"properties":{"tarea_id":{"type":"string"},"archivos":{"type":"integer"},"bytes":{"type":"integer"}}},"TextosAviso":{"type":"object","required":["titulo","resumen","puntos","boton","boton_pedir"],"properties":{"titulo":{"type":"string"},"resumen":{"type":"string"},"puntos":{"type":"array","items":{"type":"string"}},"boton":{"type":"string"},"boton_pedir":{"type":["string","null"],"description":"Texto del botón para pedírselo a un admin (solo si `puede_pedir`)"}}},"AvisoFrio":{"type":"object","description":"Aviso antes de mandar a frío o despertar (docs/api.md § «Frío»). Todo en bytes y USD; fechas en UTC.","required":["accion","objeto","archivos","bytes","ya","en_curso","puede","puede_pedir","motivo_no_puede","requiere_confirmacion","requiere_aprobacion","solo_lectura","costo_mes","cobro_minimo","despertar","cupo_frio","textos"],"properties":{"accion":{"type":"string","enum":["archivar","despertar"]},"objeto":{"type":"object","required":["tipo","id","nombre","ruta","espacio_id","espacio_nombre","nivel","nivel_desde"],"properties":{"tipo":{"type":"string","enum":["espacio","carpeta","archivo"]},"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"ruta":{"type":["string","null"]},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"espacio_nombre":{"type":"string"},"nivel":{"type":["string","null"]},"nivel_desde":{"$ref":"#/components/schemas/FechaONula"}}},"archivos":{"type":"integer","description":"Los que cambiarían de nivel"},"bytes":{"type":"integer"},"ya":{"type":"object","description":"Lo de adentro que ya está en el otro nivel (se salta)","required":["archivos","bytes"],"properties":{"archivos":{"type":"integer"},"bytes":{"type":"integer"}}},"en_curso":{"type":"boolean"},"puede":{"type":"boolean"},"puede_pedir":{"type":"boolean"},"motivo_no_puede":{"type":["string","null"]},"requiere_confirmacion":{"type":"boolean","description":"Pide código OZS (más de 20 archivos o 50 GB)"},"requiere_aprobacion":{"type":"boolean","description":"Despertar con un costo que aprueba un dueño o admin"},"solo_lectura":{"type":"boolean"},"costo_mes":{"type":"object","required":["caliente_usd","frio_usd","ahorro_usd","precio_tb","base"],"properties":{"caliente_usd":{"type":"number"},"frio_usd":{"type":"number"},"ahorro_usd":{"type":"number"},"precio_tb":{"type":"object","required":["caliente","frio"],"properties":{"caliente":{"type":"number"},"frio":{"type":"number"}}},"base":{"type":"string","enum":["lista_de_precios"]}}},"cobro_minimo":{"type":"object","required":["dias","hasta"],"properties":{"dias":{"type":"integer"},"hasta":{"$ref":"#/components/schemas/FechaONula"}}},"despertar":{"type":"object","required":["horas_aprox","horas_max","bytes_boveda","con_plan","gratis_mes_bytes","ya_despertado_mes_bytes","cargo_extra_bytes","cargo_extra_usd","precio_extra_tb_usd"],"properties":{"horas_aprox":{"type":"number"},"horas_max":{"type":"number"},"bytes_boveda":{"type":"integer"},"con_plan":{"type":"boolean"},"gratis_mes_bytes":{"type":["integer","null"]},"ya_despertado_mes_bytes":{"type":["integer","null"]},"cargo_extra_bytes":{"type":"integer"},"cargo_extra_usd":{"type":"number"},"precio_extra_tb_usd":{"type":"number"}}},"cupo_frio":{"type":["object","null"],"required":["contratado_bytes","usado_bytes","despues_bytes","cabe"],"properties":{"contratado_bytes":{"type":"integer"},"usado_bytes":{"type":"integer"},"despues_bytes":{"type":"integer"},"cabe":{"type":"boolean"}}},"textos":{"type":"object","required":["es","en"],"properties":{"es":{"$ref":"#/components/schemas/TextosAviso"},"en":{"$ref":"#/components/schemas/TextosAviso"}}}}},"TextosAlSubir":{"type":"object","required":["titulo","resumen","puntos","boton","boton_quitar"],"properties":{"titulo":{"type":"string"},"resumen":{"type":"string"},"puntos":{"type":"array","items":{"type":"string"}},"boton":{"type":"string"},"boton_quitar":{"type":"string"}}},"AvisoAlSubir":{"type":"object","description":"Aviso antes de poner «al subir, mandar a frío» (docs/api.md § «Al subir»). Bytes y USD.","required":["accion","objeto","al_subir","heredada","espera_min","ya","puede","motivo_no_puede","puede_quitar","solo_lectura","costo_tb_mes","cobro_minimo","despertar","cupo_frio","textos"],"properties":{"accion":{"type":"string","enum":["al_subir"]},"objeto":{"type":"object","required":["tipo","id","nombre","ruta","espacio_id","espacio_nombre"],"properties":{"tipo":{"type":"string","enum":["espacio","carpeta"]},"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"ruta":{"type":["string","null"]},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"espacio_nombre":{"type":"string"}}},"al_subir":{"$ref":"#/components/schemas/AlSubir"},"heredada":{"oneOf":[{"$ref":"#/components/schemas/ReglaAlSubir"},{"type":"null"}]},"espera_min":{"type":"integer","description":"Minutos que espera cada archivo después de terminar de subir"},"ya":{"type":"object","description":"Lo caliente que ya está adentro (no se toca)","required":["archivos","bytes"],"properties":{"archivos":{"type":"integer"},"bytes":{"type":"integer"}}},"puede":{"type":"boolean"},"motivo_no_puede":{"type":["string","null"]},"puede_quitar":{"type":"boolean"},"solo_lectura":{"type":"boolean"},"costo_tb_mes":{"type":"object","required":["caliente_usd","frio_usd","ahorro_usd","base"],"properties":{"caliente_usd":{"type":"number"},"frio_usd":{"type":"number"},"ahorro_usd":{"type":"number"},"base":{"type":"string","enum":["lista_de_precios"]}}},"cobro_minimo":{"type":"object","required":["dias"],"properties":{"dias":{"type":"integer"}}},"despertar":{"type":"object","required":["horas_aprox","horas_max","con_plan","gratis_pct","precio_extra_tb_usd"],"properties":{"horas_aprox":{"type":"number"},"horas_max":{"type":"number"},"con_plan":{"type":"boolean"},"gratis_pct":{"type":"number"},"precio_extra_tb_usd":{"type":"number"}}},"cupo_frio":{"type":["object","null"],"required":["contratado_bytes","usado_bytes","libre_bytes"],"properties":{"contratado_bytes":{"type":"integer"},"usado_bytes":{"type":"integer"},"libre_bytes":{"type":"integer"}}},"textos":{"type":"object","required":["es","en"],"properties":{"es":{"$ref":"#/components/schemas/TextosAlSubir"},"en":{"$ref":"#/components/schemas/TextosAlSubir"}}}}},"YoLlave":{"type":"object","required":["persona","organizacion","llave"],"properties":{"persona":{"type":"object","required":["id","correo","nombre"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"correo":{"type":"string"},"nombre":{"type":"string"}}},"organizacion":{"type":"object","required":["id","nombre","rol"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"rol":{"type":"string","enum":["dueno","admin","miembro","externo"]},"idioma":{"type":"string","enum":["es","en"]}}},"llave":{"type":"object","required":["id","tipo"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"type":"string","enum":["mcp","agente","api","dispositivo"]},"nombre":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"recurso":{"type":["string","null"]}}}}},"Espacio":{"type":"object","required":["id","nombre","estado","rol","tamano","nivel"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"prefijo":{"type":"string"},"estado":{"type":"string","enum":["activo","entregado","archivado"]},"entregado_en":{"$ref":"#/components/schemas/FechaONula"},"dias_para_frio":{"type":"integer"},"confidencial":{"type":"boolean"},"creado_en":{"$ref":"#/components/schemas/Fecha"},"rol":{"type":["string","null"],"enum":["admin","editor","lector",null]},"tamano":{"type":"integer","description":"Bytes de sus archivos vivos"},"nivel":{"type":"string","enum":["caliente","frio","mixto","despertando"]},"pasa_a_frio_en":{"$ref":"#/components/schemas/FechaONula"},"al_subir":{"$ref":"#/components/schemas/AlSubir"}}},"AlSubir":{"type":["string","null"],"enum":["frio",null],"description":"Regla «al subir» (null = lo que se sube queda caliente; `frio` = pasa a frío al terminar de subir)"},"NodoBase":{"type":"object","description":"Campos comunes de un archivo o carpeta (sin `links_activos`, que cambia de forma según la ruta)","required":["id","espacio_id","padre_id","tipo","nombre","ruta","tamano","sha256","nivel","modificado_en","version_id"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"padre_id":{"$ref":"#/components/schemas/UuidONulo"},"tipo":{"type":"string","enum":["carpeta","archivo"]},"nombre":{"type":"string"},"ruta":{"type":"string"},"tamano":{"type":"integer"},"sha256":{"$ref":"#/components/schemas/Sha256ONulo"},"nivel":{"$ref":"#/components/schemas/Nivel"},"nivel_desde":{"$ref":"#/components/schemas/FechaONula","description":"Desde cuándo está en su nivel (carpetas también)"},"al_subir":{"$ref":"#/components/schemas/AlSubir"},"tipo_mime":{"type":["string","null"]},"modificado_en":{"$ref":"#/components/schemas/Fecha"},"creado_por":{"$ref":"#/components/schemas/UuidONulo"},"en_papelera_en":{"$ref":"#/components/schemas/FechaONula"},"version_id":{"$ref":"#/components/schemas/UuidONulo"},"version_numero":{"type":["integer","null"]},"proxy":{"oneOf":[{"$ref":"#/components/schemas/Proxy"},{"type":"null"}],"description":"El proxy del archivo (null en carpetas). El nivel del nodo es el del original; el proxy siempre está caliente"},"proxy_de":{"$ref":"#/components/schemas/UuidONulo","description":"Si este archivo es el proxy subido de ese original (las listas no lo muestran salvo con_proxies=1)"}}},"Proxy":{"type":"object","required":["estado","origen"],"properties":{"estado":{"type":"string","enum":["listo","generando","sin_proxy","no_aplica"]},"motivo":{"type":"string","description":"Por qué no hay proxy (en español","listo para mostrar)":null},"tamano":{"type":"integer"},"ancho":{"type":"integer"},"alto":{"type":"integer"},"duracion":{"type":"number"},"origen":{"type":"string","enum":["servidor","subido"]},"listo_antes":{"$ref":"#/components/schemas/Fecha","description":"Generando: a más tardar cuándo lo hace OZ gratis (subida + 30 días; 60 si el original pesa 100 GB o más)"}}},"PedidoOriginal":{"type":"object","required":["id","estado","nodo_id","version_id","bytes","horas"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"estado":{"type":"string","enum":["esperando_aprobacion","restaurando","listo","vencido","rechazado","fallido"]},"nodo_id":{"$ref":"#/components/schemas/Uuid"},"version_id":{"$ref":"#/components/schemas/Uuid"},"bytes":{"type":"integer"},"horas":{"type":"integer"},"proveedor":{"type":["string","null"],"enum":["oracle","aws",null]},"creado_en":{"$ref":"#/components/schemas/Fecha"},"listo_en":{"$ref":"#/components/schemas/FechaONula"},"disponible_hasta":{"$ref":"#/components/schemas/FechaONula"},"disponible_hasta_texto":{"type":["string","null"],"description":"En hora de Guayaquil"},"pedido_por":{"$ref":"#/components/schemas/UuidONulo"},"aprobacion_id":{"$ref":"#/components/schemas/UuidONulo"},"bajadas":{"type":"integer"}}},"Nodo":{"allOf":[{"$ref":"#/components/schemas/NodoBase"},{"type":"object","required":["links_activos"],"properties":{"links_activos":{"type":"integer","description":"Cantidad de links activos (en `verNodo` es la lista)"}}}]},"AlSubirEfectivo":{"type":["object","null"],"description":"La regla «al subir» que vale aquí (de esta carpeta, de una de arriba o del proyecto); null = ninguna","required":["al_subir","origen"],"properties":{"al_subir":{"type":"string","enum":["frio"]},"origen":{"$ref":"#/components/schemas/ReglaAlSubir"}}},"ReglaAlSubir":{"type":"object","required":["tipo","id","nombre"],"properties":{"tipo":{"type":"string","enum":["carpeta","espacio"]},"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"}}},"NodoConRegla":{"allOf":[{"$ref":"#/components/schemas/Nodo"},{"type":"object","required":["al_subir_efectivo"],"properties":{"al_subir_efectivo":{"$ref":"#/components/schemas/AlSubirEfectivo"}}}]},"NodoDetalle":{"allOf":[{"$ref":"#/components/schemas/NodoBase"},{"type":"object","required":["versiones","copias","links_activos"],"properties":{"al_subir_efectivo":{"$ref":"#/components/schemas/AlSubirEfectivo"},"proxy_nodo":{"type":["object","null"],"description":"El proxy subido por una persona (para «Quitar proxy»)","properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"tamano":{"type":"integer"}}},"original":{"oneOf":[{"$ref":"#/components/schemas/PedidoOriginal"},{"type":"null"}],"description":"El último «pedir el original» de la versión actual"},"versiones":{"type":"array","items":{"$ref":"#/components/schemas/Version"}},"copias":{"type":"array","items":{"type":"object","required":["proveedor","estado"],"properties":{"version_id":{"$ref":"#/components/schemas/Uuid"},"proveedor":{"type":"string"},"estado":{"type":"string"},"verificada_en":{"$ref":"#/components/schemas/FechaONula"},"actualizada_en":{"$ref":"#/components/schemas/FechaONula"}}}},"links_activos":{"type":"array","items":{"$ref":"#/components/schemas/Link"}}}}]},"Version":{"type":"object","required":["id","numero","tamano","sha256","creada_en","actual"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"numero":{"type":"integer"},"tamano":{"type":"integer"},"sha256":{"$ref":"#/components/schemas/Sha256ONulo"},"sha256_declarada":{"$ref":"#/components/schemas/Sha256ONulo"},"tipo_mime":{"type":["string","null"]},"creada_por":{"$ref":"#/components/schemas/UuidONulo"},"creada_por_nombre":{"type":["string","null"]},"creada_via":{"type":["string","null"]},"creada_en":{"$ref":"#/components/schemas/Fecha"},"actual":{"type":"boolean"}}},"NodoPapelera":{"allOf":[{"$ref":"#/components/schemas/Nodo"},{"type":"object","required":["se_borra_en"],"properties":{"papelera_por":{"$ref":"#/components/schemas/UuidONulo"},"papelera_por_nombre":{"type":["string","null"]},"se_borra_en":{"$ref":"#/components/schemas/Fecha"}}}]},"Bajada":{"type":"object","required":["url","vence_en","nombre","tamano","sha256","variante","version_id","version_numero"],"properties":{"url":{"type":"string","format":"uri"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"nombre":{"type":"string"},"tamano":{"type":["integer","null"]},"sha256":{"$ref":"#/components/schemas/Sha256ONulo"},"variante":{"type":"string","enum":["original","miniatura","proxy"]},"version_id":{"$ref":"#/components/schemas/Uuid"},"version_numero":{"type":"integer"}}},"SubidaSimple":{"type":"object","required":["subida_id","nombre","url_simple","vence_en"],"properties":{"subida_id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string","description":"El nombre final"},"url_simple":{"type":"string","format":"uri","description":"PUT único; deja de servir al completar"},"vence_en":{"$ref":"#/components/schemas/Fecha"}}},"SubidaPartes":{"type":"object","required":["subida_id","nombre","parte_bytes","total_partes","partes","vence_en"],"properties":{"subida_id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"parte_bytes":{"type":"integer"},"total_partes":{"type":"integer"},"partes":{"type":"array","items":{"$ref":"#/components/schemas/ParteFirmada"}},"vence_en":{"$ref":"#/components/schemas/Fecha"}}},"ParteFirmada":{"type":"object","required":["numero","url"],"properties":{"numero":{"type":"integer"},"url":{"type":"string","format":"uri"}}},"Link":{"type":"object","required":["id","nodo_id","tipo","estado","token_pista","vence_en","con_clave","max_descargas","descargas","visitas","avisar","pedir_datos","creado_en"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nodo_id":{"$ref":"#/components/schemas/Uuid"},"nodo_nombre":{"type":["string","null"]},"tipo":{"type":"string","enum":["descarga","vista","subida"]},"estado":{"$ref":"#/components/schemas/EstadoLink"},"token_pista":{"type":"string","description":"Últimos 4 caracteres del token"},"vence_en":{"$ref":"#/components/schemas/FechaONula"},"con_clave":{"type":"boolean"},"max_descargas":{"type":["integer","null"]},"descargas":{"type":"integer"},"visitas":{"type":"integer"},"avisar":{"type":"boolean"},"pedir_datos":{"type":"boolean"},"verificar_correo":{"type":"boolean"},"nota":{"type":["string","null"]},"creado_por":{"$ref":"#/components/schemas/UuidONulo"},"creado_en":{"$ref":"#/components/schemas/Fecha"},"pausado_en":{"$ref":"#/components/schemas/FechaONula"},"cortado_en":{"$ref":"#/components/schemas/FechaONula"}}},"LinkConVisita":{"allOf":[{"$ref":"#/components/schemas/Link"},{"type":"object","required":["ultima_visita"],"properties":{"ultima_visita":{"$ref":"#/components/schemas/FechaONula"}}}]},"LinkDetalle":{"allOf":[{"$ref":"#/components/schemas/Link"},{"type":"object","required":["resumen"],"properties":{"resumen":{"type":"object","required":["visitas","descargas_completas","paises","ultima_visita","quienes"],"properties":{"visitas":{"type":"integer"},"descargas_completas":{"type":"integer"},"paises":{"type":"array","items":{"type":"object","required":["pais","n"],"properties":{"pais":{"type":"string"},"n":{"type":"integer"}}}},"ultima_visita":{"$ref":"#/components/schemas/FechaONula"},"quienes":{"type":"array","items":{"type":"object"},"description":"Vacío para llaves mcp/api (datos personales). Cada uno con `verificado` (correo verificado con el código)"},"quienes_visible":{"type":"boolean"},"quienes_declarados":{"type":"boolean","description":"Hay al menos uno sin verificar (correo solo declarado)"}}}}}]},"EventoLink":{"type":"object","required":["ocurrido_en","tipo"],"properties":{"ocurrido_en":{"$ref":"#/components/schemas/Fecha"},"tipo":{"type":"string","examples":["visita","descarga_inicio","descarga_completa","subida","pedir_original"]},"pais":{"type":["string","null"]},"agente":{"type":["string","null"]},"bytes":{"type":["integer","null"]},"nodo_id":{"$ref":"#/components/schemas/UuidONulo"},"ip":{"type":["string","null"],"description":"Solo admins y solo 90 días"}}},"Miembro":{"type":"object","required":["id","persona_id","correo","nombre","rol"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"persona_id":{"$ref":"#/components/schemas/Uuid"},"correo":{"type":"string"},"nombre":{"type":"string"},"rol":{"type":"string","enum":["dueno","admin","miembro","externo"]},"miembro_desde":{"$ref":"#/components/schemas/Fecha"},"creada_en":{"$ref":"#/components/schemas/Fecha"},"con_passkey":{"type":"boolean"},"pendiente":{"type":"boolean"},"desactivada_en":{"$ref":"#/components/schemas/FechaONula"},"links_activos":{"type":"integer"}}},"Uso":{"type":"object","required":["por_nivel","costo_mes_usd","por_espacio"],"properties":{"por_nivel":{"type":"object","required":["caliente","frio","boveda"],"properties":{"caliente":{"type":"integer"},"frio":{"type":"integer"},"boveda":{"type":"integer"}}},"costo_mes_usd":{"type":"number"},"ahorro_mes_usd":{"type":"number"},"precios_tb_usd":{"type":"object"},"dropbox_mes_usd":{"type":"number"},"por_espacio":{"type":"array","items":{"type":"object","required":["espacio_id","nombre","caliente","frio","boveda","costo_mes_usd"],"properties":{"espacio_id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"caliente":{"type":"integer"},"frio":{"type":"integer"},"boveda":{"type":"integer"},"costo_mes_usd":{"type":"number"}}}}}},"BytesNivel":{"type":"object","required":["archivos","bytes"],"properties":{"archivos":{"type":"integer"},"bytes":{"type":"integer"}}},"NivelesUso":{"type":"object","required":["caliente","archivando","frio","despertando"],"properties":{"caliente":{"$ref":"#/components/schemas/BytesNivel"},"archivando":{"$ref":"#/components/schemas/BytesNivel"},"frio":{"$ref":"#/components/schemas/BytesNivel"},"despertando":{"$ref":"#/components/schemas/BytesNivel"}}},"UsoNiveles":{"type":"object","required":["niveles","por_espacio"],"properties":{"niveles":{"$ref":"#/components/schemas/NivelesUso"},"por_espacio":{"type":"array","items":{"type":"object","required":["espacio_id","nombre","niveles"],"properties":{"espacio_id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"},"niveles":{"$ref":"#/components/schemas/NivelesUso"}}}}}},"LineaRegistro":{"type":"object","required":["id","ocurrido_en","accion","resumen"],"properties":{"id":{"type":"string"},"ocurrido_en":{"$ref":"#/components/schemas/Fecha"},"actor_persona_id":{"$ref":"#/components/schemas/UuidONulo"},"persona_nombre":{"type":["string","null"]},"actor_tipo":{"type":["string","null"]},"via":{"type":["string","null"]},"accion":{"type":"string"},"objeto_tipo":{"type":["string","null"]},"objeto_id":{"type":["string","null"]},"objeto_nombre":{"type":["string","null"]},"antes":{},"despues":{},"motivo":{"type":["string","null"]},"ip":{"type":["string","null"]},"agente":{"type":["string","null"]},"huella":{"type":["string","null"]},"resumen":{"type":"string"},"llave_id":{"$ref":"#/components/schemas/UuidONulo"},"llave":{"description":"La llave con la que se hizo (conexión de IA, llave de agente, OZ Storage para Mac o integración), o null.","type":["object","null"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":["string","null"]},"tipo":{"type":["string","null"]},"conexion_id":{"$ref":"#/components/schemas/UuidONulo"}}}}},"Llave":{"type":"object","required":["id","tipo","nombre","persona_id","creada_en","vence_en","actual","en_pausa_por_freno"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"type":"string"},"nombre":{"type":"string"},"persona_id":{"$ref":"#/components/schemas/Uuid"},"persona_nombre":{"type":"string"},"permisos":{"type":["array","null"],"items":{"type":"string"}},"creada_en":{"$ref":"#/components/schemas/Fecha"},"vence_en":{"$ref":"#/components/schemas/FechaONula"},"revocada_en":{"$ref":"#/components/schemas/FechaONula"},"pausada_en":{"$ref":"#/components/schemas/FechaONula"},"ultima_vez":{"$ref":"#/components/schemas/FechaONula"},"actual":{"type":"boolean"},"en_pausa_por_freno":{"type":"boolean"}}},"VolverAFecha":{"type":"object","required":["carpeta","fecha","archivos","restaurados","a_papelera","sin_cambios","en_frio","conflictos","bytes","requiere_confirmacion"],"properties":{"carpeta":{"type":"object","required":["id","ruta"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"ruta":{"type":"string"}}},"fecha":{"$ref":"#/components/schemas/Fecha"},"fecha_texto":{"type":"string","description":"La fecha en hora de Guayaquil","para mostrar":null},"archivos":{"type":"integer","description":"Archivos debajo de la carpeta (también los de la papelera)"},"restaurados":{"type":"integer","description":"Vuelven a como estaban (versión de la fecha o fuera de la papelera)"},"a_papelera":{"type":"integer","description":"Creados después de la fecha; van a la papelera"},"sin_cambios":{"type":"integer"},"en_frio":{"type":"integer","description":"Cambiaron pero están en frío; despertarlos antes"},"conflictos":{"type":"integer","description":"Quedan en la papelera porque su nombre ya está ocupado (o su carpeta sigue ahí)"},"conflictos_nombres":{"type":"array","items":{"type":"string"}},"bytes":{"type":"integer"},"bytes_a_papelera":{"type":"integer"},"detalle":{"type":"object","properties":{"de_papelera":{"type":"integer"},"versiones":{"type":"integer"}}},"requiere_confirmacion":{"type":"boolean","description":"Más de 20 archivos o 50 GB → dos pasos (código OZS)"}}},"VolverEspacioAFecha":{"allOf":[{"type":"object","required":["espacio"],"properties":{"espacio":{"type":"object","required":["id","nombre"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"nombre":{"type":"string"}}}}},{"type":"object","required":["fecha","archivos","restaurados","a_papelera","sin_cambios","en_frio","conflictos","bytes","requiere_confirmacion"],"properties":{"fecha":{"$ref":"#/components/schemas/Fecha"},"fecha_texto":{"type":"string"},"archivos":{"type":"integer"},"restaurados":{"type":"integer"},"a_papelera":{"type":"integer"},"sin_cambios":{"type":"integer"},"en_frio":{"type":"integer"},"conflictos":{"type":"integer"},"conflictos_nombres":{"type":"array","items":{"type":"string"}},"bytes":{"type":"integer"},"bytes_a_papelera":{"type":"integer"},"detalle":{"type":"object","properties":{"de_papelera":{"type":"integer"},"versiones":{"type":"integer"}}},"requiere_confirmacion":{"type":"boolean"}}}]},"Pendiente":{"type":"object","required":["id","tipo","accion","codigo","resumen","vence_en","puede_decidir","costo_estimado_usd","aprobacion"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"enum":["aprobacion","confirmacion"],"description":"`confirmacion`: un código común de la misma persona (solo llave `dispositivo`)"},"accion":{"type":"string"},"codigo":{"type":"string"},"resumen":{"type":"string"},"detalle":{"type":["string","null"]},"creada_en":{"$ref":"#/components/schemas/Fecha"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"pedida_por":{"type":"object"},"puede_decidir":{"type":"boolean"},"puede_aprobar":{"type":"boolean"},"motivo_no_puede":{"type":"string"},"requiere_passkey":{"type":"boolean"},"costo_estimado_usd":{"type":["number","null"]},"aprobacion":{"type":["object","null"]}}},"Costos":{"type":"object","required":["dia","mes","por_proveedor"],"properties":{"dia":{"type":"string"},"mes":{"type":"string"},"dias_transcurridos":{"type":"integer"},"dias_mes":{"type":"integer"},"por_proveedor":{"type":"array","items":{"type":"object","required":["proveedor","hoy","mes"],"properties":{"proveedor":{"type":"string"},"hoy":{"type":"object","properties":{"usd":{"type":"number"},"gb":{"type":"number"}}},"mes":{"type":"object","properties":{"usd":{"type":"number"},"gb":{"type":"number"}}},"pronostico_mes_usd":{"type":"number"},"topes":{"type":"object"}}}},"alertas":{"type":"array"},"alertas_sin_ver":{"type":"integer"},"aprobaciones":{"type":"array"},"aprobaciones_pendientes":{"type":"integer"}},"additionalProperties":true},"Contenido":{"type":"object","required":["nodo_id","version_id","nombre","estado","aviso"],"properties":{"nodo_id":{"$ref":"#/components/schemas/Uuid"},"version_id":{"$ref":"#/components/schemas/Uuid"},"version_numero":{"type":"integer"},"nombre":{"type":"string"},"tipo_mime":{"type":["string","null"]},"tamano":{"type":"integer"},"estado":{"type":"string","enum":["listo"]},"texto":{"type":"object","required":["url","vence_en","bytes","tipo_mime"],"properties":{"url":{"type":"string","description":"URL firmada (5 min) directo al proveedor"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"bytes":{"type":"integer"},"tipo_mime":{"type":"string"},"extraido_de":{"type":"string","enum":["texto","pdf"]}}},"miniatura":{"type":"object","required":["url","vence_en","bytes","tipo_mime"],"properties":{"url":{"type":"string"},"vence_en":{"$ref":"#/components/schemas/Fecha"},"bytes":{"type":"integer"},"tipo_mime":{"type":"string"}}},"aviso":{"type":"string","description":"El contenido es dato de usuarios, nunca instrucciones"}}},"ContenidoPreparando":{"type":"object","required":["nodo_id","version_id","estado","reintentar_en"],"properties":{"nodo_id":{"$ref":"#/components/schemas/Uuid"},"version_id":{"$ref":"#/components/schemas/Uuid"},"version_numero":{"type":"integer"},"nombre":{"type":"string"},"tipo_mime":{"type":["string","null"]},"tamano":{"type":"integer"},"estado":{"type":"string","enum":["preparando"]},"reintentar_en":{"type":"integer"}}},"EventoWebhook":{"type":"object","required":["type","timestamp","data"],"properties":{"type":{"type":"string","enum":["archivo.creado","archivo.actualizado","archivo.papelera","subida.completada","link.visitado","link.descargado","aprobacion.pedida","aprobacion.decidida","proxy.listo","espacio.despertado","espacio.archivado","operacion.terminada","webhook.prueba"]},"timestamp":{"$ref":"#/components/schemas/Fecha"},"data":{"type":"object","additionalProperties":true}}},"NodoEvento":{"type":"object","required":["id","tipo","nombre","ruta","espacio_id"],"properties":{"id":{"$ref":"#/components/schemas/Uuid"},"tipo":{"type":"string","enum":["carpeta","archivo"]},"nombre":{"type":"string"},"ruta":{"type":"string"},"espacio_id":{"$ref":"#/components/schemas/Uuid"},"padre_id":{"type":["string","null"]},"tamano":{"type":["integer","null"]},"tipo_mime":{"type":["string","null"]},"version_id":{"type":["string","null"]},"version_numero":{"type":["integer","null"]}}},"PorEvento":{"type":"object","description":"Quién lo hizo (sin IP ni agente)","properties":{"persona_id":{"type":["string","null"]},"via":{"type":["string","null"]},"llave_id":{"type":["string","null"]},"tipo":{"type":"string"}}},"PedidoToken":{"type":"object","required":["grant_type"],"properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"]},"code":{"type":"string"},"code_verifier":{"type":"string"},"client_id":{"type":"string"},"redirect_uri":{"type":"string"},"resource":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string"}}}}}}
