{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base",
  "info": {
    "title": "API de clientes empresa de FCM (fase 1)",
    "version": "2026-10-15",
    "summary": "Cuentas de pago en pesos, CVU, transferencias por COELSA y eventos para clientes empresa de FCM Payment Solutions S.A.S.",
    "description": "API para que las empresas clientes de **FCM Payment Solutions S.A.S.** (proveedor de servicios de pago que ofrece\ncuentas de pago, inscripto en el BCRA; PSP 214 en COELSA) operen **cuentas de pago en pesos**: ver saldos, usar sus\nCVU, validar contrapartes, ordenar transferencias por COELSA y enterarse de los créditos entrantes.\n\nEs el contrato de la **fase 1**, multi-cliente desde el día uno: cada entidad tiene sus credenciales, sus claves de\nfirma, su URL de webhook, sus cuentas en el libro, sus CVU, sus topes y su comisión. Este contrato es estable: la implementación puede cambiar y la integración del cliente no.\n\n## Lo que esta API no hace\n\n- **No opera activos digitales.** No hay criptoactivos, stablecoins, direcciones de blockchain, conversiones ni\n  cotizaciones. El TO de PSP del BCRA (punto 4.6) prohíbe a FCM realizarlas y facilitarlas. Si un cliente opera\n  cripto, esa pata la ejecuta otra persona jurídica regulada y FCM sólo mueve pesos contra instrucciones.\n- **No opera moneda extranjera ni giros al exterior.** La única moneda es `ARS` y los destinos son CBU, CVU o alias\n  del sistema argentino.\n- **No crea CVU ni cuentas en fase 1.** Las da de alta FCM a pedido de la entidad (llegan como números de cuenta\n  listables). El alta por API es fase 2.\n\nFCM Payment Solutions S.A.S. se limita a ofrecer servicios de pago y no se encuentra autorizada a operar como\nentidad financiera por el BCRA. Los fondos depositados en cuentas de pago no constituyen depósitos en una entidad\nfinanciera, ni cuentan con ninguna de las garantías que tales depósitos puedan gozar de acuerdo con la legislación\ny reglamentación aplicables en materia de depósitos en entidades financieras.\n\n## Entornos\n\n| | Producción | Sandbox |\n|---|---|---|\n| Host | `https://api.fcmpayments.com` | `https://empresas-sandbox.fcmpayments.com` |\n| API keys | `fcm_live_…` | `fcm_test_…` |\n| Dinero | Real. Las transferencias por COELSA son irreversibles. | Simulado. Libro y riel propios del sandbox. |\n| Simuladores (`/v1/simulations/*`) | No existen (404) | Sí |\n\nUna clave de un entorno usada en el otro responde `403 environment_mismatch`.\n\n## Autenticación: API key y firma de cada pedido\n\nTodo pedido lleva **las dos cosas**:\n\n1. `Authorization: Bearer fcm_live_…`: la API key de la entidad. FCM la guarda hasheada. Puede haber dos activas\n   para rotar sin corte.\n2. **Firma HTTP del pedido (RFC 9421, HTTP Message Signatures)** hecha con la clave privada del cliente. FCM guarda\n   sólo la clave pública, registrada en el alta (hasta dos activas por entorno). Algoritmos: `ed25519` o\n   `ecdsa-p256-sha256`.\n   - Componentes firmados obligatorios: `\"@method\"` y `\"@target-uri\"`. Si el pedido tiene cuerpo, también\n     `\"content-type\"`, `\"content-digest\"` e `\"idempotency-key\"`. Si mandás `FCM-Version`, también\n     `\"fcm-version\"`. **`\"authorization\"` no se firma**: una firma que la cubre se rechaza con\n     `signature_invalid`. Así FCM puede volver a verificar la firma de cada instrucción con tu clave pública, sin\n     tu API key, que sólo guarda hasheada.\n   - Parámetros obligatorios de la firma: `created` (segundos Unix; se acepta ±300 s), `nonce` (16 a 64\n     caracteres base64url, único por clave durante 10 minutos), `keyid` (id de tu clave pública, `ck_…`) y `alg`.\n   - Con cuerpo: `Content-Digest: sha-256=:…:` (RFC 9530) calculado sobre los bytes exactos que mandás.\n\n```http\nPOST /v1/outgoing_transfers HTTP/1.1\nHost: api.fcmpayments.com\nAuthorization: Bearer fcm_live_3kTq…\nContent-Type: application/json\nIdempotency-Key: 01JA2B3C4D5E6F7G8H9JKMNPQR\nContent-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:\nSignature-Input: sig1=(\"@method\" \"@target-uri\" \"content-type\" \"content-digest\" \"idempotency-key\");created=1760112000;nonce=\"Vq3n8sZx0bR1yTqLkM2pWg\";keyid=\"ck_01JA2B3C4D5E6F7G8H9JKMNPQS\";alg=\"ed25519\"\nSignature: sig1=:Kp9…==:\n```\n\nEn producción la entidad puede pedir una lista de IP permitidas. mTLS se ofrece como capa adicional en fase 2 para\nquien lo exija; no reemplaza la firma.\n\n## Idempotencia\n\n- `Idempotency-Key` es **obligatoria en todo `POST`** (16 a 128 caracteres `A-Z a-z 0-9 . _ : -`; recomendado\n  UUID o ULID). El ámbito es la entidad en ese entorno.\n- Misma clave y mismo pedido: misma respuesta (código y cuerpo), con `Idempotent-Replayed: true`.\n- Misma clave con otro pedido (huella SHA-256 de método, ruta y cuerpo canonizado según RFC 8785):\n  `409 idempotency_key_reused`.\n- Mientras el primer pedido está en curso: `409 idempotency_request_in_progress` (reintentable).\n- Las respuestas `5xx` no se guardan: reintentá con la **misma** clave.\n- El registro completo vive **35 días** y se consulta con `GET /v1/idempotency_keys/{idempotency_key}`. La clave de\n  una transferencia queda atada a esa transferencia **para siempre**: no se puede reusar ni pasados los 35 días, y\n  la transferencia se busca con `GET /v1/outgoing_transfers?idempotency_key=…`.\n- Si la primera respuesta se perdió (por ejemplo, un corte), el reintento devuelve el **estado actual** de la misma\n  transferencia, que puede estar más avanzado que el original.\n- Una respuesta `202` se guarda y se repite igual que cualquier `2xx`. El estado vigente se pide con\n  `GET /v1/outgoing_transfers/{id}` o llega por webhook.\n\n## Versionado\n\n- El mayor va en la ruta (`/v1`) y cambia sólo ante un rediseño total.\n- La versión por fecha va en `FCM-Version: AAAA-MM-DD`. Cada entidad queda fijada a la versión vigente cuando se da\n  de alta y puede probar otra mandando el header. La respuesta devuelve la versión usada.\n- Sin versión nueva entran los cambios aditivos: endpoints nuevos, campos opcionales nuevos en pedidos, campos nuevos\n  en respuestas, valores nuevos en enums de respuesta y tipos de evento nuevos. **Tu integración tiene que ignorar\n  campos y tipos de evento desconocidos y tolerar valores de enum nuevos.**\n- Lo que rompe sólo sale en una versión nueva. Una versión se mantiene al menos 12 meses después de publicada la\n  siguiente y su retiro se avisa con 6 meses de anticipación (headers `Deprecation` y `Sunset`, mail al contacto\n  técnico y changelog). Como máximo hay dos versiones vivas.\n- Los webhooks y los eventos se arman en la versión fijada de la entidad (campo `api_version`).\n\n## Montos, moneda y fechas\n\n- Montos: **enteros en centavos** (`150000` = $ 1.500,00). Moneda: sólo `ARS`.\n- Fechas y horas: RFC 3339 en UTC. El día de negocio, los topes diarios y los mensuales usan el calendario de Buenos\n  Aires (`America/Argentina/Buenos_Aires`).\n\n## Paginación\n\nLas listas devuelven del más nuevo al más viejo. `limit` va de 1 a 100 (25 por defecto); para la página siguiente\nmandá `starting_after` con el `next_cursor` recibido. Los eventos son distintos: orden ascendente por `sequence`\n(ver \"Eventos y webhooks\").\n\n## Errores\n\nTodo error tiene la misma forma:\n\n```json\n{\n  \"error\": {\n    \"type\": \"transfer_declined\",\n    \"code\": \"insufficient_funds\",\n    \"message\": \"La cuenta acc_01JA2B3C4D5E6F7G8H9JKMNPQR tiene 120000 centavos disponibles y la transferencia necesita 150050.\",\n    \"display_message\": \"No hay saldo suficiente para esta transferencia.\",\n    \"param\": \"amount\",\n    \"request_id\": \"req_01JA2B3C4D5E6F7G8H9JKMNPQT\",\n    \"retryable\": false,\n    \"doc_url\": \"https://docs.fcmpayments.com/errores#insufficient_funds\",\n    \"transfer_id\": \"otr_01JA2B3C4D5E6F7G8H9JKMNPQV\"\n  }\n}\n```\n\n`message` es para quien integra; `display_message` es un texto en castellano apto para mostrar a un usuario final\n(o `null`). `retryable: true` significa: reintentá el mismo pedido con la misma `Idempotency-Key`.\n\n| `code` | HTTP | Reintentable | ISO 20022 (motivo) |\n|---|---|---|---|\n| `invalid_request` | 400 | no | |\n| `parameter_missing` | 400 | no | |\n| `parameter_invalid` | 400 | no | |\n| `amount_invalid` | 400 | no | AM12 |\n| `currency_not_supported` | 400 | no | AM03 |\n| `concept_not_supported` | 400 | no | |\n| `destination_invalid` | 400 | no | AC01 |\n| `unsupported_version` | 400 | no | |\n| `idempotency_key_missing` | 400 | no | |\n| `idempotency_key_invalid` | 400 | no | |\n| `api_key_missing` | 401 | no | |\n| `api_key_invalid` | 401 | no | |\n| `signature_missing` | 401 | no | |\n| `signature_invalid` | 401 | no | |\n| `signature_expired` | 401 | sí, con firma nueva | |\n| `signature_replayed` | 401 | no | |\n| `signature_key_unknown` | 401 | no | |\n| `content_digest_mismatch` | 401 | no | |\n| `ip_not_allowed` | 403 | no | |\n| `environment_mismatch` | 403 | no | |\n| `entity_suspended` | 403 | no | |\n| `not_found` | 404 | no | |\n| `idempotency_key_reused` | 409 | no | |\n| `idempotency_request_in_progress` | 409 | sí | |\n| `insufficient_funds` | 422 | no | AM04 |\n| `account_frozen` | 422 | no | AC06 |\n| `account_closed` | 422 | no | AC04 |\n| `limit_per_transfer_exceeded` | 422 | no | AM02 |\n| `limit_daily_exceeded` | 422 | no | AM14 |\n| `limit_monthly_exceeded` | 422 | no | AM14 |\n| `destination_not_found` | 422 | no | AC03 |\n| `destination_inactive` | 422 | no | AC04 |\n| `destination_is_source` | 422 | no | AG01 |\n| `destination_holder_mismatch` | 422 | no | BE01 |\n| `compliance_rejected` | 422 | no | RR04 |\n| `risk_rejected` | 422 | no | AG01 |\n| `rate_limited` | 429 | sí | |\n| `internal_error` | 500 | sí | |\n| `rail_unavailable` | 503 | sí | |\n| `ledger_unavailable` | 503 | sí | |\n| `transfers_paused` | 503 | sí | |\n| `service_unavailable` | 503 | sí | |\n\n`compliance_rejected` y `risk_rejected` son deliberadamente genéricos: FCM no informa el detalle de un control de\nprevención de lavado (Ley 25.246, deber de no revelar). FCM sí guarda el motivo completo.\n\n## Transferencias salientes: autorizar antes de transferir\n\nVer `POST /v1/outgoing_transfers`. Estados y su equivalente ISO 20022 (pacs.002, `TransactionStatus`):\n\n| `status` | Qué significa | Reserva en el libro | ISO 20022 |\n|---|---|---|---|\n| `pending` | FCM recibió la orden pero todavía no puede confirmar la autorización. Puede haber plata reservada. No reintentes con otra Idempotency-Key. | Puede haber una pendiente | `PDNG` |\n| `rejected` | La autorización la rechazó. No salió plata. | No hay, o se liberó | `RJCT` |\n| `reserved` | Autorizada; importe más cargos reservados; todavía no se envió a COELSA. | Pendiente | `ACCP` |\n| `submitted` | Enviada a COELSA; falta el resultado. Con `status_reason: late_settlement_review`, reabierta por una acreditación tardía (ver abajo). | Pendiente (reabierta: liberada, y el importe ya debitado) | `ACSP` |\n| `completed` | COELSA la acreditó en el destino. | Asentada | `ACCC` |\n| `failed` | COELSA la rechazó o venció. Sin cargo. Si COELSA la acredita después, se reabre y se debita el importe, siempre sin comisión (ver abajo). | Liberada | `RJCT` |\n\n**Acreditación tardía.** Si COELSA acredita una transferencia que ya te informamos `failed` (su aviso\nllegó tarde o se perdió), la plata salió y FCM la reabre: vuelve a `submitted` con `status_reason:\nlate_settlement_review` (ISO `ACSP`; `failure` y `failed_at` vuelven a `null`) y te avisamos con el evento\n`transfer.outgoing.reopened`. El importe se debita de tu cuenta de fondos con un asiento compensatorio (sus referencias\nvan en el evento); si los fondos no alcanzan, el faltante lo cubre tu cuenta de garantía y el resto queda como deuda con\nFCM, según contrato. FCM deshabilita tus transferencias salientes y siguen deshabilitadas, aun después de `completed`,\nhasta que FCM las vuelva a habilitar (sólo en el sandbox se rehabilitan solas después del cierre simulado: ver\nSandbox). Cuando dos personas de FCM confirman la acreditación, la transferencia pasa a\n`completed` (evento `transfer.outgoing.completed`) **sin cargo**: FCM no cobra comisión por una transferencia\nreabierta, porque la reapertura no es culpa tuya (FCM sólo libera una reserva con evidencia). `charges` lo dice con un\ncargo `fcm_fee` de `0` y su motivo, y `total_debit_amount` es el importe. Es la única forma de salir de `failed`; no\nla repitas con otra Idempotency-Key.\n\nLos créditos entrantes tienen un solo estado en fase 1, `posted`, equivalente a `BOOK` (camt.054).\n\n## Eventos y webhooks\n\n- **Webhooks delgados:** el cuerpo trae el tipo y el id del objeto, no el objeto. Para el estado vigente, pedí el\n  objeto con su `GET`.\n- **Conciliación por cursor:** `GET /v1/events?after_sequence=N`. `sequence` es contiguo por entidad (1, 2, 3…):\n  si recibiste el 41 y después el 43, te falta el 42. Cada evento de plata trae `ledger_references`, la referencia\n  estable a los asientos del libro que lo produjeron.\n- **Entrega al menos una vez.** Un webhook puede llegar repetido o fuera de orden: deduplicá por `id` del evento y\n  ordená por `sequence`.\n- **Reintentos:** si tu endpoint no responde `2xx` en 10 s, reintentamos 24 veces más (25 intentos) durante unos 4,7\n  días: 30 s, 1 min, 2 min, 5 min, 10 min, 15 min, 30 min, 1 h, 2 h, 3 h, 4 h, 5 h y después cada 8 h, con ±20 %\n  de variación. Los eventos quedan en `/v1/events` durante 90 días.\n- **Firma asimétrica:** el header `FCM-Signature` es un JWS compacto (JWT) firmado por FCM con una clave\n  asimétrica guardada en KMS (`EdDSA` sobre Ed25519 o `ES256` sobre P-256; el JWKS dice cuál). Claims: `iss`\n  (`https://api.fcmpayments.com`), `aud` (tu `entity_id`), `iat`, `exp` (`iat` + 300), `jti` (id de entrega,\n  único), `evt` (id del evento) y `body_sha256` (SHA-256 de los bytes crudos del cuerpo, en base64url sin relleno).\n- **Cómo verificar:** (1) leé `kid` y `alg` del encabezado del JWS y buscá esa clave en el JWKS (cacheado; si el\n  `kid` no está, refrescá como máximo una vez por minuto); (2) verificá la firma con el `alg` que publica el JWKS para\n  ese `kid`, nunca con el que dice el pedido si no coincide; (3) exigí `iat` dentro de los últimos 5 minutos y `exp`\n  futuro; (4) recalculá `body_sha256` sobre el cuerpo crudo; (5) rechazá un `jti` ya visto (guardalo 10 minutos);\n  (6) exigí `aud` igual a tu `entity_id`.\n- **JWKS:** `GET /.well-known/jwks.json`, sin autenticación y cacheable. Una clave nueva se publica 7 días antes de\n  empezar a usarse y la vieja sigue publicada 7 días después de dejar de usarse.\n- **Tu endpoint:** HTTPS público con TLS 1.2 o superior, sin redirecciones (no las seguimos), respuesta en 10 s como\n  máximo. Procesá en segundo plano. La URL la registra FCM en el alta y se cambia por pedido verificado.\n\n## Sandbox\n\n- Las transferencias salientes se completan solas a los ~2 s, salvo por los centavos del importe: `…13` termina\n  `failed` con `destination_closed` (COELSA 7502), `…70` termina `failed` con `rail_expired` (COELSA 7570) y `…99`\n  queda `submitted` hasta que lo resuelvas con `POST /v1/simulations/outgoing_transfers/{id}/rail_result`.\n- Alias de prueba para validar contrapartes: `sbx.valida` (válida), `sbx.inactiva`, `sbx.inexistente`,\n  `sbx.bloqueada` (control de cumplimiento) y `sbx.otro.titular` (un CUIT distinto del esperado si mandás\n  `expected_cuit`). Cualquier CBU o CVU con dígitos verificadores correctos valida con un titular sintético.\n- `POST /v1/simulations/incoming_transfers` simula un crédito entrante: recorre el mismo camino que un aviso real de\n  COELSA (asiento, comisión, evento y webhook).\n- Reloj de prueba por entidad: `GET /v1/simulations/clock` y `POST /v1/simulations/clock/advance` mueven la hora\n  de la entidad hacia adelante (topes diarios y mensuales, reintentos de webhooks, vencimientos).\n- Acreditación tardía, en dos pasos: sobre una transferencia `failed` que salió por COELSA (por\n  ejemplo, una `…13`), `POST /v1/simulations/outgoing_transfers/{id}/rail_result` con `{\"outcome\":\"completed\"}`\n  simula que COELSA la acreditó después, por el mismo camino que en producción (débito compensatorio del importe,\n  salidas deshabilitadas, `submitted` con `late_settlement_review` y el evento `transfer.outgoing.reopened`). Después,\n  `POST /v1/simulations/outgoing_transfers/{id}/late_settlement_review` con `{\"outcome\":\"completed\"}` simula que dos\n  personas de FCM confirman la acreditación: unos segundos después FCM la cierra en `completed`, sin cargo, con el\n  evento `transfer.outgoing.completed`. Como en producción, desde el primer paso tus transferencias salientes quedan\n  deshabilitadas (`403 entity_suspended`). **Sólo en el sandbox**, unos segundos después de ese\n  `transfer.outgoing.completed` FCM las vuelve a habilitar sola (`GET /v1/entity` vuelve a `active`; no si FCM bloqueó\n  tu entidad en el medio) y podés seguir probando; en producción siguen deshabilitadas hasta que FCM las rehabilite.\n\n## Límites de uso\n\nPor entidad: 5 escrituras y 25 lecturas por segundo (ampliables por contrato). Al pasarte: `429 rate_limited` con\n`Retry-After`.\n",
    "license": {
      "name": "La tecnología de Grip Rails es de Peppe IO, LLC (Grip). En la Argentina la opera FCM Payment Solutions S.A.S. El uso de la API se rige por el contrato entre FCM Payment Solutions S.A.S. y cada cliente."
    },
    "contact": {
      "name": "FCM Payment Solutions S.A.S.",
      "url": "https://fcmpayments.com"
    }
  },
  "servers": [
    {
      "url": "https://api.fcmpayments.com",
      "description": "Producción. Dinero real; las transferencias por COELSA son irreversibles."
    },
    {
      "url": "https://empresas-sandbox.fcmpayments.com",
      "description": "Sandbox. Libro y riel simulados; nunca mueve dinero real."
    }
  ],
  "security": [
    {
      "apiKey": [],
      "requestSignature": []
    }
  ],
  "tags": [
    {
      "name": "Entidad",
      "description": "La empresa cliente autenticada, sus topes, su uso y sus comisiones."
    },
    {
      "name": "Cuentas",
      "description": "Cuentas de pago en pesos de la entidad (fondos y garantía) con su saldo en el libro."
    },
    {
      "name": "Números de cuenta",
      "description": "CVU de cada cuenta (N por cuenta). Todos tienen como titular a la entidad."
    },
    {
      "name": "Contrapartes",
      "description": "Validación del titular de un destino contra COELSA antes de pagar."
    },
    {
      "name": "Transferencias salientes",
      "description": "Pagos en pesos a CBU, CVU o alias, con autorización previa y reserva en el libro."
    },
    {
      "name": "Transferencias entrantes",
      "description": "Créditos recibidos en los CVU de la entidad, asentados con liquidación real de COELSA."
    },
    {
      "name": "Eventos",
      "description": "Registro ordenado de lo que pasó, para conciliar y para los webhooks."
    },
    {
      "name": "Idempotencia",
      "description": "Consulta de una Idempotency-Key usada."
    },
    {
      "name": "Claves de FCM",
      "description": "Claves públicas con las que FCM firma los webhooks."
    },
    {
      "name": "Sandbox",
      "description": "Simuladores. Sólo existen en el sandbox."
    }
  ],
  "paths": {
    "/v1/entity": {
      "get": {
        "operationId": "getEntity",
        "tags": [
          "Entidad"
        ],
        "summary": "Ver la entidad autenticada",
        "description": "Devuelve la entidad dueña de la API key, con sus topes, el uso del día y del mes, y sus comisiones.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "La entidad.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/accounts": {
      "get": {
        "operationId": "listAccounts",
        "tags": [
          "Cuentas"
        ],
        "summary": "Listar cuentas",
        "description": "Lista las cuentas de la entidad con su saldo y su estado.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de cuentas.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/accounts/{account_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/AccountIdPath"
        }
      ],
      "get": {
        "operationId": "getAccount",
        "tags": [
          "Cuentas"
        ],
        "summary": "Ver una cuenta (saldo y estado)",
        "description": "Saldo y estado de una cuenta. El saldo sale del libro en el momento del pedido:\n`posted` es lo asentado, `held` lo reservado por transferencias salientes en curso y `available` = `posted` − `held`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "La cuenta.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                },
                "examples": {
                  "fondos": {
                    "summary": "Cuenta de fondos con una salida en curso",
                    "value": {
                      "id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "object": "account",
                      "entity_id": "ent_01JA2B3C4D5E6F7G8H9JKMNPQA",
                      "type": "funds",
                      "name": "Fondos operativos",
                      "currency": "ARS",
                      "status": "active",
                      "balances": {
                        "posted": 2500000,
                        "held": 150050,
                        "available": 2349950
                      },
                      "primary_account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQB",
                      "created_at": "2026-10-15T13:00:00Z",
                      "updated_at": "2026-10-16T18:22:41Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/account_numbers": {
      "get": {
        "operationId": "listAccountNumbers",
        "tags": [
          "Números de cuenta"
        ],
        "summary": "Listar números de cuenta (CVU)",
        "description": "Lista los CVU de la entidad. Una cuenta puede tener N CVU (por ejemplo, uno por cada usuario o comercio del\ncliente, para atribuir cobros); todos tienen como titular a la entidad y lo que entra por cualquiera de ellos se\nasienta en la misma cuenta. En fase 1 los da de alta FCM.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/AccountIdQuery"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filtra por estado.",
            "schema": {
              "$ref": "#/components/schemas/AccountNumberStatus"
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de números de cuenta.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountNumberList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/account_numbers/{account_number_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/AccountNumberIdPath"
        }
      ],
      "get": {
        "operationId": "getAccountNumber",
        "tags": [
          "Números de cuenta"
        ],
        "summary": "Ver un número de cuenta",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "El número de cuenta.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountNumber"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/counterparty_validations": {
      "post": {
        "operationId": "createCounterpartyValidation",
        "tags": [
          "Contrapartes"
        ],
        "summary": "Validar una contraparte",
        "description": "Consulta en COELSA quién es el titular de un CBU, CVU o alias, si la cuenta está activa y si pasa los controles\nde cumplimiento de FCM. No mueve plata.\n\nUna validación `valid` dura 15 minutos (`expires_at`) y se puede pasar en `counterparty_validation_id` al crear la\ntransferencia para no consultar de nuevo. Un resultado negativo no es un error HTTP: responde `201` con el\n`result` correspondiente. Si COELSA no contesta: `503 rail_unavailable`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CounterpartyValidationRequest"
              },
              "examples": {
                "alias": {
                  "summary": "Validar un alias esperando un CUIT",
                  "value": {
                    "destination": {
                      "type": "alias",
                      "value": "proveedor.ejemplo"
                    },
                    "expected_cuit": "27000000006"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Validación hecha (el resultado puede ser negativo).",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CounterpartyValidation"
                },
                "examples": {
                  "valida": {
                    "summary": "Titular encontrado y activo",
                    "value": {
                      "id": "cval_01JA2B3C4D5E6F7G8H9JKMNPQC",
                      "object": "counterparty_validation",
                      "destination": {
                        "type": "alias",
                        "value": "proveedor.ejemplo"
                      },
                      "expected_cuit": "27000000006",
                      "result": "valid",
                      "display_message": null,
                      "counterparty": {
                        "name": "PROVEEDOR EJEMPLO",
                        "cuit": "27000000006",
                        "account": "0110599520000001234569",
                        "account_type": "cbu",
                        "bank_code": "011",
                        "alias": "proveedor.ejemplo",
                        "is_fcm_account": false
                      },
                      "validated_at": "2026-10-16T18:20:03Z",
                      "expires_at": "2026-10-16T18:35:03Z"
                    }
                  }
                }
              }
            }
          },
          "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"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/outgoing_transfers": {
      "post": {
        "operationId": "createOutgoingTransfer",
        "tags": [
          "Transferencias salientes"
        ],
        "summary": "Crear una transferencia saliente",
        "description": "Ordena una transferencia en pesos desde una cuenta de la entidad hacia un CBU, CVU o alias.\n\n**Antes de mover un peso, FCM autoriza**, en este orden:\n\n1. Cuenta y entidad activas, cuenta no congelada y transferencias habilitadas.\n2. Tope por operación.\n3. **Reserva** en el libro (transferencia pendiente) por el importe más los cargos. Sin saldo\n   disponible: `insufficient_funds`.\n4. Titular del destino según COELSA (o una validación vigente pasada en `counterparty_validation_id`): existe,\n   está activo, no es la misma cuenta y, si mandaste `expected_counterparty_cuit`, coincide.\n5. Listas sancionatorias (RePET, ONU, OFAC) sobre el titular del destino.\n6. Topes diario y mensual de la entidad (cuentan las transferencias `reserved`, `submitted` y `completed`).\n7. Reglas antifraude.\n\n**Si todo pasa:** `201` con la transferencia en `reserved` y el evento `transfer.outgoing.reserved`. FCM la envía\na COELSA enseguida (`submitted`) y la cierra con el aviso de COELSA: `completed` (la plata llegó y la reserva se\nasienta, con el evento `transfer.outgoing.completed`) o `failed` (la reserva se libera, no hay cargo, evento\n`transfer.outgoing.failed`). Si COELSA la acredita después de informarla `failed`, FCM la reabre (`submitted` con\n`status_reason: late_settlement_review`, evento `transfer.outgoing.reopened`) y la cierra en `completed`: ver\n\"Acreditación tardía\" en la descripción general.\n\n**Si FCM no puede confirmar el resultado en el momento:** `202` con la transferencia en `pending`, o en `submitted`\ncon `status_reason: rail_outcome_unknown` si un reintento la encuentra ya enviada y sin resultado. La orden existe y\nestá atada a tu Idempotency-Key: no la repitas con otra clave. Una `pending` termina en `reserved` (evento\n`transfer.outgoing.reserved`) o en `failed` con `failure.code: canceled_by_fcm` (evento `transfer.outgoing.failed`).\n\n**Si algo falla:** `422` con el motivo en `error.code`. La transferencia queda guardada en `rejected` (su id va en\n`error.transfer_id`) y la reserva, si llegó a tomarse, se libera. Los pedidos mal formados (`400`) no crean nada.\n\n**COELSA es irreversible:** FCM no libera una reserva ya enviada sin evidencia de rechazo. Si el resultado no\nllega, la transferencia sigue `submitted` con `status_reason: rail_outcome_unknown` y la plata sigue reservada\nhasta resolverlo. Nunca se reenvía con otro identificador.\n\nSi el destino es una cuenta de FCM, la transferencia es interna (`rail.name: fcm_book`) y se completa en el acto.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutgoingTransferCreateRequest"
              },
              "examples": {
                "cbu": {
                  "summary": "Pago a un CBU con control de titular",
                  "value": {
                    "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                    "amount": 150000,
                    "currency": "ARS",
                    "destination": {
                      "type": "cbu",
                      "value": "0110599520000001234569"
                    },
                    "expected_counterparty_cuit": "27000000006",
                    "concept": "FAC",
                    "description": "Factura 0003-00001234",
                    "external_reference": "pedido-7781",
                    "metadata": {
                      "agent_id": "agt_42"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Autorizada y reservada.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransfer"
                },
                "examples": {
                  "reservada": {
                    "summary": "Recién autorizada",
                    "value": {
                      "id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV",
                      "object": "outgoing_transfer",
                      "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQB",
                      "amount": 150000,
                      "currency": "ARS",
                      "charges": [
                        {
                          "type": "fee",
                          "code": "fcm_fee",
                          "amount": 50,
                          "description": "Comisión por transferencia saliente"
                        }
                      ],
                      "total_debit_amount": 150050,
                      "destination": {
                        "type": "cbu",
                        "value": "0110599520000001234569"
                      },
                      "counterparty": {
                        "name": "PROVEEDOR EJEMPLO",
                        "cuit": "27000000006",
                        "account": "0110599520000001234569",
                        "account_type": "cbu",
                        "bank_code": "011",
                        "alias": null,
                        "is_fcm_account": false
                      },
                      "concept": "FAC",
                      "description": "Factura 0003-00001234",
                      "external_reference": "pedido-7781",
                      "metadata": {
                        "agent_id": "agt_42"
                      },
                      "status": "reserved",
                      "status_reason": null,
                      "iso20022": {
                        "status": "ACCP",
                        "reason": null
                      },
                      "authorization": {
                        "decision": "approved",
                        "decided_at": "2026-10-16T18:22:41Z",
                        "rationale": {
                          "code": "approved",
                          "message": "Pasó todos los controles."
                        },
                        "checks": [
                          {
                            "name": "account",
                            "result": "passed"
                          },
                          {
                            "name": "limits",
                            "result": "passed"
                          },
                          {
                            "name": "funds",
                            "result": "passed"
                          },
                          {
                            "name": "counterparty",
                            "result": "passed"
                          },
                          {
                            "name": "compliance",
                            "result": "passed"
                          }
                        ]
                      },
                      "reservation": {
                        "amount": 150050,
                        "state": "held",
                        "placed_at": "2026-10-16T18:22:41Z",
                        "resolved_at": null,
                        "ledger_references": [
                          "7f3a9c2e4b1d8f6a0c5e3b9d7a1f4c2e",
                          "1b8e4d2c9a7f3e5d0b6c8a2f4e1d9c7b"
                        ]
                      },
                      "rail": null,
                      "failure": null,
                      "idempotency_key": "01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "created_at": "2026-10-16T18:22:40Z",
                      "updated_at": "2026-10-16T18:22:41Z",
                      "completed_at": null,
                      "failed_at": null
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Recibida; el resultado todavía no se puede confirmar. No reintentes con otra Idempotency-Key.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransfer"
                }
              }
            }
          },
          "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"
          },
          "422": {
            "$ref": "#/components/responses/TransferDeclined"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      },
      "get": {
        "operationId": "listOutgoingTransfers",
        "tags": [
          "Transferencias salientes"
        ],
        "summary": "Listar transferencias salientes",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/AccountIdQuery"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filtra por estado.",
            "schema": {
              "$ref": "#/components/schemas/OutgoingTransferStatus"
            }
          },
          {
            "name": "idempotency_key",
            "in": "query",
            "required": false,
            "description": "Busca la transferencia creada con esta Idempotency-Key (sirve también pasados los 35 días).",
            "schema": {
              "$ref": "#/components/schemas/IdempotencyKeyValue"
            }
          },
          {
            "name": "external_reference",
            "in": "query",
            "required": false,
            "description": "Filtra por tu referencia.",
            "schema": {
              "$ref": "#/components/schemas/ExternalReference"
            }
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de transferencias salientes.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransferList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/outgoing_transfers/{outgoing_transfer_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/OutgoingTransferIdPath"
        }
      ],
      "get": {
        "operationId": "getOutgoingTransfer",
        "tags": [
          "Transferencias salientes"
        ],
        "summary": "Ver una transferencia saliente",
        "description": "Estado vigente de la transferencia. Es lo que hay que consultar al recibir un webhook.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "La transferencia.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransfer"
                },
                "examples": {
                  "completada": {
                    "summary": "Acreditada por COELSA",
                    "value": {
                      "id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV",
                      "object": "outgoing_transfer",
                      "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQB",
                      "amount": 150000,
                      "currency": "ARS",
                      "charges": [
                        {
                          "type": "fee",
                          "code": "fcm_fee",
                          "amount": 50,
                          "description": "Comisión por transferencia saliente"
                        }
                      ],
                      "total_debit_amount": 150050,
                      "destination": {
                        "type": "cbu",
                        "value": "0110599520000001234569"
                      },
                      "counterparty": {
                        "name": "PROVEEDOR EJEMPLO",
                        "cuit": "27000000006",
                        "account": "0110599520000001234569",
                        "account_type": "cbu",
                        "bank_code": "011",
                        "alias": null,
                        "is_fcm_account": false
                      },
                      "concept": "FAC",
                      "description": "Factura 0003-00001234",
                      "external_reference": "pedido-7781",
                      "metadata": {
                        "agent_id": "agt_42"
                      },
                      "status": "completed",
                      "status_reason": null,
                      "iso20022": {
                        "status": "ACCC",
                        "reason": null
                      },
                      "authorization": {
                        "decision": "approved",
                        "decided_at": "2026-10-16T18:22:41Z",
                        "rationale": {
                          "code": "approved",
                          "message": "Pasó todos los controles."
                        },
                        "checks": [
                          {
                            "name": "account",
                            "result": "passed"
                          },
                          {
                            "name": "limits",
                            "result": "passed"
                          },
                          {
                            "name": "funds",
                            "result": "passed"
                          },
                          {
                            "name": "counterparty",
                            "result": "passed"
                          },
                          {
                            "name": "compliance",
                            "result": "passed"
                          }
                        ]
                      },
                      "reservation": {
                        "amount": 150050,
                        "state": "posted",
                        "placed_at": "2026-10-16T18:22:41Z",
                        "resolved_at": "2026-10-16T18:22:44Z",
                        "ledger_references": [
                          "7f3a9c2e4b1d8f6a0c5e3b9d7a1f4c2e",
                          "1b8e4d2c9a7f3e5d0b6c8a2f4e1d9c7b"
                        ]
                      },
                      "rail": {
                        "name": "coelsa",
                        "operation_id": "86VRPQ2GX0O4XQ4Y9GLY0X",
                        "origin_reference": "9000000000017",
                        "status_code": "7500",
                        "submitted_at": "2026-10-16T18:22:42Z",
                        "finalized_at": "2026-10-16T18:22:44Z"
                      },
                      "failure": null,
                      "idempotency_key": "01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "created_at": "2026-10-16T18:22:40Z",
                      "updated_at": "2026-10-16T18:22:44Z",
                      "completed_at": "2026-10-16T18:22:44Z",
                      "failed_at": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/incoming_transfers": {
      "get": {
        "operationId": "listIncomingTransfers",
        "tags": [
          "Transferencias entrantes"
        ],
        "summary": "Listar créditos entrantes",
        "description": "Créditos recibidos en los CVU de la entidad. Cada uno nace de un aviso de COELSA verificado (crédito ya\nliquidado en la cuenta recaudadora de FCM) y se asienta en el libro con su comisión como asiento aparte.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/AccountIdQuery"
          },
          {
            "name": "account_number_id",
            "in": "query",
            "required": false,
            "description": "Filtra por el CVU por el que entró.",
            "schema": {
              "$ref": "#/components/schemas/AccountNumberId"
            }
          },
          {
            "$ref": "#/components/parameters/CreatedAfter"
          },
          {
            "$ref": "#/components/parameters/CreatedBefore"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de créditos entrantes.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IncomingTransferList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/incoming_transfers/{incoming_transfer_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/IncomingTransferIdPath"
        }
      ],
      "get": {
        "operationId": "getIncomingTransfer",
        "tags": [
          "Transferencias entrantes"
        ],
        "summary": "Ver un crédito entrante",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "El crédito entrante.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IncomingTransfer"
                },
                "examples": {
                  "credito": {
                    "summary": "Crédito por un CVU de referencia",
                    "value": {
                      "id": "itr_01JA2B3C4D5E6F7G8H9JKMNPQW",
                      "object": "incoming_transfer",
                      "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQD",
                      "cvu": "0000214300000009999994",
                      "amount": 1500000,
                      "currency": "ARS",
                      "charges": [
                        {
                          "type": "fee",
                          "code": "fcm_fee",
                          "amount": 50,
                          "description": "Comisión por crédito entrante"
                        }
                      ],
                      "net_amount": 1499950,
                      "payer": {
                        "name": "PAGADOR EJEMPLO",
                        "cuit": "20000000001",
                        "account": "0000999100000000000420",
                        "account_type": "cvu",
                        "bank_code": null
                      },
                      "concept": "VAR",
                      "status": "posted",
                      "iso20022": {
                        "entry_status": "BOOK"
                      },
                      "rail": {
                        "name": "coelsa",
                        "operation_id": "WY7ZEPN6YGGPE6LV2Q0M5X",
                        "business_date": "2026-10-16"
                      },
                      "ledger_references": [
                        "3c9e1a7b5d2f8e4c6a0b9d3f7e1c5a2b",
                        "9d4b2f8a6c1e7d3b5f0a8c2e6d4b1f9a",
                        "5e2c8a4f1b7d9e3c6a0f2b8d4e6c1a7f"
                      ],
                      "posted_at": "2026-10-16T21:20:15Z",
                      "created_at": "2026-10-16T21:20:15Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "tags": [
          "Eventos"
        ],
        "summary": "Listar eventos por cursor",
        "description": "Eventos de la entidad en orden ascendente de `sequence`, desde el siguiente a `after_sequence`. Sin filtro de\ntipo, `sequence` es contiguo: guardá el último que procesaste y pedí desde ahí. Con el filtro `type` la secuencia\ntiene saltos por diseño (es sólo para consultar). Es la fuente para conciliar; los webhooks son un aviso.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "name": "after_sequence",
            "in": "query",
            "required": false,
            "description": "Devuelve los eventos con `sequence` mayor a este valor. Por defecto 0 (desde el primero disponible).",
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filtra por tipo de evento.",
            "schema": {
              "$ref": "#/components/schemas/EventType"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Cantidad máxima de eventos (1 a 100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de eventos.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventList"
                },
                "examples": {
                  "pagina": {
                    "summary": "Dos eventos",
                    "value": {
                      "object": "list",
                      "data": [
                        {
                          "id": "evt_01JA2B3C4D5E6F7G8H9JKMNPQX",
                          "object": "event",
                          "type": "transfer.outgoing.reserved",
                          "sequence": 41,
                          "entity_id": "ent_01JA2B3C4D5E6F7G8H9JKMNPQA",
                          "api_version": "2026-10-15",
                          "created_at": "2026-10-16T18:22:41Z",
                          "data": {
                            "object": "outgoing_transfer",
                            "id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV",
                            "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                            "ledger_references": [
                              "7f3a9c2e4b1d8f6a0c5e3b9d7a1f4c2e",
                              "1b8e4d2c9a7f3e5d0b6c8a2f4e1d9c7b"
                            ]
                          }
                        },
                        {
                          "id": "evt_01JA2B3C4D5E6F7G8H9JKMNPQY",
                          "object": "event",
                          "type": "transfer.outgoing.completed",
                          "sequence": 42,
                          "entity_id": "ent_01JA2B3C4D5E6F7G8H9JKMNPQA",
                          "api_version": "2026-10-15",
                          "created_at": "2026-10-16T18:22:44Z",
                          "data": {
                            "object": "outgoing_transfer",
                            "id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV",
                            "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                            "ledger_references": [
                              "2a6d9f3c8e1b5a7d4c0e9b2f6a8d3c1e",
                              "8c3f7a1e5d9b2c6f0a4e8d1b7c5f3a9e"
                            ]
                          }
                        }
                      ],
                      "has_more": false,
                      "next_after_sequence": 42
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/events/{event_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/EventIdPath"
        }
      ],
      "get": {
        "operationId": "getEvent",
        "tags": [
          "Eventos"
        ],
        "summary": "Ver un evento",
        "description": "Sirve para confirmar por otra vía un webhook recibido.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "El evento.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Event"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/idempotency_keys/{idempotency_key}": {
      "parameters": [
        {
          "name": "idempotency_key",
          "in": "path",
          "required": true,
          "description": "La Idempotency-Key usada.",
          "schema": {
            "$ref": "#/components/schemas/IdempotencyKeyValue"
          }
        }
      ],
      "get": {
        "operationId": "getIdempotencyKey",
        "tags": [
          "Idempotencia"
        ],
        "summary": "Consultar una Idempotency-Key",
        "description": "Dice si la clave está en curso o terminada, con qué pedido se usó (huella), qué respondimos y qué objeto creó.\nDisponible 35 días desde el primer uso. Las claves de transferencias siguen ligadas a su transferencia después de\nese plazo (ver `GET /v1/outgoing_transfers?idempotency_key=`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "El registro de la clave.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "FCM-Version": {
                "$ref": "#/components/headers/FcmVersionUsed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyRecord"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/.well-known/jwks.json": {
      "get": {
        "operationId": "getJwks",
        "tags": [
          "Claves de FCM"
        ],
        "summary": "Claves públicas de FCM para verificar webhooks",
        "description": "JWKS (RFC 7517) con las claves públicas vigentes con las que FCM firma los webhooks. No requiere autenticación.\nLas claves privadas viven en KMS y no salen de ahí.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "Conjunto de claves.",
            "headers": {
              "Cache-Control": {
                "description": "Se puede cachear 5 minutos.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "public, max-age=300"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Jwks"
                },
                "examples": {
                  "p256": {
                    "summary": "Una clave P-256 vigente",
                    "value": {
                      "keys": [
                        {
                          "kty": "EC",
                          "crv": "P-256",
                          "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
                          "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
                          "kid": "fcm-whk-2026-10",
                          "alg": "ES256",
                          "use": "sig"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/simulations/incoming_transfers": {
      "post": {
        "operationId": "simulateIncomingTransfer",
        "tags": [
          "Sandbox"
        ],
        "summary": "Simular un crédito entrante",
        "description": "Arma un aviso de COELSA sintético hacia un CVU de la entidad y lo hace pasar por el mismo camino que uno real:\nasiento en el libro del sandbox, comisión, evento `transfer.incoming.posted` y webhook. Sólo sandbox.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateIncomingTransferRequest"
              },
              "examples": {
                "basico": {
                  "summary": "Crédito de $ 15.000",
                  "value": {
                    "account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQD",
                    "amount": 1500000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Crédito simulado y asentado.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IncomingTransfer"
                }
              }
            }
          },
          "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"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/simulations/outgoing_transfers/{outgoing_transfer_id}/rail_result": {
      "parameters": [
        {
          "$ref": "#/components/parameters/OutgoingTransferIdPath"
        }
      ],
      "post": {
        "operationId": "simulateOutgoingTransferRailResult",
        "tags": [
          "Sandbox"
        ],
        "summary": "Simular el resultado de COELSA para una transferencia",
        "description": "Inyecta el aviso de resultado de COELSA (equivalente a `AvisoOperacionFinalizada`) para una transferencia en\n`submitted`: `completed` asienta la reserva y `failed` la libera. Sobre una transferencia `failed` que salió por\nCOELSA, `completed` simula una acreditación tardía: el aviso llega después de liberada la reserva y\nFCM la reabre por el mismo camino que en producción (débito compensatorio del importe, salidas deshabilitadas,\n`submitted` con `status_reason: late_settlement_review` y el evento `transfer.outgoing.reopened`). Sólo sandbox.\nCualquier otro caso responde `400 parameter_invalid`: otro estado, una `failed` con `outcome: failed`, una\n`failed` que nunca salió a COELSA o una reabierta (la cierra FCM: ver\n`POST /v1/simulations/outgoing_transfers/{id}/late_settlement_review`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateRailResultRequest"
              },
              "examples": {
                "rechazo": {
                  "summary": "COELSA rechaza por cuenta inexistente",
                  "value": {
                    "outcome": "failed",
                    "coelsa_code": "7502"
                  }
                },
                "acreditacion_tardia": {
                  "summary": "Sobre una transferencia failed, COELSA la acredita después (acreditación tardía)",
                  "value": {
                    "outcome": "completed"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado aplicado. Devuelve la transferencia actualizada.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransfer"
                }
              }
            }
          },
          "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"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/simulations/outgoing_transfers/{outgoing_transfer_id}/late_settlement_review": {
      "parameters": [
        {
          "$ref": "#/components/parameters/OutgoingTransferIdPath"
        }
      ],
      "post": {
        "operationId": "simulateOutgoingTransferLateSettlementReview",
        "tags": [
          "Sandbox"
        ],
        "summary": "Simular que dos personas de FCM confirman una acreditación tardía",
        "description": "Para una transferencia reabierta por una acreditación tardía (`submitted` con `status_reason:\nlate_settlement_review`), simula que dos personas de FCM confirman la acreditación: en el sandbox son dos\noperadores sintéticos distintos que proponen y aprueban la conciliación por el mismo camino que en producción. La\nrespuesta `202` trae la transferencia todavía reabierta; unos segundos después FCM la cierra en `completed`, sin\ncargo (`charges` con un `fcm_fee` de `0` y su motivo), con el evento `transfer.outgoing.completed`, y unos\nsegundos más tarde vuelve a habilitar tus transferencias salientes (`GET /v1/entity` vuelve a `active`; no si FCM\nbloqueó tu entidad en el medio): esa rehabilitación automática existe sólo en el sandbox; en producción siguen\ndeshabilitadas hasta que FCM las rehabilite. Sólo sandbox. Una transferencia que no está reabierta responde\n`400 parameter_invalid`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateLateSettlementReviewRequest"
              },
              "examples": {
                "confirmada": {
                  "summary": "Dos personas de FCM confirman la acreditación tardía",
                  "value": {
                    "outcome": "completed"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Confirmada por dos personas sintéticas. Devuelve la transferencia todavía reabierta; FCM la cierra en `completed` en segundos.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutgoingTransfer"
                }
              }
            }
          },
          "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"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/v1/simulations/clock": {
      "get": {
        "operationId": "getSandboxClock",
        "tags": [
          "Sandbox"
        ],
        "summary": "Ver el reloj de prueba de la entidad",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "El reloj.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxClock"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/simulations/clock/advance": {
      "post": {
        "operationId": "advanceSandboxClock",
        "tags": [
          "Sandbox"
        ],
        "summary": "Adelantar el reloj de prueba",
        "description": "Mueve hacia adelante la hora de la entidad en el sandbox (nunca hacia atrás). Afecta el día y el mes de los\ntopes, los reintentos de webhooks pendientes y los vencimientos simulados. Todas las fechas que devuelve el\nsandbox para esa entidad usan este reloj.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdvanceClockRequest"
              },
              "examples": {
                "un_dia": {
                  "summary": "Adelantar un día",
                  "value": {
                    "advance_seconds": 86400
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reloj adelantado.",
            "headers": {
              "FCM-Request-Id": {
                "$ref": "#/components/headers/FcmRequestId"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SandboxClock"
                }
              }
            }
          },
          "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"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "webhooks": {
    "transfer.incoming.posted": {
      "post": {
        "operationId": "webhookTransferIncomingPosted",
        "tags": [
          "Eventos"
        ],
        "summary": "Entró plata a una cuenta de la entidad",
        "description": "Se asentó un crédito entrante. Pedí `GET /v1/incoming_transfers/{data.id}` para el detalle.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignature"
          },
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttempt"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              },
              "examples": {
                "credito": {
                  "value": {
                    "id": "evt_01JA2B3C4D5E6F7G8H9JKMNPQZ",
                    "object": "event",
                    "type": "transfer.incoming.posted",
                    "sequence": 43,
                    "entity_id": "ent_01JA2B3C4D5E6F7G8H9JKMNPQA",
                    "api_version": "2026-10-15",
                    "created_at": "2026-10-16T21:20:15Z",
                    "data": {
                      "object": "incoming_transfer",
                      "id": "itr_01JA2B3C4D5E6F7G8H9JKMNPQW",
                      "account_id": "acc_01JA2B3C4D5E6F7G8H9JKMNPQR",
                      "ledger_references": [
                        "3c9e1a7b5d2f8e4c6a0b9d3f7e1c5a2b",
                        "9d4b2f8a6c1e7d3b5f0a8c2e6d4b1f9a",
                        "5e2c8a4f1b7d9e3c6a0f2b8d4e6c1a7f"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recibido. Respondé en 10 s como máximo y procesá en segundo plano."
          },
          "default": {
            "description": "Cualquier otra respuesta, o ninguna en 10 s, dispara un reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.reserved": {
      "post": {
        "operationId": "webhookTransferOutgoingReserved",
        "tags": [
          "Eventos"
        ],
        "summary": "Una transferencia saliente quedó autorizada y reservada",
        "description": "La autorización aprobó la transferencia y el importe más los cargos quedaron reservados en el libro.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignature"
          },
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttempt"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recibido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.completed": {
      "post": {
        "operationId": "webhookTransferOutgoingCompleted",
        "tags": [
          "Eventos"
        ],
        "summary": "Una transferencia saliente se acreditó",
        "description": "COELSA confirmó la acreditación en el destino y la reserva se asentó. Es irreversible. Una transferencia reabierta\npor una acreditación tardía llega acá cuando FCM la cierra, sin cargo: su único débito es el asiento\ncompensatorio (sus referencias van en `data.ledger_references`).\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignature"
          },
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttempt"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recibido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.failed": {
      "post": {
        "operationId": "webhookTransferOutgoingFailed",
        "tags": [
          "Eventos"
        ],
        "summary": "Una transferencia saliente falló",
        "description": "COELSA la rechazó o venció, o FCM la canceló antes de enviarla. La reserva se liberó y no hubo cargo. El motivo está en `failure` del objeto. Si COELSA la acredita después, llega `transfer.outgoing.reopened`.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignature"
          },
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttempt"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recibido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.reopened": {
      "post": {
        "operationId": "webhookTransferOutgoingReopened",
        "tags": [
          "Eventos"
        ],
        "summary": "Una transferencia saliente fallida se reabrió",
        "description": "COELSA acreditó una transferencia que ya te habíamos informado `failed` (acreditación tardía): la\nplata salió. La transferencia vuelve a `submitted` con `status_reason: late_settlement_review`, el importe se debitó\ncon un asiento compensatorio (sus referencias van en `data.ledger_references`) y FCM la cierra en `completed`\n(evento `transfer.outgoing.completed`) cuando dos personas confirman la acreditación. Pedí\n`GET /v1/outgoing_transfers/{data.id}` para el estado vigente.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookSignature"
          },
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryAttempt"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recibido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "fcm_live_… o fcm_test_…",
        "description": "API key de la entidad en `Authorization: Bearer`. Identifica a la entidad y al entorno. FCM la guarda hasheada y\nse rota sin corte (hasta dos activas). Sola no alcanza: todo pedido va además firmado (`requestSignature`).\n"
      },
      "requestSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "Signature",
        "description": "Firma del pedido según RFC 9421 (HTTP Message Signatures) con la clave privada del cliente (`ed25519` o\n`ecdsa-p256-sha256`). Va con `Signature-Input` y, si hay cuerpo, con `Content-Digest`. Componentes y parámetros\nobligatorios en la descripción general (\"Autenticación\"). FCM sólo conoce la clave pública: una base de datos de\nFCM filtrada no permite falsificar instrucciones del cliente.\n"
      }
    },
    "parameters": {
      "FcmVersion": {
        "name": "FCM-Version",
        "in": "header",
        "required": false,
        "description": "Versión por fecha del contrato. Si falta, se usa la versión fijada de la entidad.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "examples": [
            "2026-10-15"
          ]
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Clave única por intención del cliente. Obligatoria en todo POST. Ver \"Idempotencia\".",
        "schema": {
          "$ref": "#/components/schemas/IdempotencyKeyValue"
        }
      },
      "SignatureInput": {
        "name": "Signature-Input",
        "in": "header",
        "required": true,
        "description": "Parámetros de la firma RFC 9421 (componentes cubiertos, `created`, `nonce`, `keyid`, `alg`).",
        "schema": {
          "type": "string",
          "maxLength": 2048,
          "examples": [
            "sig1=(\"@method\" \"@target-uri\");created=1760112000;nonce=\"Vq3n8sZx0bR1yTqLkM2pWg\";keyid=\"ck_01JA2B3C4D5E6F7G8H9JKMNPQS\";alg=\"ed25519\""
          ]
        }
      },
      "ContentDigest": {
        "name": "Content-Digest",
        "in": "header",
        "required": true,
        "description": "SHA-256 de los bytes exactos del cuerpo, según RFC 9530.",
        "schema": {
          "type": "string",
          "pattern": "^sha-256=:[A-Za-z0-9+/]{43}=:$",
          "examples": [
            "sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:"
          ]
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Cantidad máxima de objetos por página.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "StartingAfter": {
        "name": "starting_after",
        "in": "query",
        "required": false,
        "description": "Cursor opaco (`next_cursor` de la página anterior).",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      },
      "CreatedAfter": {
        "name": "created_after",
        "in": "query",
        "required": false,
        "description": "Sólo objetos creados en este instante o después (RFC 3339).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "CreatedBefore": {
        "name": "created_before",
        "in": "query",
        "required": false,
        "description": "Sólo objetos creados antes de este instante (RFC 3339).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "AccountIdQuery": {
        "name": "account_id",
        "in": "query",
        "required": false,
        "description": "Filtra por cuenta.",
        "schema": {
          "$ref": "#/components/schemas/AccountId"
        }
      },
      "AccountIdPath": {
        "name": "account_id",
        "in": "path",
        "required": true,
        "description": "Id de la cuenta.",
        "schema": {
          "$ref": "#/components/schemas/AccountId"
        }
      },
      "AccountNumberIdPath": {
        "name": "account_number_id",
        "in": "path",
        "required": true,
        "description": "Id del número de cuenta.",
        "schema": {
          "$ref": "#/components/schemas/AccountNumberId"
        }
      },
      "OutgoingTransferIdPath": {
        "name": "outgoing_transfer_id",
        "in": "path",
        "required": true,
        "description": "Id de la transferencia saliente.",
        "schema": {
          "$ref": "#/components/schemas/OutgoingTransferId"
        }
      },
      "IncomingTransferIdPath": {
        "name": "incoming_transfer_id",
        "in": "path",
        "required": true,
        "description": "Id del crédito entrante.",
        "schema": {
          "$ref": "#/components/schemas/IncomingTransferId"
        }
      },
      "EventIdPath": {
        "name": "event_id",
        "in": "path",
        "required": true,
        "description": "Id del evento.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "WebhookSignature": {
        "name": "FCM-Signature",
        "in": "header",
        "required": true,
        "description": "JWS compacto (JWT) firmado por FCM. Ver \"Eventos y webhooks\" para los claims y los pasos de verificación.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$"
        }
      },
      "WebhookEventId": {
        "name": "FCM-Event-Id",
        "in": "header",
        "required": true,
        "description": "Id del evento (igual a `id` del cuerpo). Clave para deduplicar.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "WebhookEventType": {
        "name": "FCM-Event-Type",
        "in": "header",
        "required": true,
        "description": "Tipo del evento (igual a `type` del cuerpo).",
        "schema": {
          "$ref": "#/components/schemas/EventType"
        }
      },
      "WebhookDeliveryId": {
        "name": "FCM-Delivery-Id",
        "in": "header",
        "required": true,
        "description": "Id de este intento de entrega (igual al claim `jti`).",
        "schema": {
          "type": "string",
          "pattern": "^whd_[0-9A-HJKMNP-TV-Z]{26}$"
        }
      },
      "WebhookDeliveryAttempt": {
        "name": "FCM-Delivery-Attempt",
        "in": "header",
        "required": true,
        "description": "Número de intento (1 a 25).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 25
        }
      }
    },
    "headers": {
      "FcmRequestId": {
        "description": "Id del pedido en FCM. Citalo en cualquier consulta a soporte.",
        "schema": {
          "$ref": "#/components/schemas/RequestId"
        }
      },
      "FcmVersionUsed": {
        "description": "Versión del contrato con la que se respondió.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
        }
      },
      "IdempotentReplayed": {
        "description": "`true` si es la respuesta guardada para esa Idempotency-Key.",
        "schema": {
          "type": "boolean"
        }
      },
      "RetryAfter": {
        "description": "Segundos a esperar antes de reintentar.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Pedido mal formado o parámetro inválido. No se creó nada.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "parametro": {
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "code": "amount_invalid",
                    "message": "amount tiene que ser un entero positivo en centavos.",
                    "display_message": null,
                    "param": "amount",
                    "request_id": "req_01JA2B3C4D5E6F7G8H9JKMNPQT",
                    "retryable": false,
                    "doc_url": "https://docs.fcmpayments.com/errores#amount_invalid",
                    "transfer_id": null
                  }
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Falta la API key o la firma, o no son válidas.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "firma": {
                "value": {
                  "error": {
                    "type": "authentication_error",
                    "code": "signature_expired",
                    "message": "El parámetro created de la firma está fuera de la ventana de ±300 segundos.",
                    "display_message": null,
                    "param": null,
                    "request_id": "req_01JA2B3C4D5E6F7G8H9JKMNPQT",
                    "retryable": true,
                    "doc_url": "https://docs.fcmpayments.com/errores#signature_expired",
                    "transfer_id": null
                  }
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "La credencial es válida pero no puede hacer esto (IP, entorno o entidad suspendida).",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No existe, o es de otra entidad (FCM no distingue los dos casos).",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflicto de idempotencia.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "reusada": {
                "value": {
                  "error": {
                    "type": "idempotency_error",
                    "code": "idempotency_key_reused",
                    "message": "La Idempotency-Key 01JA2B3C4D5E6F7G8H9JKMNPQR ya se usó con otro pedido (POST /v1/outgoing_transfers, huella distinta).",
                    "display_message": null,
                    "param": "Idempotency-Key",
                    "request_id": "req_01JA2B3C4D5E6F7G8H9JKMNPQT",
                    "retryable": false,
                    "doc_url": "https://docs.fcmpayments.com/errores#idempotency_key_reused",
                    "transfer_id": null
                  }
                }
              }
            }
          }
        }
      },
      "TransferDeclined": {
        "description": "La autorización rechazó la transferencia. Quedó guardada en `rejected` y no salió plata.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          },
          "Idempotent-Replayed": {
            "$ref": "#/components/headers/IdempotentReplayed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "sin_saldo": {
                "value": {
                  "error": {
                    "type": "transfer_declined",
                    "code": "insufficient_funds",
                    "message": "La cuenta acc_01JA2B3C4D5E6F7G8H9JKMNPQR tiene 120000 centavos disponibles y la transferencia necesita 150050.",
                    "display_message": "No hay saldo suficiente para esta transferencia.",
                    "param": "amount",
                    "request_id": "req_01JA2B3C4D5E6F7G8H9JKMNPQT",
                    "retryable": false,
                    "doc_url": "https://docs.fcmpayments.com/errores#insufficient_funds",
                    "transfer_id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV"
                  }
                }
              },
              "titular": {
                "value": {
                  "error": {
                    "type": "transfer_declined",
                    "code": "destination_holder_mismatch",
                    "message": "COELSA informa otro CUIT para el titular del destino.",
                    "display_message": "La cuenta de destino no es de quien esperabas.",
                    "param": "expected_counterparty_cuit",
                    "request_id": "req_01JA2B3C4D5E6F7G8H9JKMNPQT",
                    "retryable": false,
                    "doc_url": "https://docs.fcmpayments.com/errores#destination_holder_mismatch",
                    "transfer_id": "otr_01JA2B3C4D5E6F7G8H9JKMNPQV"
                  }
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Pasaste el límite de pedidos por segundo.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Error de FCM. Reintentá con la misma Idempotency-Key.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "COELSA, el libro o las transferencias no están disponibles por ahora. Reintentá con la misma Idempotency-Key.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "EntityId": {
        "type": "string",
        "pattern": "^ent_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "ent_01JA2B3C4D5E6F7G8H9JKMNPQA"
        ]
      },
      "AccountId": {
        "type": "string",
        "pattern": "^acc_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "acc_01JA2B3C4D5E6F7G8H9JKMNPQR"
        ]
      },
      "AccountNumberId": {
        "type": "string",
        "pattern": "^acn_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "acn_01JA2B3C4D5E6F7G8H9JKMNPQB"
        ]
      },
      "OutgoingTransferId": {
        "type": "string",
        "description": "Determinístico a partir de la entidad y la Idempotency-Key, así un reintento llega al mismo objeto.",
        "pattern": "^otr_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "otr_01JA2B3C4D5E6F7G8H9JKMNPQV"
        ]
      },
      "IncomingTransferId": {
        "type": "string",
        "description": "Determinístico a partir del id de COELSA del crédito.",
        "pattern": "^itr_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "itr_01JA2B3C4D5E6F7G8H9JKMNPQW"
        ]
      },
      "CounterpartyValidationId": {
        "type": "string",
        "pattern": "^cval_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "cval_01JA2B3C4D5E6F7G8H9JKMNPQC"
        ]
      },
      "EventId": {
        "type": "string",
        "pattern": "^evt_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "evt_01JA2B3C4D5E6F7G8H9JKMNPQX"
        ]
      },
      "RequestId": {
        "type": "string",
        "pattern": "^req_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "req_01JA2B3C4D5E6F7G8H9JKMNPQT"
        ]
      },
      "IdempotencyKeyValue": {
        "type": "string",
        "pattern": "^[A-Za-z0-9._:-]{16,128}$",
        "examples": [
          "01JA2B3C4D5E6F7G8H9JKMNPQR"
        ]
      },
      "Amount": {
        "type": "integer",
        "format": "int64",
        "minimum": 1,
        "maximum": 9007199254740991,
        "description": "Importe en centavos de peso. `150000` = $ 1.500,00.",
        "examples": [
          150000
        ]
      },
      "AmountOrZero": {
        "type": "integer",
        "format": "int64",
        "minimum": 0,
        "maximum": 9007199254740991,
        "description": "Importe en centavos de peso, puede ser cero."
      },
      "Currency": {
        "type": "string",
        "enum": [
          "ARS"
        ],
        "description": "Única moneda de la API."
      },
      "Cuit": {
        "type": "string",
        "pattern": "^\\d{11}$",
        "description": "CUIT o CUIL, 11 dígitos sin guiones.",
        "examples": [
          "27000000006"
        ]
      },
      "BankKey": {
        "type": "string",
        "pattern": "^\\d{22}$",
        "description": "CBU o CVU de 22 dígitos con dígitos verificadores válidos.",
        "examples": [
          "0110599520000001234569"
        ]
      },
      "Alias": {
        "type": "string",
        "pattern": "^[A-Za-z0-9.-]{6,20}$",
        "description": "Alias del sistema de COELSA.",
        "examples": [
          "proveedor.ejemplo"
        ]
      },
      "LedgerReference": {
        "type": "string",
        "pattern": "^[0-9a-f]{32}$",
        "description": "Referencia opaca y estable a un asiento del libro (id de 128 bits, en hexadecimal). Se deriva de identificadores estables (id de COELSA, entidad e Idempotency-Key), así que no cambia\nsi el libro se reconstruye.\n",
        "examples": [
          "7f3a9c2e4b1d8f6a0c5e3b9d7a1f4c2e"
        ]
      },
      "ExternalReference": {
        "type": "string",
        "pattern": "^[A-Za-z0-9._:-]{1,64}$",
        "description": "Referencia del cliente para conciliar. No tiene que ser única y no viaja a COELSA.",
        "examples": [
          "pedido-7781"
        ]
      },
      "Metadata": {
        "type": "object",
        "description": "Hasta 20 pares clave-valor del cliente. No poner datos personales.",
        "maxProperties": 20,
        "propertyNames": {
          "pattern": "^[a-z0-9_]{1,40}$"
        },
        "additionalProperties": {
          "type": "string",
          "maxLength": 500
        }
      },
      "Concept": {
        "type": "string",
        "description": "Concepto BCRA de la transferencia, que viaja a COELSA. Lista inicial; puede crecer de forma aditiva.\nVAR varios, ALQ alquileres, CUO cuotas, EXP expensas, FAC facturas, HAB haberes, HON honorarios, PRE préstamos,\nSEG seguros.\n",
        "enum": [
          "VAR",
          "ALQ",
          "CUO",
          "EXP",
          "FAC",
          "HAB",
          "HON",
          "PRE",
          "SEG"
        ],
        "default": "VAR"
      },
      "EntityStatus": {
        "type": "string",
        "description": "`suspended`: puede leer pero no ordenar transferencias.",
        "enum": [
          "active",
          "suspended",
          "closed"
        ]
      },
      "Entity": {
        "type": "object",
        "required": [
          "id",
          "object",
          "legal_name",
          "cuit",
          "status",
          "environment",
          "api_version",
          "limits",
          "usage",
          "fees",
          "created_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EntityId"
          },
          "object": {
            "type": "string",
            "const": "entity"
          },
          "legal_name": {
            "type": "string",
            "maxLength": 200
          },
          "cuit": {
            "description": "CUIT con el que la entidad es titular de sus CVU ante COELSA.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "$ref": "#/components/schemas/EntityStatus"
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "api_version": {
            "type": "string",
            "description": "Versión del contrato fijada para la entidad.",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "limits": {
            "$ref": "#/components/schemas/Limits"
          },
          "usage": {
            "$ref": "#/components/schemas/LimitUsage"
          },
          "fees": {
            "$ref": "#/components/schemas/FeeSchedule"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Limits": {
        "type": "object",
        "description": "Topes de transferencias salientes de la entidad, fijados por contrato (los aprueba FCM, no se cambian por API).\nCuentan el importe sin cargos de las transferencias `reserved`, `submitted` y `completed`. `null` = sin tope.\n",
        "required": [
          "per_transfer_max_amount",
          "daily_max_amount",
          "monthly_max_amount"
        ],
        "properties": {
          "per_transfer_max_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 1
          },
          "daily_max_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 1
          },
          "monthly_max_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 1
          }
        }
      },
      "LimitUsage": {
        "type": "object",
        "required": [
          "business_date",
          "daily_used_amount",
          "daily_remaining_amount",
          "month",
          "monthly_used_amount",
          "monthly_remaining_amount"
        ],
        "properties": {
          "business_date": {
            "type": "string",
            "format": "date",
            "description": "Día de Buenos Aires al que corresponde el uso diario."
          },
          "daily_used_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "daily_remaining_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0,
            "description": "`null` si no hay tope diario."
          },
          "month": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}$"
          },
          "monthly_used_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "monthly_remaining_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0,
            "description": "`null` si no hay tope mensual."
          }
        }
      },
      "FeeRule": {
        "type": "object",
        "required": [
          "fixed_amount",
          "rate_bps"
        ],
        "properties": {
          "fixed_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "rate_bps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "description": "Porcentaje en puntos básicos sobre el importe (100 = 1 %). La comisión es fijo + porcentaje, redondeado hacia abajo al centavo."
          }
        }
      },
      "FeeSchedule": {
        "type": "object",
        "description": "Comisión por movimiento, según contrato. Se cobra como asiento separado en el libro: en una salida se reserva con\nla transferencia y se libera si falla; en una entrada se descuenta al asentar y nunca supera el importe recibido.\n",
        "required": [
          "outgoing",
          "incoming"
        ],
        "properties": {
          "outgoing": {
            "$ref": "#/components/schemas/FeeRule"
          },
          "incoming": {
            "$ref": "#/components/schemas/FeeRule"
          }
        }
      },
      "AccountType": {
        "type": "string",
        "description": "`funds`: cuenta de fondos, la que opera. `guarantee`: cuenta de garantía (reserva) que el cliente deposita según\ncontrato para cubrir faltantes; se ve pero no se debita por API.\n",
        "enum": [
          "funds",
          "guarantee"
        ]
      },
      "AccountStatus": {
        "type": "string",
        "description": "`frozen`: no puede ordenar salidas; las entradas se asientan.",
        "enum": [
          "active",
          "frozen",
          "closed"
        ]
      },
      "Balances": {
        "type": "object",
        "required": [
          "posted",
          "held",
          "available"
        ],
        "properties": {
          "posted": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "held": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "available": {
            "$ref": "#/components/schemas/AmountOrZero"
          }
        }
      },
      "Account": {
        "type": "object",
        "required": [
          "id",
          "object",
          "entity_id",
          "type",
          "name",
          "currency",
          "status",
          "balances",
          "primary_account_number_id",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "object": {
            "type": "string",
            "const": "account"
          },
          "entity_id": {
            "$ref": "#/components/schemas/EntityId"
          },
          "type": {
            "$ref": "#/components/schemas/AccountType"
          },
          "name": {
            "type": "string",
            "maxLength": 80
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "status": {
            "$ref": "#/components/schemas/AccountStatus"
          },
          "balances": {
            "$ref": "#/components/schemas/Balances"
          },
          "primary_account_number_id": {
            "description": "CVU que figura como origen ante COELSA si la transferencia no indica otro.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AccountNumberId"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AccountList": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Account"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AccountNumberStatus": {
        "type": "string",
        "description": "`pending`: alta en COELSA en curso. `inactive`: dado de baja o inactivo en COELSA.",
        "enum": [
          "active",
          "inactive",
          "pending"
        ]
      },
      "Holder": {
        "type": "object",
        "required": [
          "name",
          "cuit"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "cuit": {
            "$ref": "#/components/schemas/Cuit"
          }
        }
      },
      "AccountNumber": {
        "type": "object",
        "required": [
          "id",
          "object",
          "account_id",
          "cvu",
          "alias",
          "status",
          "holder",
          "is_primary",
          "external_reference",
          "created_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/AccountNumberId"
          },
          "object": {
            "type": "string",
            "const": "account_number"
          },
          "account_id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "cvu": {
            "$ref": "#/components/schemas/BankKey"
          },
          "alias": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Alias"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "$ref": "#/components/schemas/AccountNumberStatus"
          },
          "holder": {
            "description": "Titular registrado en COELSA. En fase 1 siempre es la entidad.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Holder"
              }
            ]
          },
          "is_primary": {
            "type": "boolean"
          },
          "external_reference": {
            "description": "Etiqueta que el cliente pidió para este CVU (por ejemplo, el id de su usuario o comercio). Sin datos personales.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ExternalReference"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AccountNumberList": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountNumber"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Destination": {
        "description": "Destino de una transferencia o de una validación.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/DestinationCbu"
          },
          {
            "$ref": "#/components/schemas/DestinationCvu"
          },
          {
            "$ref": "#/components/schemas/DestinationAlias"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "cbu": "#/components/schemas/DestinationCbu",
            "cvu": "#/components/schemas/DestinationCvu",
            "alias": "#/components/schemas/DestinationAlias"
          }
        }
      },
      "DestinationCbu": {
        "type": "object",
        "required": [
          "type",
          "value"
        ],
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": "string",
            "const": "cbu"
          },
          "value": {
            "$ref": "#/components/schemas/BankKey"
          }
        }
      },
      "DestinationCvu": {
        "type": "object",
        "required": [
          "type",
          "value"
        ],
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": "string",
            "const": "cvu"
          },
          "value": {
            "$ref": "#/components/schemas/BankKey"
          }
        }
      },
      "DestinationAlias": {
        "type": "object",
        "required": [
          "type",
          "value"
        ],
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": "string",
            "const": "alias"
          },
          "value": {
            "$ref": "#/components/schemas/Alias"
          }
        }
      },
      "Counterparty": {
        "type": "object",
        "description": "Titular y cuenta del destino según COELSA, tal como se verificaron al autorizar.",
        "required": [
          "name",
          "cuit",
          "account",
          "account_type",
          "bank_code",
          "alias",
          "is_fcm_account"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "cuit": {
            "$ref": "#/components/schemas/Cuit"
          },
          "account": {
            "$ref": "#/components/schemas/BankKey"
          },
          "account_type": {
            "type": "string",
            "enum": [
              "cbu",
              "cvu"
            ]
          },
          "bank_code": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{3}$",
            "description": "Código de la entidad financiera del CBU, si COELSA lo informa."
          },
          "alias": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Alias"
              },
              {
                "type": "null"
              }
            ]
          },
          "is_fcm_account": {
            "type": "boolean",
            "description": "`true` si el destino es una cuenta de FCM (la transferencia es interna)."
          }
        }
      },
      "CounterpartyValidationRequest": {
        "type": "object",
        "required": [
          "destination"
        ],
        "additionalProperties": false,
        "properties": {
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "expected_cuit": {
            "description": "Si viene, el resultado es `holder_mismatch` cuando COELSA informa otro CUIT.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              }
            ]
          }
        }
      },
      "CounterpartyValidationResult": {
        "type": "string",
        "description": "`valid`: titular encontrado, cuenta activa y controles en orden. `not_found`: COELSA no conoce la cuenta o el\nalias. `inactive`: la cuenta existe pero no está activa. `holder_mismatch`: el CUIT no es el esperado.\n`blocked`: FCM no puede operar con esa cuenta (control de cumplimiento; sin detalle).\n",
        "enum": [
          "valid",
          "not_found",
          "inactive",
          "holder_mismatch",
          "blocked"
        ]
      },
      "CounterpartyValidation": {
        "type": "object",
        "required": [
          "id",
          "object",
          "destination",
          "expected_cuit",
          "result",
          "display_message",
          "counterparty",
          "validated_at",
          "expires_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/CounterpartyValidationId"
          },
          "object": {
            "type": "string",
            "const": "counterparty_validation"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "expected_cuit": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {
            "$ref": "#/components/schemas/CounterpartyValidationResult"
          },
          "display_message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Texto en castellano para mostrar al usuario final cuando el resultado no es `valid`."
          },
          "counterparty": {
            "description": "Presente si COELSA informó un titular (`valid`, `inactive` y `holder_mismatch`).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Counterparty"
              },
              {
                "type": "null"
              }
            ]
          },
          "validated_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Hasta cuándo se puede usar en una transferencia (15 minutos)."
          }
        }
      },
      "OutgoingTransferCreateRequest": {
        "type": "object",
        "required": [
          "account_id",
          "amount",
          "currency",
          "destination"
        ],
        "additionalProperties": false,
        "properties": {
          "account_id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "account_number_id": {
            "description": "CVU de la cuenta que figura como origen ante COELSA. Por defecto, el principal de la cuenta.",
            "allOf": [
              {
                "$ref": "#/components/schemas/AccountNumberId"
              }
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "expected_counterparty_cuit": {
            "description": "Recomendado siempre. Si COELSA informa otro CUIT para el titular, se rechaza con `destination_holder_mismatch`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              }
            ]
          },
          "counterparty_validation_id": {
            "description": "Validación `valid` vigente (15 minutos) del mismo destino. Si vence o no coincide, `400 parameter_invalid`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CounterpartyValidationId"
              }
            ]
          },
          "concept": {
            "$ref": "#/components/schemas/Concept"
          },
          "description": {
            "type": "string",
            "maxLength": 140,
            "description": "Texto del cliente. Queda en FCM; en fase 1 no viaja a COELSA."
          },
          "external_reference": {
            "$ref": "#/components/schemas/ExternalReference"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        }
      },
      "OutgoingTransferStatus": {
        "type": "string",
        "description": "Ver la tabla de estados en la descripción general.",
        "enum": [
          "pending",
          "rejected",
          "reserved",
          "submitted",
          "completed",
          "failed"
        ]
      },
      "OutgoingTransferStatusReason": {
        "type": "string",
        "description": "Sólo en `submitted`. `awaiting_rail_result`: esperando el aviso de COELSA (normal, segundos).\n`rail_outcome_unknown`: el resultado no llegó en el plazo esperado; FCM lo está resolviendo con COELSA y la plata\nsigue reservada. No reintentes con otra Idempotency-Key: podrías pagar dos veces.\n`late_settlement_review`: COELSA acreditó la transferencia después de que te la informamos `failed`\n(acreditación tardía). La plata salió y el importe se debitó con un asiento compensatorio; FCM la cierra en\n`completed` cuando dos personas confirman la acreditación.\n",
        "enum": [
          "awaiting_rail_result",
          "rail_outcome_unknown",
          "late_settlement_review"
        ]
      },
      "ChargeType": {
        "type": "string",
        "enum": [
          "fee",
          "tax"
        ]
      },
      "ChargeCode": {
        "type": "string",
        "description": "`fcm_fee`: comisión de FCM. `idcb`: impuesto a los débitos y créditos retenido por FCM como agente, si corresponde.",
        "enum": [
          "fcm_fee",
          "idcb"
        ]
      },
      "Charge": {
        "type": "object",
        "required": [
          "type",
          "code",
          "amount",
          "description"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/ChargeType"
          },
          "code": {
            "$ref": "#/components/schemas/ChargeCode"
          },
          "amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "description": {
            "type": "string",
            "maxLength": 140
          }
        }
      },
      "Iso20022OutgoingStatus": {
        "type": "object",
        "required": [
          "status",
          "reason"
        ],
        "properties": {
          "status": {
            "type": "string",
            "description": "pacs.002 `TransactionStatus` (ExternalPaymentTransactionStatus1Code).",
            "enum": [
              "PDNG",
              "ACCP",
              "ACSP",
              "ACCC",
              "RJCT"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Z0-9]{4}$",
            "description": "ExternalStatusReason1Code cuando `status` es `RJCT` (por ejemplo AM04, AC03, AC04, AB05, RR04)."
          }
        }
      },
      "AuthorizationCheckName": {
        "type": "string",
        "description": "`account`: entidad y cuenta habilitadas. `limits`: topes. `funds`: reserva en el libro. `counterparty`: titular\ndel destino en COELSA. `compliance`: listas sancionatorias y antifraude (se informa junto, sin detalle).\n",
        "enum": [
          "account",
          "limits",
          "funds",
          "counterparty",
          "compliance"
        ]
      },
      "AuthorizationCheck": {
        "type": "object",
        "required": [
          "name",
          "result"
        ],
        "properties": {
          "name": {
            "$ref": "#/components/schemas/AuthorizationCheckName"
          },
          "result": {
            "type": "string",
            "enum": [
              "passed",
              "failed",
              "not_run"
            ]
          }
        }
      },
      "Rationale": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "`approved`, o el código de error del rechazo (por ejemplo `insufficient_funds`).",
            "examples": [
              "approved"
            ]
          },
          "message": {
            "type": "string",
            "maxLength": 300
          }
        }
      },
      "Authorization": {
        "type": "object",
        "description": "Decisión de la autorización previa, con su motivo. FCM guarda además el detalle completo de cada control.",
        "required": [
          "decision",
          "decided_at",
          "rationale",
          "checks"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "description": "`approved`, `declined` o `pending` (la autorización todavía no terminó; `decided_at` es la hora en que quedó pendiente).",
            "enum": [
              "approved",
              "declined",
              "pending"
            ]
          },
          "decided_at": {
            "type": "string",
            "format": "date-time"
          },
          "rationale": {
            "$ref": "#/components/schemas/Rationale"
          },
          "checks": {
            "type": "array",
            "description": "Un resultado por control. `not_run` si no llegó a correr porque uno anterior falló.",
            "items": {
              "$ref": "#/components/schemas/AuthorizationCheck"
            }
          }
        }
      },
      "Reservation": {
        "type": "object",
        "description": "Reserva en el libro (transferencias pendientes) por el importe más los cargos.",
        "required": [
          "amount",
          "state",
          "placed_at",
          "resolved_at",
          "ledger_references"
        ],
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "state": {
            "type": "string",
            "description": "`held`: reservada. `posted`: asentada (la plata salió). `voided`: liberada. Una transferencia reabierta por una\nacreditación tardía sigue `voided` (la reserva se liberó al fallar y el importe se debitó con un\nasiento compensatorio); cuando FCM la cierra en `completed`, sin cargo, queda `posted` por el importe con las\nreferencias del asiento compensatorio.\n",
            "enum": [
              "held",
              "posted",
              "voided"
            ]
          },
          "placed_at": {
            "type": "string",
            "format": "date-time"
          },
          "resolved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ledger_references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerReference"
            }
          }
        }
      },
      "Rail": {
        "type": "object",
        "required": [
          "name",
          "operation_id",
          "origin_reference",
          "status_code",
          "submitted_at",
          "finalized_at"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "`coelsa`: transferencia por COELSA. `fcm_book`: interna entre cuentas de FCM.",
            "enum": [
              "coelsa",
              "fcm_book"
            ]
          },
          "operation_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id de la operación en COELSA.",
            "maxLength": 64
          },
          "origin_reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "`ori_trx_id` con el que FCM envió la operación. No cambia entre reintentos.",
            "pattern": "^\\d{1,16}$"
          },
          "status_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Último código de estado de COELSA (por ejemplo 7541 persistido, 7500 acreditado).",
            "maxLength": 8
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finalized_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "FailureCode": {
        "type": "string",
        "description": "`rail_rejected`: COELSA la rechazó (detalle en `rail.status_code` e `iso20022.reason`). `rail_expired`: venció\nen COELSA. `destination_closed`: la cuenta de destino no existe o está cerrada al momento de acreditar.\n`canceled_by_fcm`: FCM la canceló antes de enviarla (corte de emergencia, control posterior a la reserva o una transferencia `pending` que no se pudo autorizar).\n",
        "enum": [
          "rail_rejected",
          "rail_expired",
          "destination_closed",
          "canceled_by_fcm"
        ]
      },
      "Failure": {
        "type": "object",
        "required": [
          "code",
          "message",
          "display_message"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/FailureCode"
          },
          "message": {
            "type": "string",
            "maxLength": 300
          },
          "display_message": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          }
        }
      },
      "OutgoingTransfer": {
        "type": "object",
        "required": [
          "id",
          "object",
          "account_id",
          "account_number_id",
          "amount",
          "currency",
          "charges",
          "total_debit_amount",
          "destination",
          "counterparty",
          "concept",
          "description",
          "external_reference",
          "metadata",
          "status",
          "status_reason",
          "iso20022",
          "authorization",
          "reservation",
          "rail",
          "failure",
          "idempotency_key",
          "created_at",
          "updated_at",
          "completed_at",
          "failed_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/OutgoingTransferId"
          },
          "object": {
            "type": "string",
            "const": "outgoing_transfer"
          },
          "account_id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "account_number_id": {
            "description": "CVU que figura como origen ante COELSA. `null` si se rechazó antes de elegirlo.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AccountNumberId"
              },
              {
                "type": "null"
              }
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "charges": {
            "type": "array",
            "description": "Cargos de esta transferencia. Cada uno con importe es un asiento separado en el libro. Una transferencia reabierta por una acreditación tardía y completada va sin cargo y lo dice con un `fcm_fee` de `0` y su motivo.",
            "items": {
              "$ref": "#/components/schemas/Charge"
            }
          },
          "total_debit_amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "counterparty": {
            "description": "Titular verificado. `null` si se rechazó antes de consultar el destino.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Counterparty"
              },
              {
                "type": "null"
              }
            ]
          },
          "concept": {
            "$ref": "#/components/schemas/Concept"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 140
          },
          "external_reference": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ExternalReference"
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "status": {
            "$ref": "#/components/schemas/OutgoingTransferStatus"
          },
          "status_reason": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/OutgoingTransferStatusReason"
              },
              {
                "type": "null"
              }
            ]
          },
          "iso20022": {
            "$ref": "#/components/schemas/Iso20022OutgoingStatus"
          },
          "authorization": {
            "$ref": "#/components/schemas/Authorization"
          },
          "reservation": {
            "description": "`null` si se rechazó antes de reservar.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Reservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "rail": {
            "description": "`null` hasta que se envía.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Rail"
              },
              {
                "type": "null"
              }
            ]
          },
          "failure": {
            "description": "Presente sólo en `failed`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Failure"
              },
              {
                "type": "null"
              }
            ]
          },
          "idempotency_key": {
            "$ref": "#/components/schemas/IdempotencyKeyValue"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Hora en que quedó `failed`. Vuelve a `null` si se reabre por una acreditación tardía."
          }
        }
      },
      "OutgoingTransferList": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OutgoingTransfer"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Payer": {
        "type": "object",
        "description": "Quien pagó, según el aviso de COELSA. Cualquier dato puede faltar si COELSA no lo informa.",
        "required": [
          "name",
          "cuit",
          "account",
          "account_type",
          "bank_code"
        ],
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "cuit": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              },
              {
                "type": "null"
              }
            ]
          },
          "account": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BankKey"
              },
              {
                "type": "null"
              }
            ]
          },
          "account_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "cbu",
              "cvu",
              null
            ]
          },
          "bank_code": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^\\d{3}$"
          }
        }
      },
      "IncomingTransfer": {
        "type": "object",
        "required": [
          "id",
          "object",
          "account_id",
          "account_number_id",
          "cvu",
          "amount",
          "currency",
          "charges",
          "net_amount",
          "payer",
          "concept",
          "status",
          "iso20022",
          "rail",
          "ledger_references",
          "posted_at",
          "created_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/IncomingTransferId"
          },
          "object": {
            "type": "string",
            "const": "incoming_transfer"
          },
          "account_id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "account_number_id": {
            "$ref": "#/components/schemas/AccountNumberId"
          },
          "cvu": {
            "$ref": "#/components/schemas/BankKey"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "charges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Charge"
            }
          },
          "net_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "payer": {
            "$ref": "#/components/schemas/Payer"
          },
          "concept": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Z]{3}$",
            "description": "Concepto BCRA informado por COELSA, si viene."
          },
          "status": {
            "type": "string",
            "description": "En fase 1 siempre `posted`.",
            "enum": [
              "posted"
            ]
          },
          "iso20022": {
            "type": "object",
            "required": [
              "entry_status"
            ],
            "properties": {
              "entry_status": {
                "type": "string",
                "description": "camt.054 `EntryStatus`.",
                "enum": [
                  "BOOK"
                ]
              }
            }
          },
          "rail": {
            "type": "object",
            "required": [
              "name",
              "operation_id",
              "business_date"
            ],
            "properties": {
              "name": {
                "type": "string",
                "enum": [
                  "coelsa",
                  "fcm_book"
                ]
              },
              "operation_id": {
                "type": "string",
                "maxLength": 64,
                "description": "Id de COELSA del crédito, o el `otr_…` de origen si `name` es `fcm_book` (interna entre cuentas de FCM). Es la clave de idempotencia del asiento."
              },
              "business_date": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date",
                "description": "Fecha de negocio (compensación) informada por COELSA."
              }
            }
          },
          "ledger_references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerReference"
            }
          },
          "posted_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "IncomingTransferList": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IncomingTransfer"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "EventType": {
        "type": "string",
        "description": "Tipos de la fase 1. Pueden aparecer tipos nuevos sin aviso de versión; ignorá los que no conozcas.\n`transfer.outgoing.reopened`: una transferencia `failed` que COELSA acreditó después volvió a\n`submitted` (`status_reason: late_settlement_review`).\n",
        "enum": [
          "transfer.incoming.posted",
          "transfer.outgoing.reserved",
          "transfer.outgoing.completed",
          "transfer.outgoing.failed",
          "transfer.outgoing.reopened"
        ]
      },
      "EventData": {
        "type": "object",
        "description": "Referencia delgada al objeto. Para el estado vigente, pedí el objeto.",
        "required": [
          "object",
          "id",
          "account_id",
          "ledger_references"
        ],
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "incoming_transfer",
              "outgoing_transfer"
            ]
          },
          "id": {
            "type": "string",
            "maxLength": 40
          },
          "account_id": {
            "$ref": "#/components/schemas/AccountId"
          },
          "ledger_references": {
            "type": "array",
            "description": "Asientos del libro que produjeron el evento.",
            "items": {
              "$ref": "#/components/schemas/LedgerReference"
            }
          }
        }
      },
      "Event": {
        "type": "object",
        "required": [
          "id",
          "object",
          "type",
          "sequence",
          "entity_id",
          "api_version",
          "created_at",
          "data"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "object": {
            "type": "string",
            "const": "event"
          },
          "type": {
            "$ref": "#/components/schemas/EventType"
          },
          "sequence": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "description": "Contiguo y creciente por entidad, asignado en el orden en que se confirmó el cambio."
          },
          "entity_id": {
            "$ref": "#/components/schemas/EntityId"
          },
          "api_version": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/EventData"
          }
        }
      },
      "EventList": {
        "type": "object",
        "required": [
          "object",
          "data",
          "has_more",
          "next_after_sequence"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_after_sequence": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Valor para el próximo `after_sequence` (la `sequence` del último evento devuelto)."
          }
        }
      },
      "IdempotencyRecord": {
        "type": "object",
        "required": [
          "key",
          "object",
          "status",
          "method",
          "path",
          "request_fingerprint",
          "response_status",
          "resource",
          "created_at",
          "expires_at"
        ],
        "properties": {
          "key": {
            "$ref": "#/components/schemas/IdempotencyKeyValue"
          },
          "object": {
            "type": "string",
            "const": "idempotency_key"
          },
          "status": {
            "type": "string",
            "enum": [
              "in_progress",
              "completed"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "POST"
            ]
          },
          "path": {
            "type": "string",
            "maxLength": 200
          },
          "request_fingerprint": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "SHA-256 de método, ruta y cuerpo canonizado (RFC 8785)."
          },
          "response_status": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 200,
            "maximum": 499
          },
          "resource": {
            "description": "Objeto creado o afectado, si lo hubo.",
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "object",
                  "id"
                ],
                "properties": {
                  "object": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ErrorType": {
        "type": "string",
        "enum": [
          "invalid_request_error",
          "authentication_error",
          "permission_error",
          "not_found_error",
          "idempotency_error",
          "transfer_declined",
          "rate_limit_error",
          "service_error"
        ]
      },
      "ErrorCode": {
        "type": "string",
        "description": "Ver la tabla de códigos en la descripción general.",
        "enum": [
          "invalid_request",
          "parameter_missing",
          "parameter_invalid",
          "amount_invalid",
          "currency_not_supported",
          "concept_not_supported",
          "destination_invalid",
          "unsupported_version",
          "idempotency_key_missing",
          "idempotency_key_invalid",
          "api_key_missing",
          "api_key_invalid",
          "signature_missing",
          "signature_invalid",
          "signature_expired",
          "signature_replayed",
          "signature_key_unknown",
          "content_digest_mismatch",
          "ip_not_allowed",
          "environment_mismatch",
          "entity_suspended",
          "not_found",
          "idempotency_key_reused",
          "idempotency_request_in_progress",
          "insufficient_funds",
          "account_frozen",
          "account_closed",
          "limit_per_transfer_exceeded",
          "limit_daily_exceeded",
          "limit_monthly_exceeded",
          "destination_not_found",
          "destination_inactive",
          "destination_is_source",
          "destination_holder_mismatch",
          "compliance_rejected",
          "risk_rejected",
          "rate_limited",
          "internal_error",
          "rail_unavailable",
          "ledger_unavailable",
          "transfers_paused",
          "service_unavailable"
        ]
      },
      "ErrorBody": {
        "type": "object",
        "required": [
          "type",
          "code",
          "message",
          "display_message",
          "param",
          "request_id",
          "retryable",
          "doc_url",
          "transfer_id"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/ErrorType"
          },
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "message": {
            "type": "string",
            "description": "Explicación técnica para quien integra. No mostrar a usuarios finales."
          },
          "display_message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Texto en castellano apto para mostrar a un usuario final, o `null`."
          },
          "param": {
            "type": [
              "string",
              "null"
            ],
            "description": "Campo o header que causó el error, si aplica."
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          },
          "retryable": {
            "type": "boolean",
            "description": "`true`: reintentá el mismo pedido con la misma Idempotency-Key."
          },
          "doc_url": {
            "type": "string",
            "format": "uri"
          },
          "transfer_id": {
            "description": "En un `422` de transferencia, el id del objeto que quedó en `rejected`.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/OutgoingTransferId"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody"
          }
        }
      },
      "JwkOkp": {
        "type": "object",
        "required": [
          "kty",
          "crv",
          "x",
          "kid",
          "alg",
          "use"
        ],
        "properties": {
          "kty": {
            "type": "string",
            "const": "OKP"
          },
          "crv": {
            "type": "string",
            "const": "Ed25519"
          },
          "x": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "kid": {
            "type": "string",
            "maxLength": 64
          },
          "alg": {
            "type": "string",
            "const": "EdDSA"
          },
          "use": {
            "type": "string",
            "const": "sig"
          }
        }
      },
      "JwkEc": {
        "type": "object",
        "required": [
          "kty",
          "crv",
          "x",
          "y",
          "kid",
          "alg",
          "use"
        ],
        "properties": {
          "kty": {
            "type": "string",
            "const": "EC"
          },
          "crv": {
            "type": "string",
            "const": "P-256"
          },
          "x": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "y": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "kid": {
            "type": "string",
            "maxLength": 64
          },
          "alg": {
            "type": "string",
            "const": "ES256"
          },
          "use": {
            "type": "string",
            "const": "sig"
          }
        }
      },
      "Jwks": {
        "type": "object",
        "required": [
          "keys"
        ],
        "properties": {
          "keys": {
            "type": "array",
            "minItems": 1,
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/JwkOkp"
                },
                {
                  "$ref": "#/components/schemas/JwkEc"
                }
              ]
            }
          }
        }
      },
      "SimulateIncomingTransferRequest": {
        "type": "object",
        "required": [
          "account_number_id",
          "amount"
        ],
        "additionalProperties": false,
        "properties": {
          "account_number_id": {
            "$ref": "#/components/schemas/AccountNumberId"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "payer": {
            "type": "object",
            "additionalProperties": false,
            "description": "Datos del pagador simulado. Si falta, se usa uno sintético.",
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 120
              },
              "cuit": {
                "$ref": "#/components/schemas/Cuit"
              },
              "account": {
                "$ref": "#/components/schemas/BankKey"
              }
            }
          },
          "concept": {
            "$ref": "#/components/schemas/Concept"
          }
        }
      },
      "SimulateRailResultRequest": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "additionalProperties": false,
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "completed",
              "failed"
            ]
          },
          "coelsa_code": {
            "type": "string",
            "pattern": "^\\d{2,4}$",
            "description": "Código de COELSA a simular. Por defecto 7500 si `completed` y 7699 si `failed`."
          }
        }
      },
      "SimulateLateSettlementReviewRequest": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "additionalProperties": false,
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "completed"
            ],
            "description": "La única salida de la revisión de una acreditación tardía: dos personas de FCM confirman que la plata salió y la transferencia se cierra en `completed`, sin cargo."
          }
        }
      },
      "SandboxClock": {
        "type": "object",
        "required": [
          "object",
          "entity_id",
          "now",
          "offset_seconds"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "sandbox_clock"
          },
          "entity_id": {
            "$ref": "#/components/schemas/EntityId"
          },
          "now": {
            "type": "string",
            "format": "date-time",
            "description": "Hora de la entidad en el sandbox."
          },
          "offset_seconds": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Cuánto está adelantada respecto de la hora real."
          }
        }
      },
      "AdvanceClockRequest": {
        "type": "object",
        "required": [
          "advance_seconds"
        ],
        "additionalProperties": false,
        "properties": {
          "advance_seconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2678400,
            "description": "Segundos a adelantar (hasta 31 días por pedido)."
          }
        }
      }
    }
  }
}
