{"openapi": "3.1.0", "info": {"title": "YoFacturo API", "version": "1.0.0", "summary": "API pública de YoFacturo para integraciones programáticas (catálogo, ventas, facturación electrónica AFIP, clientes y más).", "description": "API REST para acceso programático a una cuenta de YoFacturo — facturación electrónica AFIP, catálogo, ventas, clientes, cuenta corriente, contabilidad y automatizaciones vía webhooks salientes.\n\n### Autenticación\nCada request se autentica con un token opaco (`X-API-Key: yf_live_xxx` o `Authorization: Bearer yf_live_xxx`), generado desde **Configuración > API Tokens** en el panel. Cada token lleva uno o más *scopes* (`recurso:read` / `recurso:write`) — el request falla con 403 si le falta el scope que ese endpoint requiere.\n\n### Modo sandbox (`yf_test_*`)\nUn token con prefijo `yf_test_*` en lugar de `yf_live_*` autentica como el mismo tenant/usuario (mismo plan, mismos permisos) pero cada lectura/escritura se enruta a una base de datos físicamente separada (`{tenant}__sandbox`) que nunca toca los datos reales, y la emisión de comprobantes AFIP nunca sale a la red: se persiste un comprobante simulado con un CAE sintético (`simulated: true`, `livemode: false`). `POST /sandbox/reset/` vacía esa base de un saque para reiniciar una suite de integración desde cero. Un token `yf_live_*` recibe 403 en ese endpoint — nunca puede alcanzar un drop de base de datos por acá.\n\n### Reintentos seguros (Idempotency-Key)\nLos endpoints de creación con mayor costo de un duplicado (`POST /sales/`, `POST /products/`, `POST /bill/receipts/invoice/`) aceptan un header `Idempotency-Key` elegido por el cliente. Reenviar el mismo request con la misma clave dentro de las 24h reproduce la respuesta original en vez de crear un segundo recurso (la respuesta trae `Idempotency-Replayed: true`); la misma clave con un body distinto devuelve 422.\n\n### Rate limiting\nTodos los tokens de un mismo tenant comparten una ventana deslizante (10/s · 100/min · 3000/h · 20000/día). Al superarla, la respuesta es 429 con headers `X-RateLimit-*` y `Retry-After`.\n\n### Modelo de respuesta\nToda respuesta exitosa tiene la forma `{\"success\": true, \"data\": ..., \"message\"?: ..., \"_links\"?: {...}}`. Todo error tiene la forma `{\"success\": false, \"error\": \"...\", \"code\": \"...\"}` — `code` es estable y apto para switch/case, `error` es para mostrar.\n\n### Confianza y disponibilidad\nSeguridad: https://yo-facturo.com/seguridad/ · Confiabilidad: https://yo-facturo.com/confiabilidad/ · DPA: https://yo-facturo.com/legal/dpa/ · SLA: https://yo-facturo.com/legal/sla/ · Estado del servicio: https://status.yo-facturo.com\n\n## Cobertura de este spec\n\nDocumentado con detalle completo (request/response tipados): **Productos**,\n**Clientes**, **Ventas**, **Facturación** (emisión/nota de crédito/nota de\ndébito/autorización/anulación de comprobantes AFIP), **Cuenta corriente**,\n**Webhooks salientes** y **Sandbox**.\n\nDocumentado con un esquema genérico (`GenericEntity`, `additionalProperties:\ntrue`) pero con las rutas, scopes y métodos REALES: Categorías, Servicios,\nAlquileres, Variantes/Opciones de producto, Perfiles de precio, Promociones,\nPOS, Caja registradora, Metas de venta, Pedidos, Presupuestos/Cotizaciones,\nFacturas de compra, Remitos, Proveedores, Gastos, Insumos, CRM (tareas,\nrecordatorios, pipelines, oportunidades, segmentos, plantillas,\ncomunicaciones), Beneficios/Recompensas, Turnos, Contratos, Métodos de pago,\nAsientos contables y Cuentas contables.\n\n**Deferred / not yet in this spec** (endpoints reales que existen y son\nalcanzables con un API token, pero quedaron fuera de esta primera versión —\ncandidatos para una v1.1):\n- Envíos (`/shipping/*`): ~30 endpoints (proveedores, envíos, cotizaciones,\n  tracking) con `shipping:read`/`shipping:write` — forma no estandar (no sigue\n  el patrón CRUD create/list de 5 rutas).\n- Servicio en campo (`/field-service/work-orders/*`): CRUD + `cancel`,\n  `generate-sale`, `emit-remito`, `emit-invoice` con `field_service:read`/`write`.\n- Sub-operaciones de venta que SOLO aceptan sesión JWT (no API token todavía):\n  `/sales/{id}/refund/`, `/sales/{id}/cancel/`, `/sales/{id}/credit_note/`,\n  `/sales/{id}/payments/`.\n- Diagnóstico/utilidad de facturación: `/bill/receipts/doctor/`,\n  `/bill/receipts/wsmtxca/diagnose/`, `/bill/receipts/test-environment/`,\n  `/bill/receipts/preview-type/`, `/bill/receipts/validate-type/*`,\n  `/bill/receipts/notes/*`, `/bill/receipts/{id}/send-email/`,\n  PUT/PATCH de comprobante.\n- Import/export (Excel/CSV) por entidad: `/{entity}/import/`,\n  `/{entity}/export/`, `/{entity}/import/template/` — autenticados solo por\n  JWT en la mayoría de entidades.\n- SCIM 2.0 (`scim:provision`) y MCP (`POST /api/v1/mcp`) — protocolos propios,\n  no HTTP REST convencional; se documentarán en specs separadas.", "contact": {"name": "YoFacturo API Support", "email": "api@yo-facturo.com", "url": "https://yo-facturo.com/seguridad/"}, "license": {"name": "Proprietary", "url": "https://yo-facturo.com/legal/terms-and-conditions/"}}, "servers": [{"url": "https://api.yo-facturo.com/api/v1", "description": "Producción"}], "tags": [{"name": "Catálogo", "description": "Productos, servicios, alquileres, categorías, variantes, perfiles de precio y promociones."}, {"name": "Ventas", "description": "Ventas, punto de venta, caja registradora, metas de venta, presupuestos y pedidos."}, {"name": "Facturación", "description": "Comprobantes electrónicos AFIP (facturas, notas de crédito/débito), facturas de compra y remitos."}, {"name": "Compras", "description": "Proveedores, gastos e insumos."}, {"name": "Clientes", "description": "Clientes, cuenta corriente, CRM y programa de beneficios."}, {"name": "Operaciones", "description": "Turnos, contratos, métodos de pago, envíos y servicio en campo."}, {"name": "Contabilidad", "description": "Plan de cuentas y libro diario."}, {"name": "Webhooks", "description": "Suscripción a eventos salientes (HTTP) y su historial de entregas."}, {"name": "Sandbox", "description": "Gestión de la base de datos de pruebas aislada de un token yf_test_*."}], "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "paths": {"/accounting/accounts/": {"post": {"tags": ["Contabilidad"], "summary": "Crear cuenta contable", "operationId": "create_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Cuenta contable creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}}, "/accounting/accounts/list/": {"get": {"tags": ["Contabilidad"], "summary": "Listar cuenta contables", "operationId": "list_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de cuenta contables.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:read"], "description": "Requiere scope `accounting:read`."}}, "/accounting/accounts/{account_id}/": {"get": {"tags": ["Contabilidad"], "summary": "Obtener cuenta contable por id", "operationId": "get_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cuenta contable.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:read"], "description": "Requiere scope `accounting:read`."}, "put": {"tags": ["Contabilidad"], "summary": "Actualizar cuenta contable", "operationId": "update_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Cuenta contable actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}, "delete": {"tags": ["Contabilidad"], "summary": "Eliminar cuenta contable", "operationId": "delete_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cuenta contable eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}}, "/accounting/journal/": {"post": {"tags": ["Contabilidad"], "summary": "Crear asiento contable", "operationId": "create_journal_entry", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Asiento contable creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}}, "/accounting/journal/list/": {"get": {"tags": ["Contabilidad"], "summary": "Listar asiento contables", "operationId": "list_journal_entry", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de asiento contables.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:read"], "description": "Requiere scope `accounting:read`."}}, "/accounting/journal/{journal_entry_id}/": {"get": {"tags": ["Contabilidad"], "summary": "Obtener asiento contable por id", "operationId": "get_journal_entry", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "journal_entry_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Asiento contable.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:read"], "description": "Requiere scope `accounting:read`."}, "put": {"tags": ["Contabilidad"], "summary": "Actualizar asiento contable", "operationId": "update_journal_entry", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "journal_entry_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Asiento contable actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}, "delete": {"tags": ["Contabilidad"], "summary": "Eliminar asiento contable", "operationId": "delete_journal_entry", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "journal_entry_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Asiento contable eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["accounting:write"], "description": "Requiere scope `accounting:write`."}}, "/appointments/": {"post": {"tags": ["Operaciones"], "summary": "Crear turno/cita", "operationId": "create_appointment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Turno/Cita creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["appointments:write"], "description": "Requiere scope `appointments:write`."}}, "/appointments/list/": {"get": {"tags": ["Operaciones"], "summary": "Listar turno/citas", "operationId": "list_appointment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de turno/citas.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["appointments:read"], "description": "Requiere scope `appointments:read`."}}, "/appointments/{appointment_id}/": {"get": {"tags": ["Operaciones"], "summary": "Obtener turno/cita por id", "operationId": "get_appointment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "appointment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Turno/Cita.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["appointments:read"], "description": "Requiere scope `appointments:read`."}, "put": {"tags": ["Operaciones"], "summary": "Actualizar turno/cita", "operationId": "update_appointment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "appointment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Turno/Cita actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["appointments:write"], "description": "Requiere scope `appointments:write`."}, "delete": {"tags": ["Operaciones"], "summary": "Eliminar turno/cita", "operationId": "delete_appointment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "appointment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Turno/Cita eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["appointments:write"], "description": "Requiere scope `appointments:write`."}}, "/bill/receipts/authorize/{comprobante_id}/": {"post": {"tags": ["Facturación"], "summary": "Autorizar comprobante (obtener CAE)", "operationId": "authorize_comprobante", "description": "Envía a AFIP un comprobante creado en borrador y obtiene su CAE. Con un token `yf_test_*` (sandbox) este endpoint no llama a AFIP: persiste un comprobante simulado (`simulated: true`, `livemode: false`, un CAE sintético) en la base sandbox aislada del tenant. Requiere scope `invoices:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "comprobante_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Comprobante autorizado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:write"]}}, "/bill/receipts/cancel/{comprobante_id}/": {"post": {"tags": ["Facturación"], "summary": "Anular comprobante", "operationId": "cancel_comprobante", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "comprobante_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Comprobante anulado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:write"], "description": "Requiere scope `invoices:write`."}}, "/bill/receipts/credit-note/": {"post": {"tags": ["Facturación"], "summary": "Emitir nota de crédito", "operationId": "create_credit_note", "description": "Anula total o parcialmente un comprobante existente. Con un token `yf_test_*` (sandbox) este endpoint no llama a AFIP: persiste un comprobante simulado (`simulated: true`, `livemode: false`, un CAE sintético) en la base sandbox aislada del tenant. Requiere scope `invoices:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NoteCreateRequest"}}}}, "responses": {"200": {"description": "Nota de crédito creada.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:write"]}}, "/bill/receipts/debit-note/": {"post": {"tags": ["Facturación"], "summary": "Emitir nota de débito", "operationId": "create_debit_note", "description": "Ajusta al alza un comprobante existente. Con un token `yf_test_*` (sandbox) este endpoint no llama a AFIP: persiste un comprobante simulado (`simulated: true`, `livemode: false`, un CAE sintético) en la base sandbox aislada del tenant. Requiere scope `invoices:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NoteCreateRequest"}}}}, "responses": {"200": {"description": "Nota de débito creada.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:write"]}}, "/bill/receipts/invoice/": {"post": {"tags": ["Facturación"], "summary": "Emitir factura", "operationId": "create_invoice", "description": "Crea (y opcionalmente autoriza) una factura electrónica AFIP. Con un token `yf_test_*` (sandbox) este endpoint no llama a AFIP: persiste un comprobante simulado (`simulated: true`, `livemode: false`, un CAE sintético) en la base sandbox aislada del tenant. Soporta reintentos seguros vía `Idempotency-Key`; si no se envía ese header, igual se deduplica por huella del payload durante 5 minutos para no emitir dos comprobantes fiscales por un reintento de red. Requiere scope `invoices:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/InvoiceCreateRequest"}}}}, "responses": {"200": {"description": "Comprobante creado (borrador o autorizado si `autorizar: true`).", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "422": {"$ref": "#/components/responses/UnprocessableEntity"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "503": {"description": "ARCA/AFIP no disponible."}}, "x-required-scope": ["invoices:write"]}}, "/bill/receipts/list/": {"get": {"tags": ["Facturación"], "summary": "Listar comprobantes", "operationId": "list_comprobantes", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}, {"name": "tipo_comprobante", "in": "query", "schema": {"type": "integer"}}, {"name": "estado", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Listado paginado de comprobantes.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/Comprobante"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:read"], "description": "Requiere scope `invoices:read`."}}, "/bill/receipts/supported-types/": {"get": {"tags": ["Facturación"], "summary": "Tipos de comprobante soportados por la condición fiscal del emisor", "operationId": "get_supported_comprobante_types", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "responses": {"200": {"description": "Tipos soportados.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "array", "items": {"type": "object", "additionalProperties": true}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}}, "x-required-scope": ["invoices:read"], "description": "Requiere scope `invoices:read`."}}, "/bill/receipts/{comprobante_id}/": {"get": {"tags": ["Facturación"], "summary": "Obtener comprobante", "operationId": "get_comprobante", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "comprobante_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Comprobante.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Comprobante"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["invoices:read"], "description": "Requiere scope `invoices:read`."}}, "/budgets/": {"post": {"tags": ["Ventas"], "summary": "Crear presupuesto/cotización", "operationId": "create_budget", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Presupuesto/Cotización creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["budgets:write"], "description": "Requiere scope `budgets:write`."}}, "/budgets/list/": {"get": {"tags": ["Ventas"], "summary": "Listar presupuesto/cotizacións", "operationId": "list_budget", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de presupuesto/cotizacións.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["budgets:read"], "description": "Requiere scope `budgets:read`."}}, "/budgets/{quote_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener presupuesto/cotización por id", "operationId": "get_budget", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "quote_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Presupuesto/Cotización.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["budgets:read"], "description": "Requiere scope `budgets:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar presupuesto/cotización", "operationId": "update_budget", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "quote_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Presupuesto/Cotización actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["budgets:write"], "description": "Requiere scope `budgets:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar presupuesto/cotización", "operationId": "delete_budget", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "quote_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Presupuesto/Cotización eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["budgets:write"], "description": "Requiere scope `budgets:write`."}}, "/cash_register/": {"post": {"tags": ["Ventas"], "summary": "Crear caja registradora", "operationId": "create_cash_register", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Caja registradora creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["cash_register:write"], "description": "Requiere scope `cash_register:write`."}}, "/cash_register/list/": {"get": {"tags": ["Ventas"], "summary": "Listar caja registradoras", "operationId": "list_cash_register", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de caja registradoras.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["cash_register:read"], "description": "Requiere scope `cash_register:read`."}}, "/cash_register/{cash_register_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener caja registradora por id", "operationId": "get_cash_register", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "cash_register_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Caja registradora.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["cash_register:read"], "description": "Requiere scope `cash_register:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar caja registradora", "operationId": "update_cash_register", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "cash_register_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Caja registradora actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["cash_register:write"], "description": "Requiere scope `cash_register:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar caja registradora", "operationId": "delete_cash_register", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "cash_register_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Caja registradora eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["cash_register:write"], "description": "Requiere scope `cash_register:write`."}}, "/categories/": {"post": {"tags": ["Catálogo"], "summary": "Crear categoría", "operationId": "create_category", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Categoría creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["categories:write"], "description": "Requiere scope `categories:write`."}}, "/categories/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar categorías", "operationId": "list_category", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de categorías.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["categories:read"], "description": "Requiere scope `categories:read`."}}, "/categories/{category_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener categoría por id", "operationId": "get_category", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "category_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Categoría.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["categories:read"], "description": "Requiere scope `categories:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar categoría", "operationId": "update_category", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "category_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Categoría actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["categories:write"], "description": "Requiere scope `categories:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar categoría", "operationId": "delete_category", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "category_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Categoría eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["categories:write"], "description": "Requiere scope `categories:write`."}}, "/contracts/": {"post": {"tags": ["Operaciones"], "summary": "Crear contrato", "operationId": "create_contract", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Contrato creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["contracts:write"], "description": "Requiere scope `contracts:write`."}}, "/contracts/list/": {"get": {"tags": ["Operaciones"], "summary": "Listar contratos", "operationId": "list_contract", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de contratos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["contracts:read"], "description": "Requiere scope `contracts:read`."}}, "/contracts/{contract_id}/": {"get": {"tags": ["Operaciones"], "summary": "Obtener contrato por id", "operationId": "get_contract", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "contract_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Contrato.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["contracts:read"], "description": "Requiere scope `contracts:read`."}, "put": {"tags": ["Operaciones"], "summary": "Actualizar contrato", "operationId": "update_contract", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "contract_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Contrato actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["contracts:write"], "description": "Requiere scope `contracts:write`."}, "delete": {"tags": ["Operaciones"], "summary": "Eliminar contrato", "operationId": "delete_contract", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "contract_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Contrato eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["contracts:write"], "description": "Requiere scope `contracts:write`."}}, "/crm-communications/": {"post": {"tags": ["Clientes"], "summary": "Crear comunicación crm", "operationId": "create_crm_communication", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Comunicación CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-communications/list/": {"get": {"tags": ["Clientes"], "summary": "Listar comunicación crms", "operationId": "list_crm_communication", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de comunicación crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-communications/{crm_communication_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener comunicación crm por id", "operationId": "get_crm_communication", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_communication_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Comunicación CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar comunicación crm", "operationId": "update_crm_communication", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_communication_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Comunicación CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar comunicación crm", "operationId": "delete_crm_communication", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_communication_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Comunicación CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-opportunities/": {"post": {"tags": ["Clientes"], "summary": "Crear oportunidad crm", "operationId": "create_crm_opportunity", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Oportunidad CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-opportunities/list/": {"get": {"tags": ["Clientes"], "summary": "Listar oportunidad crms", "operationId": "list_crm_opportunity", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de oportunidad crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-opportunities/{crm_opportunity_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener oportunidad crm por id", "operationId": "get_crm_opportunity", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_opportunity_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Oportunidad CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar oportunidad crm", "operationId": "update_crm_opportunity", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_opportunity_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Oportunidad CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar oportunidad crm", "operationId": "delete_crm_opportunity", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_opportunity_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Oportunidad CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-pipelines/": {"post": {"tags": ["Clientes"], "summary": "Crear pipeline crm", "operationId": "create_crm_pipeline", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Pipeline CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-pipelines/list/": {"get": {"tags": ["Clientes"], "summary": "Listar pipeline crms", "operationId": "list_crm_pipeline", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de pipeline crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-pipelines/{crm_pipeline_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener pipeline crm por id", "operationId": "get_crm_pipeline", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_pipeline_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Pipeline CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar pipeline crm", "operationId": "update_crm_pipeline", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_pipeline_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Pipeline CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar pipeline crm", "operationId": "delete_crm_pipeline", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_pipeline_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Pipeline CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-reminders/": {"post": {"tags": ["Clientes"], "summary": "Crear recordatorio crm", "operationId": "create_crm_reminder", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Recordatorio CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-reminders/list/": {"get": {"tags": ["Clientes"], "summary": "Listar recordatorio crms", "operationId": "list_crm_reminder", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de recordatorio crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-reminders/{crm_reminder_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener recordatorio crm por id", "operationId": "get_crm_reminder", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_reminder_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Recordatorio CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar recordatorio crm", "operationId": "update_crm_reminder", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_reminder_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Recordatorio CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar recordatorio crm", "operationId": "delete_crm_reminder", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_reminder_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Recordatorio CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-segments/": {"post": {"tags": ["Clientes"], "summary": "Crear segmento crm", "operationId": "create_crm_segment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Segmento CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-segments/list/": {"get": {"tags": ["Clientes"], "summary": "Listar segmento crms", "operationId": "list_crm_segment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de segmento crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-segments/{crm_segment_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener segmento crm por id", "operationId": "get_crm_segment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_segment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Segmento CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar segmento crm", "operationId": "update_crm_segment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_segment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Segmento CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar segmento crm", "operationId": "delete_crm_segment", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_segment_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Segmento CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-tasks/": {"post": {"tags": ["Clientes"], "summary": "Crear tarea crm", "operationId": "create_crm_task", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Tarea CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-tasks/list/": {"get": {"tags": ["Clientes"], "summary": "Listar tarea crms", "operationId": "list_crm_task", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de tarea crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-tasks/{crm_task_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener tarea crm por id", "operationId": "get_crm_task", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_task_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Tarea CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar tarea crm", "operationId": "update_crm_task", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_task_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Tarea CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar tarea crm", "operationId": "delete_crm_task", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_task_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Tarea CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-templates/": {"post": {"tags": ["Clientes"], "summary": "Crear plantilla de mensaje crm", "operationId": "create_crm_template", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Plantilla de mensaje CRM creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/crm-templates/list/": {"get": {"tags": ["Clientes"], "summary": "Listar plantilla de mensaje crms", "operationId": "list_crm_template", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de plantilla de mensaje crms.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}}, "/crm-templates/{crm_template_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener plantilla de mensaje crm por id", "operationId": "get_crm_template", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_template_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Plantilla de mensaje CRM.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:read"], "description": "Requiere scope `crm:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar plantilla de mensaje crm", "operationId": "update_crm_template", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_template_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Plantilla de mensaje CRM actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar plantilla de mensaje crm", "operationId": "delete_crm_template", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "crm_template_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Plantilla de mensaje CRM eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["crm:write"], "description": "Requiere scope `crm:write`."}}, "/current-accounts/": {"get": {"tags": ["Clientes"], "summary": "Listar cuentas corrientes", "operationId": "list_current_accounts", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "entity_type", "in": "query", "schema": {"type": "string", "enum": ["customer", "supplier"]}}, {"name": "status", "in": "query", "schema": {"type": "string"}}, {"name": "only_debtors", "in": "query", "schema": {"type": "boolean", "default": false}}, {"$ref": "#/components/parameters/Page"}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "default": 50}}], "responses": {"200": {"description": "Listado paginado de cuentas corrientes.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/CurrentAccount"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:read"], "description": "Requiere scope `current_accounts:read`."}, "post": {"tags": ["Clientes"], "summary": "Crear cuenta corriente", "operationId": "create_current_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CurrentAccountCreate"}}}}, "responses": {"201": {"description": "Cuenta corriente creada.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/CurrentAccount"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:write"], "description": "Requiere scope `current_accounts:write`."}}, "/current-accounts/aging/": {"get": {"tags": ["Clientes"], "summary": "Antigüedad de saldos (aging report)", "operationId": "get_current_accounts_aging", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "responses": {"200": {"description": "Reporte de aging.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "additionalProperties": true}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}}, "x-required-scope": ["current_accounts:read"], "description": "Requiere scope `current_accounts:read`."}}, "/current-accounts/{account_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener cuenta corriente", "operationId": "get_current_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cuenta corriente.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/CurrentAccount"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:read"], "description": "Requiere scope `current_accounts:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar cuenta corriente", "operationId": "update_current_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "additionalProperties": true}}}}, "responses": {"200": {"description": "Cuenta corriente actualizada.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/CurrentAccount"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:write"], "description": "Requiere scope `current_accounts:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar cuenta corriente", "operationId": "delete_current_account", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cuenta corriente eliminada.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:write"], "description": "Requiere scope `current_accounts:write`."}}, "/current-accounts/{account_id}/movements/": {"get": {"tags": ["Clientes"], "summary": "Listar movimientos de una cuenta corriente", "operationId": "list_current_account_movements", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}, {"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}], "responses": {"200": {"description": "Movimientos de la cuenta.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"type": "object", "additionalProperties": true}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}}, "x-required-scope": ["current_accounts:read"], "description": "Requiere scope `current_accounts:read`."}}, "/current-accounts/{account_id}/payments/": {"post": {"tags": ["Clientes"], "summary": "Registrar cobro/pago", "operationId": "register_current_account_payment", "description": "El pago queda pendiente de reconciliar salvo `auto_apply: true`. Requiere scope `current_accounts:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PaymentCreate"}}}}, "responses": {"201": {"description": "Pago registrado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "additionalProperties": true}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["current_accounts:write"]}}, "/current-accounts/{account_id}/statement/": {"get": {"tags": ["Clientes"], "summary": "Estado de cuenta (resumen)", "operationId": "get_current_account_statement", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "account_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Estado de cuenta.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "additionalProperties": true}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}}, "x-required-scope": ["current_accounts:read"], "description": "Requiere scope `current_accounts:read`."}}, "/customers/": {"post": {"tags": ["Clientes"], "summary": "Crear cliente", "operationId": "create_customer", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomerCreate"}}}}, "responses": {"201": {"description": "Cliente creado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Customer"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["customers:write"], "description": "Requiere scope `customers:write`."}}, "/customers/list/": {"get": {"tags": ["Clientes"], "summary": "Listar clientes", "operationId": "list_customers", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de clientes.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/Customer"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["customers:read"], "description": "Requiere scope `customers:read`."}}, "/customers/{customer_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener cliente", "operationId": "get_customer", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cliente.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Customer"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["customers:read"], "description": "Requiere scope `customers:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar cliente", "operationId": "update_customer", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomerUpdate"}}}}, "responses": {"200": {"description": "Cliente actualizado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Customer"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["customers:write"], "description": "Requiere scope `customers:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar cliente", "operationId": "delete_customer", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "customer_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Cliente eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["customers:write"], "description": "Requiere scope `customers:write`."}}, "/delivery_notes/": {"post": {"tags": ["Facturación"], "summary": "Crear remito", "operationId": "create_delivery_note", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Remito creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["delivery_notes:write"], "description": "Requiere scope `delivery_notes:write`."}}, "/delivery_notes/list/": {"get": {"tags": ["Facturación"], "summary": "Listar remitos", "operationId": "list_delivery_note", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de remitos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["delivery_notes:read"], "description": "Requiere scope `delivery_notes:read`."}}, "/delivery_notes/{delivery_note_id}/": {"get": {"tags": ["Facturación"], "summary": "Obtener remito por id", "operationId": "get_delivery_note", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "delivery_note_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Remito.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["delivery_notes:read"], "description": "Requiere scope `delivery_notes:read`."}, "put": {"tags": ["Facturación"], "summary": "Actualizar remito", "operationId": "update_delivery_note", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "delivery_note_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Remito actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["delivery_notes:write"], "description": "Requiere scope `delivery_notes:write`."}, "delete": {"tags": ["Facturación"], "summary": "Eliminar remito", "operationId": "delete_delivery_note", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "delivery_note_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Remito eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["delivery_notes:write"], "description": "Requiere scope `delivery_notes:write`."}}, "/expenses/": {"post": {"tags": ["Compras"], "summary": "Crear gasto", "operationId": "create_expense", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Gasto creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["expenses:write"], "description": "Requiere scope `expenses:write`."}}, "/expenses/list/": {"get": {"tags": ["Compras"], "summary": "Listar gastos", "operationId": "list_expense", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de gastos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["expenses:read"], "description": "Requiere scope `expenses:read`."}}, "/expenses/{expense_id}/": {"get": {"tags": ["Compras"], "summary": "Obtener gasto por id", "operationId": "get_expense", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "expense_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Gasto.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["expenses:read"], "description": "Requiere scope `expenses:read`."}, "put": {"tags": ["Compras"], "summary": "Actualizar gasto", "operationId": "update_expense", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "expense_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Gasto actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["expenses:write"], "description": "Requiere scope `expenses:write`."}, "delete": {"tags": ["Compras"], "summary": "Eliminar gasto", "operationId": "delete_expense", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "expense_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Gasto eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["expenses:write"], "description": "Requiere scope `expenses:write`."}}, "/goals/": {"post": {"tags": ["Ventas"], "summary": "Crear meta de venta", "operationId": "create_goals", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Meta de venta creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["sales_goals:write"], "description": "Requiere scope `sales_goals:write`."}}, "/goals/list/": {"get": {"tags": ["Ventas"], "summary": "Listar meta de ventas", "operationId": "list_goals", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de meta de ventas.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales_goals:read"], "description": "Requiere scope `sales_goals:read`."}}, "/goals/{goals_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener meta de venta por id", "operationId": "get_goals", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "goals_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Meta de venta.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales_goals:read"], "description": "Requiere scope `sales_goals:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar meta de venta", "operationId": "update_goals", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "goals_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Meta de venta actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales_goals:write"], "description": "Requiere scope `sales_goals:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar meta de venta", "operationId": "delete_goals", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "goals_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Meta de venta eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales_goals:write"], "description": "Requiere scope `sales_goals:write`."}}, "/orders/": {"post": {"tags": ["Ventas"], "summary": "Crear pedido", "operationId": "create_order", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Pedido creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["orders:write"], "description": "Requiere scope `orders:write`."}}, "/orders/list/": {"get": {"tags": ["Ventas"], "summary": "Listar pedidos", "operationId": "list_order", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de pedidos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["orders:read"], "description": "Requiere scope `orders:read`."}}, "/orders/{order_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener pedido por id", "operationId": "get_order", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "order_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Pedido.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["orders:read"], "description": "Requiere scope `orders:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar pedido", "operationId": "update_order", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "order_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Pedido actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["orders:write"], "description": "Requiere scope `orders:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar pedido", "operationId": "delete_order", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "order_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Pedido eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["orders:write"], "description": "Requiere scope `orders:write`."}}, "/payment_methods/": {"post": {"tags": ["Operaciones"], "summary": "Crear método de pago", "operationId": "create_payment_method", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Método de pago creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["payment_methods:write"], "description": "Requiere scope `payment_methods:write`."}}, "/payment_methods/list/": {"get": {"tags": ["Operaciones"], "summary": "Listar método de pagos", "operationId": "list_payment_method", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de método de pagos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["payment_methods:read"], "description": "Requiere scope `payment_methods:read`."}}, "/payment_methods/{payment_method_id}/": {"get": {"tags": ["Operaciones"], "summary": "Obtener método de pago por id", "operationId": "get_payment_method", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "payment_method_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Método de pago.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["payment_methods:read"], "description": "Requiere scope `payment_methods:read`."}, "put": {"tags": ["Operaciones"], "summary": "Actualizar método de pago", "operationId": "update_payment_method", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "payment_method_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Método de pago actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["payment_methods:write"], "description": "Requiere scope `payment_methods:write`."}, "delete": {"tags": ["Operaciones"], "summary": "Eliminar método de pago", "operationId": "delete_payment_method", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "payment_method_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Método de pago eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["payment_methods:write"], "description": "Requiere scope `payment_methods:write`."}}, "/pos/": {"post": {"tags": ["Ventas"], "summary": "Crear sesión de punto de venta", "operationId": "create_pos", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Sesión de punto de venta creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["pos:write"], "description": "Requiere scope `pos:write`."}}, "/pos/list/": {"get": {"tags": ["Ventas"], "summary": "Listar sesión de punto de ventas", "operationId": "list_pos", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de sesión de punto de ventas.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pos:read"], "description": "Requiere scope `pos:read`."}}, "/pos/{pos_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener sesión de punto de venta por id", "operationId": "get_pos", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pos_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Sesión de punto de venta.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pos:read"], "description": "Requiere scope `pos:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar sesión de punto de venta", "operationId": "update_pos", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pos_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Sesión de punto de venta actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pos:write"], "description": "Requiere scope `pos:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar sesión de punto de venta", "operationId": "delete_pos", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pos_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Sesión de punto de venta eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pos:write"], "description": "Requiere scope `pos:write`."}}, "/products/": {"post": {"tags": ["Catálogo"], "summary": "Crear producto", "description": "Soporta reintentos seguros vía el header `Idempotency-Key`. Requiere scope `products:write`.", "operationId": "create_product", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProductCreate"}}}}, "responses": {"200": {"description": "Producto creado (o respuesta reproducida si el Idempotency-Key ya se había usado).", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}}, "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Product"}, "message": {"type": "string", "example": "Product created successfully"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/UnprocessableEntity"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["products:write"]}}, "/products/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar productos", "operationId": "list_products", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}, {"name": "category_id", "in": "query", "schema": {"type": "string"}}, {"name": "status", "in": "query", "schema": {"type": "string"}}, {"name": "tags", "in": "query", "description": "Lista separada por coma; matchea CUALQUIERA de los valores.", "schema": {"type": "string"}}, {"name": "ids", "in": "query", "description": "Lista de ids separada por coma (resolver un conjunto ya elegido, sin traer toda la colección).", "schema": {"type": "string"}}, {"name": "include_images", "in": "query", "schema": {"type": "boolean", "default": false}}], "responses": {"200": {"description": "Listado paginado de productos.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/Product"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["products:read"], "description": "Requiere scope `products:read`."}}, "/products/options/": {"post": {"tags": ["Catálogo"], "summary": "Crear variante/opción de producto", "operationId": "create_products_option", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Variante/opción de producto creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["product_options:write"], "description": "Requiere scope `product_options:write`."}}, "/products/options/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar variante/opción de productos", "operationId": "list_products_option", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de variante/opción de productos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["product_options:read"], "description": "Requiere scope `product_options:read`."}}, "/products/options/{products_option_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener variante/opción de producto por id", "operationId": "get_products_option", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "products_option_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Variante/opción de producto.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["product_options:read"], "description": "Requiere scope `product_options:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar variante/opción de producto", "operationId": "update_products_option", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "products_option_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Variante/opción de producto actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["product_options:write"], "description": "Requiere scope `product_options:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar variante/opción de producto", "operationId": "delete_products_option", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "products_option_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Variante/opción de producto eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["product_options:write"], "description": "Requiere scope `product_options:write`."}}, "/products/pricing-profiles/": {"post": {"tags": ["Catálogo"], "summary": "Crear perfil de precio", "operationId": "create_pricing_profile", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Perfil de precio creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["pricing_profiles:write"], "description": "Requiere scope `pricing_profiles:write`."}}, "/products/pricing-profiles/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar perfil de precios", "operationId": "list_pricing_profile", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de perfil de precios.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pricing_profiles:read"], "description": "Requiere scope `pricing_profiles:read`."}}, "/products/pricing-profiles/{pricing_profile_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener perfil de precio por id", "operationId": "get_pricing_profile", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pricing_profile_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Perfil de precio.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pricing_profiles:read"], "description": "Requiere scope `pricing_profiles:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar perfil de precio", "operationId": "update_pricing_profile", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pricing_profile_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Perfil de precio actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pricing_profiles:write"], "description": "Requiere scope `pricing_profiles:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar perfil de precio", "operationId": "delete_pricing_profile", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "pricing_profile_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Perfil de precio eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["pricing_profiles:write"], "description": "Requiere scope `pricing_profiles:write`."}}, "/products/{product_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener producto", "operationId": "get_product", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "product_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Producto.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Product"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["products:read"], "description": "Requiere scope `products:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar producto", "operationId": "update_product", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "product_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProductUpdate"}}}}, "responses": {"200": {"description": "Producto actualizado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Product"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["products:write"], "description": "Requiere scope `products:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar producto", "operationId": "delete_product", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "product_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Producto eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["products:write"], "description": "Requiere scope `products:write`."}}, "/promotions/": {"post": {"tags": ["Catálogo"], "summary": "Crear promoción", "operationId": "create_promotion", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Promoción creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["promotions:write"], "description": "Requiere scope `promotions:write`."}}, "/promotions/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar promocións", "operationId": "list_promotion", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de promocións.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["promotions:read"], "description": "Requiere scope `promotions:read`."}}, "/promotions/{promotion_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener promoción por id", "operationId": "get_promotion", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "promotion_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Promoción.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["promotions:read"], "description": "Requiere scope `promotions:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar promoción", "operationId": "update_promotion", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "promotion_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Promoción actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["promotions:write"], "description": "Requiere scope `promotions:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar promoción", "operationId": "delete_promotion", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "promotion_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Promoción eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["promotions:write"], "description": "Requiere scope `promotions:write`."}}, "/received_invoices/": {"post": {"tags": ["Facturación"], "summary": "Crear factura de compra", "operationId": "create_received_invoice", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Factura de compra creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["received_invoices:write"], "description": "Requiere scope `received_invoices:write`."}}, "/received_invoices/list/": {"get": {"tags": ["Facturación"], "summary": "Listar factura de compras", "operationId": "list_received_invoice", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de factura de compras.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["received_invoices:read"], "description": "Requiere scope `received_invoices:read`."}}, "/received_invoices/{received_invoice_id}/": {"get": {"tags": ["Facturación"], "summary": "Obtener factura de compra por id", "operationId": "get_received_invoice", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "received_invoice_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Factura de compra.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["received_invoices:read"], "description": "Requiere scope `received_invoices:read`."}, "put": {"tags": ["Facturación"], "summary": "Actualizar factura de compra", "operationId": "update_received_invoice", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "received_invoice_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Factura de compra actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["received_invoices:write"], "description": "Requiere scope `received_invoices:write`."}, "delete": {"tags": ["Facturación"], "summary": "Eliminar factura de compra", "operationId": "delete_received_invoice", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "received_invoice_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Factura de compra eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["received_invoices:write"], "description": "Requiere scope `received_invoices:write`."}}, "/rentals/": {"post": {"tags": ["Catálogo"], "summary": "Crear alquiler", "operationId": "create_rental", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Alquiler creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["rentals:write"], "description": "Requiere scope `rentals:write`."}}, "/rentals/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar alquilers", "operationId": "list_rental", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de alquilers.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["rentals:read"], "description": "Requiere scope `rentals:read`."}}, "/rentals/{rental_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener alquiler por id", "operationId": "get_rental", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rental_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Alquiler.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["rentals:read"], "description": "Requiere scope `rentals:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar alquiler", "operationId": "update_rental", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rental_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Alquiler actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["rentals:write"], "description": "Requiere scope `rentals:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar alquiler", "operationId": "delete_rental", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rental_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Alquiler eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["rentals:write"], "description": "Requiere scope `rentals:write`."}}, "/rewards/": {"post": {"tags": ["Clientes"], "summary": "Crear recompensa (beneficios)", "operationId": "create_rewards", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Recompensa (beneficios) creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["benefits:write"], "description": "Requiere scope `benefits:write`."}}, "/rewards/list/": {"get": {"tags": ["Clientes"], "summary": "Listar recompensa (beneficios)s", "operationId": "list_rewards", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de recompensa (beneficios)s.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["benefits:read"], "description": "Requiere scope `benefits:read`."}}, "/rewards/{rewards_id}/": {"get": {"tags": ["Clientes"], "summary": "Obtener recompensa (beneficios) por id", "operationId": "get_rewards", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rewards_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Recompensa (beneficios).", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["benefits:read"], "description": "Requiere scope `benefits:read`."}, "put": {"tags": ["Clientes"], "summary": "Actualizar recompensa (beneficios)", "operationId": "update_rewards", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rewards_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Recompensa (beneficios) actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["benefits:write"], "description": "Requiere scope `benefits:write`."}, "delete": {"tags": ["Clientes"], "summary": "Eliminar recompensa (beneficios)", "operationId": "delete_rewards", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "rewards_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Recompensa (beneficios) eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["benefits:write"], "description": "Requiere scope `benefits:write`."}}, "/sales/": {"post": {"tags": ["Ventas"], "summary": "Crear venta", "operationId": "create_sale", "description": "Soporta reintentos seguros vía el header `Idempotency-Key`. Con `generate_invoice: true` la venta dispara la emisión del comprobante asociado. Requiere scope `sales:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SaleCreate"}}}}, "responses": {"201": {"description": "Venta creada (o respuesta reproducida si el Idempotency-Key ya se había usado).", "headers": {"Idempotency-Replayed": {"$ref": "#/components/headers/IdempotencyReplayed"}}, "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Sale"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "422": {"$ref": "#/components/responses/UnprocessableEntity"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales:write"]}}, "/sales/list/": {"get": {"tags": ["Ventas"], "summary": "Listar ventas", "operationId": "list_sales", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de ventas.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/Sale"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales:read"], "description": "Requiere scope `sales:read`."}}, "/sales/{sale_id}/": {"get": {"tags": ["Ventas"], "summary": "Obtener venta", "operationId": "get_sale", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "sale_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Venta.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Sale"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales:read"], "description": "Requiere scope `sales:read`."}, "put": {"tags": ["Ventas"], "summary": "Actualizar venta", "operationId": "update_sale", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "sale_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SaleCreate"}}}}, "responses": {"200": {"description": "Venta actualizada.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/Sale"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales:write"], "description": "Requiere scope `sales:write`."}, "delete": {"tags": ["Ventas"], "summary": "Eliminar venta", "operationId": "delete_sale", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "sale_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Venta eliminada.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["sales:write"], "description": "Requiere scope `sales:write`."}}, "/sandbox/reset/": {"post": {"tags": ["Sandbox"], "summary": "Vaciar la base de datos sandbox", "operationId": "reset_sandbox", "description": "Solo funciona con un token `yf_test_*`: dropea la base de datos sandbox del tenant entera (todas las colecciones). Un token `yf_live_*` autentica pero recibe 403 — nunca puede alcanzar un drop de base de datos por este endpoint. La próxima escritura recrea la base vacía.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "responses": {"200": {"description": "Sandbox vaciado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/SandboxResetResponse"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"description": "El token es de modo live, no de sandbox.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}}}, "/services/": {"post": {"tags": ["Catálogo"], "summary": "Crear servicio", "operationId": "create_service", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Servicio creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["services:write"], "description": "Requiere scope `services:write`."}}, "/services/list/": {"get": {"tags": ["Catálogo"], "summary": "Listar servicios", "operationId": "list_service", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de servicios.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["services:read"], "description": "Requiere scope `services:read`."}}, "/services/{service_id}/": {"get": {"tags": ["Catálogo"], "summary": "Obtener servicio por id", "operationId": "get_service", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Servicio.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["services:read"], "description": "Requiere scope `services:read`."}, "put": {"tags": ["Catálogo"], "summary": "Actualizar servicio", "operationId": "update_service", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Servicio actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["services:write"], "description": "Requiere scope `services:write`."}, "delete": {"tags": ["Catálogo"], "summary": "Eliminar servicio", "operationId": "delete_service", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "service_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Servicio eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["services:write"], "description": "Requiere scope `services:write`."}}, "/suppliers/": {"post": {"tags": ["Compras"], "summary": "Crear proveedor", "operationId": "create_supplier", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Proveedor creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["suppliers:write"], "description": "Requiere scope `suppliers:write`."}}, "/suppliers/list/": {"get": {"tags": ["Compras"], "summary": "Listar proveedors", "operationId": "list_supplier", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de proveedors.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["suppliers:read"], "description": "Requiere scope `suppliers:read`."}}, "/suppliers/{supplier_id}/": {"get": {"tags": ["Compras"], "summary": "Obtener proveedor por id", "operationId": "get_supplier", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supplier_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Proveedor.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["suppliers:read"], "description": "Requiere scope `suppliers:read`."}, "put": {"tags": ["Compras"], "summary": "Actualizar proveedor", "operationId": "update_supplier", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supplier_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Proveedor actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["suppliers:write"], "description": "Requiere scope `suppliers:write`."}, "delete": {"tags": ["Compras"], "summary": "Eliminar proveedor", "operationId": "delete_supplier", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supplier_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Proveedor eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["suppliers:write"], "description": "Requiere scope `suppliers:write`."}}, "/supplies/": {"post": {"tags": ["Compras"], "summary": "Crear insumo", "operationId": "create_supply", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Insumo creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["supplies:write"], "description": "Requiere scope `supplies:write`."}}, "/supplies/list/": {"get": {"tags": ["Compras"], "summary": "Listar insumos", "operationId": "list_supply", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de insumos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:read"], "description": "Requiere scope `supplies:read`."}}, "/supplies/{supply_id}/": {"get": {"tags": ["Compras"], "summary": "Obtener insumo por id", "operationId": "get_supply", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supply_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Insumo.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:read"], "description": "Requiere scope `supplies:read`."}, "put": {"tags": ["Compras"], "summary": "Actualizar insumo", "operationId": "update_supply", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supply_id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"200": {"description": "Insumo actualizado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:write"], "description": "Requiere scope `supplies:write`."}, "delete": {"tags": ["Compras"], "summary": "Eliminar insumo", "operationId": "delete_supply", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supply_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Insumo eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:write"], "description": "Requiere scope `supplies:write`."}}, "/supply-consumptions/": {"post": {"tags": ["Compras"], "summary": "Crear consumo de insumo", "operationId": "create_supply_consumption", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntity"}}}}, "responses": {"201": {"description": "Consumo de insumo creado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}, "500": {"$ref": "#/components/responses/InternalError"}}, "x-required-scope": ["supplies:write"], "description": "Requiere scope `supplies:write`."}}, "/supply-consumptions/list/": {"get": {"tags": ["Compras"], "summary": "Listar consumo de insumos", "operationId": "list_supply_consumption", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}, {"$ref": "#/components/parameters/Search"}, {"$ref": "#/components/parameters/Sort"}, {"$ref": "#/components/parameters/SortDir"}, {"$ref": "#/components/parameters/Fields"}], "responses": {"200": {"description": "Listado paginado de consumo de insumos.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericListResponse"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:read"], "description": "Requiere scope `supplies:read`."}}, "/supply-consumptions/{supply_consumption_id}/": {"get": {"tags": ["Compras"], "summary": "Obtener consumo de insumo por id", "operationId": "get_supply_consumption", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supply_consumption_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Consumo de insumo.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GenericEntityResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:read"], "description": "Requiere scope `supplies:read`."}, "delete": {"tags": ["Compras"], "summary": "Eliminar consumo de insumo", "operationId": "delete_supply_consumption", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "supply_consumption_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Consumo de insumo eliminado.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DeleteSuccess"}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["supplies:write"], "description": "Requiere scope `supplies:write`."}}, "/webhooks/deliveries": {"get": {"tags": ["Webhooks"], "summary": "Historial de entregas", "operationId": "list_webhook_deliveries", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "event_type", "in": "query", "schema": {"type": "string"}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["pending", "retrying", "success", "failed"]}}, {"name": "endpoint_id", "in": "query", "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}, {"name": "offset", "in": "query", "schema": {"type": "integer", "default": 0}}], "responses": {"200": {"description": "Entregas recientes.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"deliveries": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookDelivery"}}, "total": {"type": "integer"}, "limit": {"type": "integer"}, "offset": {"type": "integer"}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}}, "x-required-scope": ["webhooks:read"], "description": "Requiere scope `webhooks:read`."}}, "/webhooks/deliveries/{delivery_id}": {"get": {"tags": ["Webhooks"], "summary": "Detalle de una entrega (todos los intentos)", "operationId": "get_webhook_delivery", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "delivery_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Entrega con su historial de intentos.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/WebhookDelivery"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}}, "x-required-scope": ["webhooks:read"], "description": "Requiere scope `webhooks:read`."}}, "/webhooks/endpoints": {"get": {"tags": ["Webhooks"], "summary": "Listar endpoints registrados", "operationId": "list_webhook_endpoints", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "responses": {"200": {"description": "Endpoints del tenant (hasta 20 activos).", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"endpoints": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookEndpoint"}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}}, "x-required-scope": ["webhooks:read"], "description": "Requiere scope `webhooks:read`."}, "post": {"tags": ["Webhooks"], "summary": "Registrar un endpoint", "operationId": "create_webhook_endpoint", "description": "Devuelve el secreto de firma (`whsec_...`) UNA sola vez. La URL se valida contra SSRF (rechaza IPs privadas/loopback/link-local). Máximo 20 endpoints activos por tenant. Requiere scope `webhooks:write`.", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookEndpointCreate"}}}}, "responses": {"201": {"description": "Endpoint creado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/WebhookEndpointCreated"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "400": {"$ref": "#/components/responses/BadRequest"}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "409": {"$ref": "#/components/responses/Conflict"}, "429": {"$ref": "#/components/responses/TooManyRequests"}}, "x-required-scope": ["webhooks:write"]}}, "/webhooks/endpoints/{endpoint_id}": {"get": {"tags": ["Webhooks"], "summary": "Obtener un endpoint", "operationId": "get_webhook_endpoint", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "endpoint_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Endpoint (sin el secreto).", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/WebhookEndpoint"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}}, "x-required-scope": ["webhooks:read"], "description": "Requiere scope `webhooks:read`."}, "delete": {"tags": ["Webhooks"], "summary": "Eliminar un endpoint", "operationId": "delete_webhook_endpoint", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "parameters": [{"name": "endpoint_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Endpoint eliminado.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"id": {"type": "string"}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}, "404": {"$ref": "#/components/responses/NotFound"}}, "x-required-scope": ["webhooks:write"], "description": "Requiere scope `webhooks:write`."}}, "/webhooks/events": {"get": {"tags": ["Webhooks"], "summary": "Catálogo de eventos suscribibles", "operationId": "list_webhook_events", "security": [{"ApiKeyHeader": []}, {"ApiKeyBearer": []}], "responses": {"200": {"description": "Eventos disponibles.", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"events": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookEvent"}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "403": {"$ref": "#/components/responses/Forbidden"}}, "x-required-scope": ["webhooks:read"], "description": "Requiere scope `webhooks:read`."}}}, "components": {"securitySchemes": {"ApiKeyHeader": {"type": "apiKey", "in": "header", "name": "X-API-Key", "description": "Token opaco `yf_live_*` (producción) o `yf_test_*` (sandbox). Tiene prioridad sobre `Authorization: Bearer` si ambos están presentes. Se genera desde Configuración > API Tokens (Premium, o durante el trial) y se guarda como hash — el valor crudo solo se muestra una vez al crearlo."}, "ApiKeyBearer": {"type": "http", "scheme": "bearer", "bearerFormat": "yf_live_*  |  yf_test_*", "description": "Alternativa a X-API-Key: `Authorization: Bearer yf_live_...`."}}, "parameters": {"IdempotencyKey": {"name": "Idempotency-Key", "in": "header", "required": false, "description": "Clave elegida por el cliente (hasta 255 caracteres) para hacer este POST seguro de reintentar. Un segundo request con la MISMA clave y el MISMO body reproduce la respuesta original (200/201, header `Idempotency-Replayed: true`) en vez de crear un segundo recurso. La misma clave con un body DISTINTO devuelve 422. La clave está scopeada al token exacto (yf_live_*/yf_test_*) que la usó — dos tokens nunca colisionan aunque manden la misma clave. TTL: 24 horas.", "schema": {"type": "string", "maxLength": 255}, "example": "550e8400-e29b-41d4-a716-446655440000"}, "Page": {"name": "page", "in": "query", "description": "Número de página (1-indexed).", "schema": {"type": "integer", "minimum": 1, "default": 1}}, "PerPage": {"name": "per_page", "in": "query", "description": "Resultados por página.", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 20}}, "Search": {"name": "search", "in": "query", "description": "Término de búsqueda libre (aplica a los campos indexados de texto de la entidad).", "schema": {"type": "string"}}, "Sort": {"name": "sort", "in": "query", "description": "Campo de ordenamiento. Los campos válidos varían por entidad; uno inválido cae al default (`creation_date`).", "schema": {"type": "string", "default": "creation_date"}}, "SortDir": {"name": "sort_dir", "in": "query", "description": "Dirección de orden: 1 = ascendente, -1 = descendente.", "schema": {"type": "integer", "enum": [1, -1], "default": -1}}, "Fields": {"name": "fields", "in": "query", "description": "Lista de campos separados por coma para proyectar la respuesta (p. ej. `id,name,email`). Reduce el payload cuando solo se necesitan algunos campos.", "schema": {"type": "string"}}, "EntityId": {"name": "entity_id_path", "in": "path", "required": true, "description": "placeholder — sobreescrito por operación", "schema": {"type": "string"}}}, "headers": {"RateLimitLimit": {"description": "Límite de requests para la ventana vigente.", "schema": {"type": "integer"}}, "RateLimitRemaining": {"description": "Requests restantes en la ventana vigente.", "schema": {"type": "integer"}}, "RateLimitReset": {"description": "Segundos hasta que la ventana actual expira.", "schema": {"type": "integer"}}, "RetryAfter": {"description": "Segundos a esperar antes de reintentar (solo en 429).", "schema": {"type": "integer"}}, "IdempotencyReplayed": {"description": "Presente y en `true` cuando la respuesta es la reproducción de un request anterior con el mismo Idempotency-Key.", "schema": {"type": "boolean"}}}, "responses": {"BadRequest": {"description": "Solicitud inválida (body ausente o con formato incorrecto).", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Invalid request body", "code": "VALIDATION_ERROR"}}}}, "Unauthorized": {"description": "Falta autenticación o el token es inválido/expiró.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "API key required. Use X-API-Key header or Authorization: Bearer yf_live_*", "code": "UNAUTHORIZED"}}}}, "Forbidden": {"description": "El token no tiene el/los scope(s) requeridos, o el plan del tenant no habilita el módulo.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Token missing required scope: products:write", "code": "FORBIDDEN"}}}}, "NotFound": {"description": "El recurso solicitado no existe (o no pertenece a este tenant).", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Not found", "code": "NOT_FOUND"}}}}, "Conflict": {"description": "Conflicto de estado (p. ej. editar un recurso en un estado que no lo permite).", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Resource is in a state that does not allow this operation", "code": "CONFLICT"}}}}, "UnprocessableEntity": {"description": "Semánticamente inválido — incluye la reutilización de un Idempotency-Key con un body distinto.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Idempotency-Key was already used with a different request body", "code": "UNPROCESSABLE_ENTITY"}}}}, "TooManyRequests": {"description": "Se superó el rate limit del endpoint o del tenant. Ver headers `X-RateLimit-*` y `Retry-After`.", "headers": {"X-RateLimit-Limit": {"$ref": "#/components/headers/RateLimitLimit"}, "X-RateLimit-Remaining": {"$ref": "#/components/headers/RateLimitRemaining"}, "X-RateLimit-Reset": {"$ref": "#/components/headers/RateLimitReset"}, "Retry-After": {"$ref": "#/components/headers/RetryAfter"}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Rate limit exceeded", "code": "RATE_LIMITED"}}}}, "InternalError": {"description": "Error inesperado del servidor.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}, "example": {"success": false, "error": "Internal server error", "code": "INTERNAL_ERROR"}}}}}, "schemas": {"Error": {"type": "object", "required": ["success", "error", "code"], "properties": {"success": {"type": "boolean", "enum": [false], "example": false}, "error": {"type": "string", "description": "Mensaje de error legible.", "example": "Not found"}, "code": {"type": "string", "description": "Código de error estable y parseable (ver ResponseCode del backend).", "example": "NOT_FOUND", "enum": ["NOT_FOUND", "BAD_REQUEST", "VALIDATION_ERROR", "BUSINESS_ERROR", "UNAUTHORIZED", "FORBIDDEN", "CONFLICT", "INTERNAL_ERROR", "UNPROCESSABLE_ENTITY", "RATE_LIMITED", "SERVICE_UNAVAILABLE"]}, "errors": {"type": "array", "description": "Detalle opcional por campo (solo en errores de validación).", "items": {"type": "string"}}}}, "GenericEntity": {"type": "object", "description": "Forma del recurso deliberadamente permisiva: el backend valida contra un JSON Schema propio por entidad (no publicado aún en este spec — ver 'Deferred / not yet in this spec' en la descripción raíz). Todo documento devuelto trae como mínimo `id` y las marcas de tiempo.", "properties": {"id": {"type": "string", "description": "Identificador del recurso (ObjectId de 24 hex o UUID)."}, "creation_date": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}, "additionalProperties": true}, "Links": {"type": "object", "description": "Mapa HATEOAS: cada valor es un link accionable relativo a este recurso.", "additionalProperties": {"type": "object", "properties": {"href": {"type": "string"}, "method": {"type": "string"}, "title": {"type": "string"}}}}, "GenericEntityResponse": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"$ref": "#/components/schemas/GenericEntity"}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}, "GenericListResponse": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "object", "properties": {"items": {"type": "array", "items": {"$ref": "#/components/schemas/GenericEntity"}}, "total": {"type": "integer", "example": 128}, "page": {"type": "integer", "example": 1}, "per_page": {"type": "integer", "example": 20}, "total_pages": {"type": "integer", "example": 7}, "_meta": {"type": "object", "properties": {"sortable_fields": {"type": "array", "items": {"type": "string"}}, "current_sort": {"type": "string"}, "sort_direction": {"type": "string", "enum": ["asc", "desc"]}}}}}, "message": {"type": "string"}, "_links": {"$ref": "#/components/schemas/Links"}}}, "DeleteSuccess": {"type": "object", "properties": {"success": {"type": "boolean", "enum": [true], "example": true}, "data": {"type": "string", "example": "Category deleted successfully"}, "message": {"type": "string"}}}, "Product": {"allOf": [{"$ref": "#/components/schemas/GenericEntity"}, {"type": "object", "properties": {"name": {"type": "string"}, "sku": {"type": "string"}, "base_price": {"type": "number"}, "stock": {"type": "number"}, "status": {"type": "string"}, "category_id": {"type": "string"}, "images": {"type": "array", "items": {"type": "string"}}}}]}, "ProductCreate": {"type": "object", "required": ["name", "base_price"], "properties": {"name": {"type": "string", "minLength": 1, "maxLength": 200, "example": "Notebook 15\""}, "description": {"type": "string"}, "sku": {"type": "string"}, "barcode": {"type": "string"}, "category_id": {"type": "string"}, "base_price": {"type": "number", "minimum": 0, "maximum": 999999999999.99, "example": 450000}, "cost": {"type": "number", "minimum": 0, "maximum": 999999999999.99}, "track_stock": {"type": "boolean", "default": false}, "stock": {"type": "number", "minimum": 0, "maximum": 999999999, "description": "Fraccionario para productos vendidos por peso (kg/g)."}, "min_stock": {"type": "number", "minimum": 0, "maximum": 999999999}, "manage_batches": {"type": "boolean"}, "unit": {"type": "string", "example": "unidad"}, "status": {"type": "string", "enum": ["draft", "active", "paused", "archived"]}, "images": {"type": "array", "items": {"type": "string", "format": "uri"}}, "attributes": {"type": "object", "additionalProperties": true}, "brand": {"type": "string", "maxLength": 120}, "model": {"type": "string", "maxLength": 120}, "tags": {"type": "array", "items": {"type": "string"}}, "tax_rate": {"type": "number", "minimum": 0, "maximum": 100, "description": "Alícuota de IVA en %."}, "weight": {"type": "number", "minimum": 0}, "dimensions": {"type": "object"}, "featured": {"type": "boolean"}, "warehouse_id": {"type": "string", "description": "Depósito al que imputar el stock inicial (multi-almacén). Ausente = depósito default."}, "variants": {"oneOf": [{"type": "array"}, {"type": "object"}], "description": "Variantes del producto. Se acepta objeto `{sku: {...}}` (se normaliza a array preservando la key como id) o array directo."}, "has_variants": {"type": "boolean"}, "quantity_price_tiers": {"type": "array", "items": {"type": "object", "required": ["min_quantity"], "properties": {"min_quantity": {"type": "integer", "minimum": 1}, "max_quantity": {"type": ["integer", "null"], "minimum": 1}, "price": {"type": ["number", "null"], "minimum": 0}, "discount_percentage": {"type": ["number", "null"], "minimum": 0, "maximum": 100}}}}, "marketplace_attributes": {"type": "object", "description": "Atributos por marketplace, con los ids nativos de esa plataforma (ej. ML: GENDER, GARMENT_TYPE).", "additionalProperties": {"type": "array", "items": {"type": "object", "required": ["id", "value"], "properties": {"id": {"type": "string"}, "value": {"type": "string"}}}}}}, "additionalProperties": true}, "ProductUpdate": {"type": "object", "description": "Mismos campos que ProductCreate; todos opcionales (PUT parcial — solo se actualizan los campos enviados).", "properties": {"name": {"type": "string", "minLength": 1, "maxLength": 200, "example": "Notebook 15\""}, "description": {"type": "string"}, "sku": {"type": "string"}, "barcode": {"type": "string"}, "category_id": {"type": "string"}, "base_price": {"type": "number", "minimum": 0, "maximum": 999999999999.99, "example": 450000}, "cost": {"type": "number", "minimum": 0, "maximum": 999999999999.99}, "track_stock": {"type": "boolean", "default": false}, "stock": {"type": "number", "minimum": 0, "maximum": 999999999, "description": "Fraccionario para productos vendidos por peso (kg/g)."}, "min_stock": {"type": "number", "minimum": 0, "maximum": 999999999}, "manage_batches": {"type": "boolean"}, "unit": {"type": "string", "example": "unidad"}, "status": {"type": "string", "enum": ["draft", "active", "paused", "archived"]}, "images": {"type": "array", "items": {"type": "string", "format": "uri"}}, "attributes": {"type": "object", "additionalProperties": true}, "brand": {"type": "string", "maxLength": 120}, "model": {"type": "string", "maxLength": 120}, "tags": {"type": "array", "items": {"type": "string"}}, "tax_rate": {"type": "number", "minimum": 0, "maximum": 100, "description": "Alícuota de IVA en %."}, "weight": {"type": "number", "minimum": 0}, "dimensions": {"type": "object"}, "featured": {"type": "boolean"}, "warehouse_id": {"type": "string", "description": "Depósito al que imputar el stock inicial (multi-almacén). Ausente = depósito default."}, "variants": {"oneOf": [{"type": "array"}, {"type": "object"}], "description": "Variantes del producto. Se acepta objeto `{sku: {...}}` (se normaliza a array preservando la key como id) o array directo."}, "has_variants": {"type": "boolean"}, "quantity_price_tiers": {"type": "array", "items": {"type": "object", "required": ["min_quantity"], "properties": {"min_quantity": {"type": "integer", "minimum": 1}, "max_quantity": {"type": ["integer", "null"], "minimum": 1}, "price": {"type": ["number", "null"], "minimum": 0}, "discount_percentage": {"type": ["number", "null"], "minimum": 0, "maximum": 100}}}}, "marketplace_attributes": {"type": "object", "description": "Atributos por marketplace, con los ids nativos de esa plataforma (ej. ML: GENDER, GARMENT_TYPE).", "additionalProperties": {"type": "array", "items": {"type": "object", "required": ["id", "value"], "properties": {"id": {"type": "string"}, "value": {"type": "string"}}}}}}, "additionalProperties": true}, "Customer": {"allOf": [{"$ref": "#/components/schemas/GenericEntity"}, {"type": "object", "properties": {"name": {"type": "string"}, "email": {"type": "string"}, "phone": {"type": "string"}, "document_type": {"type": "string"}, "document_number": {"type": "string"}, "status": {"type": "string"}, "credit_limit": {"type": ["number", "null"]}}}]}, "CustomerCreate": {"type": "object", "required": ["name"], "properties": {"name": {"type": "string", "minLength": 2, "maxLength": 200, "example": "Juan Pérez"}, "email": {"type": "string", "format": "email"}, "customer_email": {"type": "string", "format": "email"}, "phone": {"type": "string", "example": "+5491122334455"}, "document_type": {"type": "string", "enum": ["", "dni", "cuit", "cuil", "passport", "cedula", "other"]}, "document_number": {"type": "string", "maxLength": 20, "example": "20345678901"}, "address": {"oneOf": [{"type": "string"}, {"type": "object"}, {"type": "null"}]}, "status": {"type": "string", "enum": ["active", "inactive", "blocked"], "default": "active"}, "notes": {"type": "string", "maxLength": 1000}, "tags": {"type": "array", "items": {"type": "string"}}, "custom_fields": {"type": "object", "additionalProperties": true}, "metadata": {"type": "object", "additionalProperties": true}, "credit_limit": {"type": ["number", "null"], "minimum": 0, "description": "Límite de cuenta corriente. `null`/ausente = crédito ilimitado."}, "credit_blocked": {"type": "boolean"}}, "additionalProperties": true}, "CustomerUpdate": {"type": "object", "description": "Mismos campos que CustomerCreate, todos opcionales.", "properties": {"name": {"type": "string", "minLength": 2, "maxLength": 200, "example": "Juan Pérez"}, "email": {"type": "string", "format": "email"}, "customer_email": {"type": "string", "format": "email"}, "phone": {"type": "string", "example": "+5491122334455"}, "document_type": {"type": "string", "enum": ["", "dni", "cuit", "cuil", "passport", "cedula", "other"]}, "document_number": {"type": "string", "maxLength": 20, "example": "20345678901"}, "address": {"oneOf": [{"type": "string"}, {"type": "object"}, {"type": "null"}]}, "status": {"type": "string", "enum": ["active", "inactive", "blocked"], "default": "active"}, "notes": {"type": "string", "maxLength": 1000}, "tags": {"type": "array", "items": {"type": "string"}}, "custom_fields": {"type": "object", "additionalProperties": true}, "metadata": {"type": "object", "additionalProperties": true}, "credit_limit": {"type": ["number", "null"], "minimum": 0, "description": "Límite de cuenta corriente. `null`/ausente = crédito ilimitado."}, "credit_blocked": {"type": "boolean"}}, "additionalProperties": true}, "SaleItem": {"type": "object", "description": "Ítem de venta. La forma exacta depende de si referencia un producto/servicio/alquiler existente o es un ítem libre.", "properties": {"product_id": {"type": "string"}, "publication_id": {"type": "string"}, "publication_type": {"type": "string", "enum": ["product", "services", "rental"]}, "name": {"type": "string"}, "quantity": {"type": "number", "minimum": 0}, "price": {"type": "number", "minimum": 0}, "variant_id": {"type": "string"}, "discount_percent": {"type": "number", "minimum": 0, "maximum": 100}, "group_id": {"type": ["string", "null"]}}, "additionalProperties": true}, "Sale": {"allOf": [{"$ref": "#/components/schemas/GenericEntity"}, {"type": "object", "properties": {"customer_id": {"type": "string"}, "items": {"type": "array", "items": {"$ref": "#/components/schemas/SaleItem"}}, "subtotal": {"type": "number"}, "total": {"type": "number"}, "status": {"type": "string"}, "payment_status": {"type": "string"}, "sale_origin": {"type": "string"}, "invoice_id": {"type": "string", "description": "Id del comprobante AFIP asociado, si generate_invoice fue true."}}}]}, "SaleCreate": {"type": "object", "required": ["items"], "properties": {"customer_id": {"type": "string"}, "customer": {"type": "string", "description": "Alternativa a customer_id: puede ser \"no-customer\" o un id."}, "items": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/SaleItem"}}, "payment_method": {"type": "string"}, "notes": {"type": "string"}, "requires_shipping": {"type": "boolean"}, "sale_origin": {"type": "string", "enum": ["manual", "pos", "ecommerce", "order", "budget", "contract", "rental_booking", "appointment", "mercadolibre", "tiendanube", "shopify", "subscription"], "default": "manual"}, "shipping_method": {"type": "string"}, "shipping_cost": {"type": "number", "minimum": 0}, "shipping_address": {"type": "object", "additionalProperties": true}, "generate_invoice": {"type": "boolean", "description": "Si true, dispara la emisión del comprobante AFIP asociado tras crear la venta."}, "subtotal": {"type": "number", "minimum": 0}, "total": {"type": "number", "minimum": 0}, "tax_type": {"type": "string"}, "tax_rate": {"type": "number", "minimum": 0, "maximum": 100}, "discount_type": {"type": "string"}, "discount_rate": {"type": "number", "minimum": 0, "maximum": 100}, "payment": {"type": "object", "additionalProperties": true}, "warehouse_id": {"type": "string", "description": "Depósito desde el que se descuenta el stock."}, "sales_point_id": {"type": "string", "description": "Punto de venta fiscal (determina el PV de la factura si se emite)."}}, "additionalProperties": true}, "InvoiceCreateRequest": {"type": "object", "description": "Datos del comprobante a emitir. El tipo (Factura A/B/C) se infiere de la condición de IVA del emisor si `tipo_comprobante` se omite. En un token `yf_test_*` este endpoint NUNCA llama a AFIP: guarda un comprobante simulado con un CAE sintético (`simulated: true`, `livemode: false`) en la base sandbox del tenant.", "required": ["tipo_documento", "numero_documento", "items"], "properties": {"tipo_comprobante": {"type": "integer", "description": "Código AFIP del tipo de comprobante (6=Factura B, 1=Factura A, 11=Factura C, ...). Opcional: se infiere si se omite.", "example": 6}, "punto_venta": {"type": "integer", "minimum": 1, "example": 1}, "tipo_documento": {"type": "integer", "description": "Código AFIP del tipo de documento del receptor (80=CUIT, 96=DNI, 99=Consumidor Final).", "example": 96}, "numero_documento": {"type": "string", "example": "30712345678"}, "razon_social": {"type": "string", "example": "Consumidor Final"}, "domicilio": {"type": "string"}, "condicion_iva_receptor": {"type": "string"}, "items": {"type": "array", "minItems": 1, "items": {"type": "object", "properties": {"descripcion": {"type": "string"}, "cantidad": {"type": "number", "minimum": 0}, "precio_unitario": {"type": "number", "minimum": 0}, "alicuota_iva": {"type": "string", "description": "Código AFIP de alícuota (5=21%, 4=10.5%, 3=0%, ...)."}}}}, "importe_total": {"type": "number", "minimum": 0}, "customer_id": {"type": "string", "description": "Id del cliente en YoFacturo (alternativa a mandar los datos fiscales sueltos)."}, "sale_id": {"type": "string", "description": "Venta de origen, si corresponde."}, "ambiente": {"type": "string", "enum": ["production", "testing"], "default": "production", "description": "Ambiente AFIP real a usar (no confundir con el modo sandbox del token, que directamente evita la llamada)."}, "autorizar": {"type": "boolean", "default": false, "description": "Si true, dispara la autorización (obtención del CAE) en background inmediatamente después de crear el borrador."}}, "additionalProperties": true}, "NoteCreateRequest": {"type": "object", "description": "Nota de crédito/débito asociada a un comprobante existente.", "required": ["comprobante_asociado_id", "items"], "properties": {"comprobante_asociado_id": {"type": "string", "description": "Id del comprobante (factura) que esta nota ajusta."}, "motivo": {"type": "string", "example": "Devolución parcial de mercadería"}, "items": {"type": "array", "minItems": 1, "items": {"type": "object", "additionalProperties": true}}, "importe_total": {"type": "number", "minimum": 0}, "ambiente": {"type": "string", "enum": ["production", "testing"], "default": "production"}}, "additionalProperties": true}, "Comprobante": {"type": "object", "properties": {"id": {"type": "string"}, "tipo_comprobante": {"type": "integer"}, "punto_venta": {"type": "integer"}, "numero_comprobante": {"type": "integer"}, "cae": {"type": "string", "description": "Código de Autorización Electrónico de AFIP (o sintético en sandbox)."}, "cae_vencimiento": {"type": "string", "example": "20261015"}, "fecha_comprobante": {"type": "string", "example": "20260805"}, "estado": {"type": "string", "example": "autorizado"}, "ambiente": {"type": "string", "example": "production"}, "livemode": {"type": "boolean", "description": "false cuando el comprobante fue emitido por un token yf_test_* (simulado, sin AFIP real)."}, "simulated": {"type": "boolean", "description": "true en modo sandbox: el CAE tiene el formato correcto pero NO es válido para un comprobante fiscal real."}, "iva_handling": {"type": "object", "properties": {"incluye_iva_discriminado": {"type": "boolean"}, "tipo_comprobante_nombre": {"type": "string"}, "condicion_fiscal_emisor": {"type": "string"}}}, "idempotent_replay": {"type": "boolean", "description": "true si esta respuesta es la reproducción de un request anterior idéntico."}}, "additionalProperties": true}, "CurrentAccount": {"allOf": [{"$ref": "#/components/schemas/GenericEntity"}, {"type": "object", "properties": {"entity_type": {"type": "string", "enum": ["customer", "supplier"]}, "entity_id": {"type": "string"}, "entity_name": {"type": "string"}, "balance": {"type": "number", "description": "Saldo actual (positivo = el cliente/proveedor nos debe)."}, "credit_limit": {"type": "number"}, "payment_terms_days": {"type": "integer"}, "status": {"type": "string"}}}]}, "CurrentAccountCreate": {"type": "object", "required": ["entity_type", "entity_id", "entity_name"], "properties": {"entity_type": {"type": "string", "enum": ["customer", "supplier"]}, "entity_id": {"type": "string", "description": "Id del cliente o proveedor dueño de esta cuenta corriente."}, "entity_name": {"type": "string"}, "credit_limit": {"type": "number", "minimum": 0, "maximum": 999999999999.99, "default": 0}, "payment_terms_days": {"type": "integer", "default": 30}}}, "PaymentCreate": {"type": "object", "required": ["amount", "payment_method", "reference"], "description": "El pago se registra en estado pendiente; NO se aplica automáticamente contra facturas salvo `auto_apply: true`.", "properties": {"amount": {"type": "number", "exclusiveMinimum": 0, "maximum": 999999999999.99}, "payment_method": {"type": "string", "example": "credit_card"}, "reference": {"type": "string", "example": "TRANS-123"}, "payment_date": {"type": "string", "format": "date-time"}, "auto_apply": {"type": "boolean", "default": false, "description": "Si true, reconcilia automáticamente el pago contra facturas pendientes (FIFO)."}, "cash_register_id": {"type": "string", "description": "Caja abierta a la que imputar la cobranza (opcional; omitido = no pasó por una caja)."}}}, "WebhookEndpoint": {"type": "object", "properties": {"id": {"type": "string"}, "url": {"type": "string"}, "description": {"type": "string"}, "events": {"type": "array", "items": {"type": "string"}}, "mode": {"type": "string", "enum": ["live", "test"], "description": "Derivado de si el endpoint se creó con un token yf_live_* o yf_test_*."}, "secret_prefix": {"type": "string", "description": "Primeros caracteres del secreto (whsec_...), para identificarlo sin volver a mostrarlo entero."}, "is_active": {"type": "boolean"}, "created_at": {"type": "string", "format": "date-time"}, "created_by": {"type": "string"}, "rotated_at": {"type": ["string", "null"], "format": "date-time"}, "last_delivery_at": {"type": ["string", "null"], "format": "date-time"}, "last_delivery_status": {"type": ["string", "null"]}}}, "WebhookEndpointCreate": {"type": "object", "required": ["url", "events"], "properties": {"url": {"type": "string", "format": "uri", "description": "URL https/http pública. Se rechaza si resuelve a una IP privada/loopback/link-local (protección SSRF)."}, "events": {"type": "array", "minItems": 1, "items": {"type": "string"}, "description": "Uno o más event_type del catálogo (ver GET /webhooks/events)."}, "description": {"type": "string"}}}, "WebhookEndpointCreated": {"allOf": [{"$ref": "#/components/schemas/WebhookEndpoint"}, {"type": "object", "properties": {"secret": {"type": "string", "description": "Secreto completo `whsec_...` usado para firmar cada delivery (HMAC-SHA256). Se devuelve UNA SOLA VEZ acá — solo persiste su forma cifrada. Si se pierde, no hay forma de recuperarlo: hay que borrar el endpoint y crear uno nuevo.", "example": "whsec_9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a"}}}]}, "WebhookEvent": {"type": "object", "properties": {"event_type": {"type": "string", "example": "invoice.authorized"}, "description": {"type": "string", "example": "AFIP autorizó el comprobante y le asignó CAE"}}}, "WebhookDelivery": {"type": "object", "properties": {"id": {"type": "string"}, "endpoint_id": {"type": "string"}, "event_type": {"type": "string"}, "payload": {"type": "object", "additionalProperties": true, "description": "El body exacto enviado (mismo que firma X-YF-Signature)."}, "status": {"type": "string", "enum": ["pending", "retrying", "success", "failed"]}, "attempt_count": {"type": "integer"}, "attempts": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookDeliveryAttempt"}}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}, "delivered_at": {"type": ["string", "null"], "format": "date-time"}, "next_retry_at": {"type": ["string", "null"], "format": "date-time"}}}, "WebhookDeliveryAttempt": {"type": "object", "properties": {"attempted_at": {"type": "string", "format": "date-time"}, "status_code": {"type": ["integer", "null"]}, "response_body": {"type": "string", "description": "Truncado a 2000 caracteres."}, "error": {"type": ["string", "null"]}, "duration_ms": {"type": "number"}}}, "SandboxResetResponse": {"type": "object", "properties": {"reset": {"type": "boolean", "example": true}, "sandbox_db": {"type": "string", "description": "Nombre físico de la base de datos sandbox que se vació.", "example": "db_7165cccd__sandbox"}, "livemode": {"type": "boolean", "enum": [false]}}}}}}