{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base",
  "info": {
    "title": "API de empresas clientes do Grip Rails (fase 1)",
    "version": "2026-10-15",
    "summary": "Contas de pagamento em pesos argentinos, CVU, transferências pela COELSA e eventos para empresas clientes da FCM Payment Solutions S.A.S.",
    "description": "API para que as empresas clientes da **FCM Payment Solutions S.A.S.** (prestadora de serviços de pagamento que oferece\ncontas de pagamento, registrada no BCRA, o Banco Central da República Argentina; PSP 214 na COELSA, a câmara de\ncompensação argentina de transferências imediatas) operem **contas de pagamento em pesos argentinos**: consultar saldos,\nusar seus CVU (números de conta virtual argentinos), validar contrapartes, ordenar transferências pela COELSA e ficar\nsabendo dos créditos recebidos.\n\nÉ o contrato da **fase 1**, multicliente desde o primeiro dia: cada entidade tem suas credenciais, suas chaves de\nassinatura, sua URL de webhook, suas contas no ledger, seus CVU, seus limites e sua tarifa. Este contrato é estável: a implementação pode mudar e a integração do cliente, não.\n\n## O que esta API não faz\n\n- **Não opera ativos digitais.** Não há criptoativos, stablecoins, endereços de blockchain, conversões nem cotações. O\n  texto ordenado de PSP do BCRA (item 4.6) proíbe a FCM Payment Solutions S.A.S. de realizar e de facilitar essas\n  operações. Se um cliente opera cripto, essa ponta é executada por outra pessoa jurídica regulada, e a\n  FCM Payment Solutions S.A.S. só movimenta pesos mediante instruções.\n- **Não opera moeda estrangeira nem remessas ao exterior.** A única moeda é `ARS`, e os destinos são CBU, CVU ou alias\n  do sistema argentino.\n- **Não cria CVU nem contas na fase 1.** O Grip Rails os cadastra a pedido da entidade (aparecem como números de conta\n  listáveis). O cadastro pela API é da fase 2.\n\nA FCM Payment Solutions S.A.S. limita-se a oferecer serviços de pagamento e não está autorizada pelo BCRA a operar como\ninstituição financeira. Os fundos depositados em contas de pagamento não constituem depósitos em uma instituição\nfinanceira nem contam com nenhuma das garantias de que tais depósitos possam gozar de acordo com a legislação e a\nregulamentação aplicáveis aos depósitos em instituições financeiras.\n\n## Ambientes\n\n| | Produção | Sandbox |\n|---|---|---|\n| Host | `https://api.fcmpayments.com` | `https://empresas-sandbox.fcmpayments.com` |\n| API keys | `fcm_live_…` | `fcm_test_…` |\n| Dinheiro | Real. As transferências pela COELSA (a câmara de compensação argentina) são irreversíveis. | Simulado. Ledger e trilho próprios do sandbox. |\n| Simuladores (`/v1/simulations/*`) | Não existem (404) | Sim |\n\nUma chave de um ambiente usada no outro responde `403 environment_mismatch`.\n\n## Autenticação: API key e assinatura de cada requisição\n\nToda requisição leva **as duas coisas**:\n\n1. `Authorization: Bearer fcm_live_…`: a API key da entidade. O Grip Rails a guarda com hash. Pode haver duas ativas\n   para fazer a rotação sem interrupção.\n2. **Assinatura HTTP da requisição (RFC 9421, HTTP Message Signatures)** feita com a chave privada do cliente. O Grip\n   Rails guarda só a chave pública, registrada no cadastro (até duas ativas por ambiente). Algoritmos: `ed25519` ou\n   `ecdsa-p256-sha256`.\n   - Componentes assinados obrigatórios: `\"@method\"` e `\"@target-uri\"`. Se a requisição tem corpo, também\n     `\"content-type\"`, `\"content-digest\"` e `\"idempotency-key\"`. Se você envia `FCM-Version`, também\n     `\"fcm-version\"`. **`\"authorization\"` não é assinado**: uma assinatura que o cobre é rejeitada com\n     `signature_invalid`. Assim o Grip Rails pode verificar de novo a assinatura de cada instrução com a sua chave\n     pública, sem a sua API key, que ele só guarda com hash.\n   - Parâmetros obrigatórios da assinatura: `created` (segundos Unix; aceita-se ±300 s), `nonce` (16 a 64 caracteres\n     base64url, único por chave durante 10 minutos), `keyid` (id da sua chave pública, `ck_…`) e `alg`.\n   - Com corpo: `Content-Digest: sha-256=:…:` (RFC 9530) calculado sobre os bytes exatos que você envia.\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\nEm produção, a entidade pode pedir uma lista de IPs permitidos. mTLS é oferecido como camada adicional na fase 2 para\nquem o exigir; não substitui a assinatura.\n\n## Idempotência\n\n- `Idempotency-Key` é **obrigatória em todo `POST`** (16 a 128 caracteres `A-Z a-z 0-9 . _ : -`; recomenda-se UUID ou\n  ULID). O escopo é a entidade naquele ambiente.\n- Mesma chave e mesma requisição: mesma resposta (código e corpo), com `Idempotent-Replayed: true`.\n- Mesma chave com outra requisição (impressão digital SHA-256 do método, do caminho e do corpo canonizado segundo a\n  RFC 8785): `409 idempotency_key_reused`.\n- Enquanto a primeira requisição está em andamento: `409 idempotency_request_in_progress` (pode ser repetida).\n- As respostas `5xx` não são guardadas: repita com a **mesma** chave.\n- O registro completo vive **35 dias** e é consultado com `GET /v1/idempotency_keys/{idempotency_key}`. A chave de uma\n  transferência fica vinculada a essa transferência **para sempre**: não pode ser reutilizada nem depois dos 35 dias, e\n  a transferência é buscada com `GET /v1/outgoing_transfers?idempotency_key=…`.\n- Se a primeira resposta se perdeu (por exemplo, numa queda de conexão), a nova tentativa devolve o **estado atual** da\n  mesma transferência, que pode estar mais avançado que o original.\n- Uma resposta `202` é guardada e repetida como qualquer `2xx`. O estado vigente é consultado com\n  `GET /v1/outgoing_transfers/{id}` ou chega por webhook.\n\n## Versionamento\n\n- A versão maior vai no caminho (`/v1`) e só muda diante de um redesenho total.\n- A versão por data vai em `FCM-Version: AAAA-MM-DD`. Cada entidade fica fixada na versão vigente quando é cadastrada e\n  pode testar outra enviando o cabeçalho. A resposta devolve a versão usada.\n- Entram sem versão nova as mudanças aditivas: endpoints novos, campos opcionais novos nas requisições, campos novos nas\n  respostas, valores novos em enums de resposta e tipos de evento novos. **Sua integração precisa ignorar campos e\n  tipos de evento desconhecidos e tolerar valores de enum novos.**\n- O que quebra compatibilidade só sai numa versão nova. Uma versão é mantida por pelo menos 12 meses depois de\n  publicada a seguinte, e sua retirada é avisada com 6 meses de antecedência (cabeçalhos `Deprecation` e `Sunset`,\n  e-mail ao contato técnico e changelog). Há no máximo duas versões vigentes ao mesmo tempo.\n- Os webhooks e os eventos são montados na versão fixada da entidade (campo `api_version`).\n\n## Valores, moeda e datas\n\n- Valores: **inteiros em centavos** de peso argentino (`150000` = ARS 1.500,00). Moeda: só `ARS`.\n- Datas e horas: RFC 3339 em UTC. O dia de negócio e os limites diários e mensais usam o calendário de Buenos Aires\n  (`America/Argentina/Buenos_Aires`).\n\n## Paginação\n\nAs listas vêm do mais novo para o mais antigo. `limit` vai de 1 a 100 (25 por padrão); para a página seguinte, envie\n`starting_after` com o `next_cursor` recebido. Os eventos são diferentes: ordem crescente por `sequence` (veja \"Eventos\ne webhooks\").\n\n## Erros\n\nTodo erro tem a mesma 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` é para quem integra; `display_message` é um texto em espanhol adequado para mostrar a um usuário final (ou\n`null`). `retryable: true` significa: repita a mesma requisição com a mesma `Idempotency-Key`.\n\n| `code` | HTTP | Pode repetir | ISO 20022 (motivo) |\n|---|---|---|---|\n| `invalid_request` | 400 | não | |\n| `parameter_missing` | 400 | não | |\n| `parameter_invalid` | 400 | não | |\n| `amount_invalid` | 400 | não | AM12 |\n| `currency_not_supported` | 400 | não | AM03 |\n| `concept_not_supported` | 400 | não | |\n| `destination_invalid` | 400 | não | AC01 |\n| `unsupported_version` | 400 | não | |\n| `idempotency_key_missing` | 400 | não | |\n| `idempotency_key_invalid` | 400 | não | |\n| `api_key_missing` | 401 | não | |\n| `api_key_invalid` | 401 | não | |\n| `signature_missing` | 401 | não | |\n| `signature_invalid` | 401 | não | |\n| `signature_expired` | 401 | sim, com nova assinatura | |\n| `signature_replayed` | 401 | não | |\n| `signature_key_unknown` | 401 | não | |\n| `content_digest_mismatch` | 401 | não | |\n| `ip_not_allowed` | 403 | não | |\n| `environment_mismatch` | 403 | não | |\n| `entity_suspended` | 403 | não | |\n| `not_found` | 404 | não | |\n| `idempotency_key_reused` | 409 | não | |\n| `idempotency_request_in_progress` | 409 | sim | |\n| `insufficient_funds` | 422 | não | AM04 |\n| `account_frozen` | 422 | não | AC06 |\n| `account_closed` | 422 | não | AC04 |\n| `limit_per_transfer_exceeded` | 422 | não | AM02 |\n| `limit_daily_exceeded` | 422 | não | AM14 |\n| `limit_monthly_exceeded` | 422 | não | AM14 |\n| `destination_not_found` | 422 | não | AC03 |\n| `destination_inactive` | 422 | não | AC04 |\n| `destination_is_source` | 422 | não | AG01 |\n| `destination_holder_mismatch` | 422 | não | BE01 |\n| `compliance_rejected` | 422 | não | RR04 |\n| `risk_rejected` | 422 | não | AG01 |\n| `rate_limited` | 429 | sim | |\n| `internal_error` | 500 | sim | |\n| `rail_unavailable` | 503 | sim | |\n| `ledger_unavailable` | 503 | sim | |\n| `transfers_paused` | 503 | sim | |\n| `service_unavailable` | 503 | sim | |\n\n`compliance_rejected` e `risk_rejected` são deliberadamente genéricos: a FCM Payment Solutions S.A.S. não informa o\ndetalhe de um controle de prevenção à lavagem de dinheiro (Lei 25.246 da Argentina, dever de não revelar).\nA FCM Payment Solutions S.A.S. guarda, sim, o motivo completo.\n\n## Transferências de saída: autorizar antes de transferir\n\nVeja `POST /v1/outgoing_transfers`. Estados e seu equivalente ISO 20022 (pacs.002, `TransactionStatus`):\n\n| `status` | O que significa | Reserva no ledger | ISO 20022 |\n|---|---|---|---|\n| `pending` | O Grip Rails recebeu a ordem, mas ainda não consegue confirmar a autorização. Pode haver dinheiro reservado. Não repita com outra Idempotency-Key. | Pode haver uma pendente | `PDNG` |\n| `rejected` | A autorização a rejeitou. Não saiu dinheiro. | Não há, ou foi liberada | `RJCT` |\n| `reserved` | Autorizada; valor mais encargos reservados; ainda não foi enviada à COELSA. | Pendente | `ACCP` |\n| `submitted` | Enviada à COELSA; falta o resultado. Com `status_reason: late_settlement_review`, reaberta por uma liquidação tardia (veja abaixo). | Pendente (reaberta: liberada, com o valor já debitado) | `ACSP` |\n| `completed` | A COELSA a creditou no destino. | Lançada | `ACCC` |\n| `failed` | A COELSA a rejeitou ou ela expirou. Sem encargo. Se a COELSA a creditar depois, ela é reaberta e o valor é debitado, sempre sem tarifa (veja abaixo). | Liberada | `RJCT` |\n\n**Liquidação tardia.** Se a COELSA credita uma transferência que já informamos a você como `failed` (o aviso chegou\ntarde ou se perdeu), o dinheiro saiu e o Grip Rails a reabre: ela volta a `submitted` com `status_reason:\nlate_settlement_review` (ISO `ACSP`; `failure` e `failed_at` voltam a `null`) e avisamos você com o evento\n`transfer.outgoing.reopened`. O valor é debitado da sua conta de fundos com um lançamento compensatório (suas\nreferências vão no evento); se os fundos não bastarem, a sua conta de garantia cobre o que faltar e o restante fica como\ndívida com a FCM Payment Solutions S.A.S., conforme o contrato. O Grip Rails desabilita as suas transferências de saída,\ne elas continuam desabilitadas, mesmo depois de `completed`, até que o Grip Rails volte a habilitá-las (só no sandbox\nelas são reabilitadas sozinhas depois do fechamento simulado: veja Sandbox). Quando duas pessoas do Grip Rails confirmam\na liquidação, a transferência passa a `completed` (evento `transfer.outgoing.completed`) **sem custo**: o Grip Rails não\ncobra tarifa por uma transferência reaberta, porque a reabertura não é culpa sua (o Grip Rails só libera uma reserva com\nevidência). `charges` informa isso com um encargo `fcm_fee` de `0` e o seu motivo, e `total_debit_amount` é o valor. É\na única forma de sair de `failed`; não a repita com outra Idempotency-Key.\n\nOs créditos recebidos têm um único estado na fase 1, `posted`, equivalente a `BOOK` (camt.054).\n\n## Eventos e webhooks\n\n- **Webhooks enxutos:** o corpo traz o tipo e o id do objeto, não o objeto. Para o estado vigente, peça o objeto com o\n  seu `GET`.\n- **Conciliação por cursor:** `GET /v1/events?after_sequence=N`. `sequence` é contíguo por entidade (1, 2, 3…): se você\n  recebeu o 41 e depois o 43, falta o 42. Cada evento de dinheiro traz `ledger_references`, a referência estável aos\n  lançamentos do ledger que o produziram.\n- **Entrega pelo menos uma vez.** Um webhook pode chegar repetido ou fora de ordem: deduplique pelo `id` do evento e\n  ordene por `sequence`.\n- **Novas tentativas:** se o seu endpoint não responder `2xx` em 10 s, tentamos mais 24 vezes (25 tentativas) durante\n  cerca de 4,7 dias: 30 s, 1 min, 2 min, 5 min, 10 min, 15 min, 30 min, 1 h, 2 h, 3 h, 4 h, 5 h e depois a cada 8 h,\n  com ±20% de variação. Os eventos ficam em `/v1/events` por 90 dias.\n- **Assinatura assimétrica:** o cabeçalho `FCM-Signature` é um JWS compacto (JWT) assinado pelo Grip Rails com uma\n  chave assimétrica guardada em KMS (`EdDSA` sobre Ed25519 ou `ES256` sobre P-256; o JWKS diz qual). Claims: `iss`\n  (`https://api.fcmpayments.com`), `aud` (o seu `entity_id`), `iat`, `exp` (`iat` + 300), `jti` (id da entrega, único),\n  `evt` (id do evento) e `body_sha256` (SHA-256 dos bytes brutos do corpo, em base64url sem preenchimento).\n- **Como verificar:** (1) leia `kid` e `alg` do cabeçalho do JWS e busque essa chave no JWKS (em cache; se o `kid` não\n  estiver lá, atualize no máximo uma vez por minuto); (2) verifique a assinatura com o `alg` que o JWKS publica para esse\n  `kid`, nunca com o que a requisição diz, se não coincidirem; (3) exija `iat` dentro dos últimos 5 minutos e `exp`\n  futuro; (4) recalcule `body_sha256` sobre o corpo bruto; (5) rejeite um `jti` já visto (guarde-o por 10 minutos);\n  (6) exija `aud` igual ao seu `entity_id`.\n- **JWKS:** `GET /.well-known/jwks.json`, sem autenticação e com cache permitido. Uma chave nova é publicada 7 dias\n  antes de começar a ser usada, e a antiga continua publicada 7 dias depois de deixar de ser usada.\n- **O seu endpoint:** HTTPS público com TLS 1.2 ou superior, sem redirecionamentos (não os seguimos), resposta em no\n  máximo 10 s. Processe em segundo plano. A URL é registrada pelo Grip Rails no cadastro e é alterada mediante pedido\n  verificado.\n\n## Sandbox\n\n- As transferências de saída se completam sozinhas em ~2 s, exceto pelos centavos do valor: `…13` termina `failed` com\n  `destination_closed` (COELSA 7502), `…70` termina `failed` com `rail_expired` (COELSA 7570) e `…99` fica em\n  `submitted` até que você o resolva com `POST /v1/simulations/outgoing_transfers/{id}/rail_result`.\n- Alias de teste (os nomes legíveis das contas argentinas) para validar contrapartes: `sbx.valida` (válida),\n  `sbx.inactiva`, `sbx.inexistente`, `sbx.bloqueada` (controle de compliance) e `sbx.otro.titular` (um CUIT, a\n  identificação fiscal argentina, diferente do esperado, se você enviar `expected_cuit`). Qualquer CBU (número de conta\n  bancária) ou CVU (número de conta virtual) com dígitos verificadores corretos é validado com um titular sintético.\n- `POST /v1/simulations/incoming_transfers` simula um crédito recebido: percorre o mesmo caminho que um aviso real da\n  COELSA (lançamento, tarifa, evento e webhook).\n- Relógio de teste por entidade: `GET /v1/simulations/clock` e `POST /v1/simulations/clock/advance` avançam a hora da\n  entidade (limites diários e mensais, novas tentativas de webhooks, vencimentos).\n- Liquidação tardia, em dois passos: sobre uma transferência `failed` que saiu pela COELSA (por exemplo, uma `…13`),\n  `POST /v1/simulations/outgoing_transfers/{id}/rail_result` com `{\"outcome\":\"completed\"}` simula que a COELSA a\n  creditou depois, pelo mesmo caminho que em produção (débito compensatório do valor, transferências de saída\n  desabilitadas, `submitted` com `late_settlement_review` e o evento `transfer.outgoing.reopened`). Depois,\n  `POST /v1/simulations/outgoing_transfers/{id}/late_settlement_review` com `{\"outcome\":\"completed\"}` simula que duas\n  pessoas do Grip Rails confirmam a liquidação: alguns segundos depois o Grip Rails a fecha como `completed`, sem custo,\n  com o evento `transfer.outgoing.completed`. Como em produção, a partir do primeiro passo as suas transferências de\n  saída ficam desabilitadas (`403 entity_suspended`). **Só no sandbox**, alguns segundos depois desse\n  `transfer.outgoing.completed` o Grip Rails volta a habilitá-las sozinho (`GET /v1/entity` volta a `active`; não se o\n  Grip Rails tiver bloqueado a sua entidade nesse meio-tempo) e você pode continuar testando; em produção elas continuam\n  desabilitadas até que o Grip Rails as reabilite.\n\n## Limites de uso\n\nPor entidade: 5 escritas e 25 leituras por segundo (ampliáveis por contrato). Ao ultrapassar: `429 rate_limited` com\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": "Produção. Dinheiro real; as transferências pela COELSA são irreversíveis."
    },
    {
      "url": "https://empresas-sandbox.fcmpayments.com",
      "description": "Sandbox. Ledger e trilho simulados; nunca movimenta dinheiro real."
    }
  ],
  "security": [
    {
      "apiKey": [],
      "requestSignature": []
    }
  ],
  "tags": [
    {
      "name": "Entidad",
      "description": "A empresa cliente autenticada, seus limites, seu uso e suas tarifas."
    },
    {
      "name": "Cuentas",
      "description": "Contas de pagamento em pesos da entidade (fundos e garantia), com seu saldo no ledger."
    },
    {
      "name": "Números de cuenta",
      "description": "CVU de cada conta (N por conta). A entidade é a titular de todos."
    },
    {
      "name": "Contrapartes",
      "description": "Validação do titular de um destino junto à COELSA antes de pagar."
    },
    {
      "name": "Transferencias salientes",
      "description": "Pagamentos em pesos para CBU, CVU ou alias, com autorização prévia e reserva no ledger."
    },
    {
      "name": "Transferencias entrantes",
      "description": "Créditos recebidos nos CVU da entidade, lançados com liquidação real da COELSA."
    },
    {
      "name": "Eventos",
      "description": "Registro ordenado do que aconteceu, para conciliar e para os webhooks."
    },
    {
      "name": "Idempotencia",
      "description": "Consulta de uma Idempotency-Key usada."
    },
    {
      "name": "Claves de FCM",
      "description": "Chaves públicas com que o Grip Rails assina os webhooks."
    },
    {
      "name": "Sandbox",
      "description": "Simuladores. Só existem no sandbox."
    }
  ],
  "paths": {
    "/v1/entity": {
      "get": {
        "operationId": "getEntity",
        "tags": [
          "Entidad"
        ],
        "summary": "Ver a entidade autenticada",
        "description": "Devolve a entidade dona da API key, com seus limites, o uso do dia e do mês e suas tarifas.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "A entidade.",
            "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 contas",
        "description": "Lista as contas da entidade com seu saldo e seu estado.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de contas.",
            "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 uma conta (saldo e estado)",
        "description": "Saldo e estado de uma conta. O saldo vem do ledger no momento da requisição:\n`posted` é o lançado, `held` o reservado por transferências de saída em andamento e `available` = `posted` − `held`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "A conta.",
            "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": "Conta de fundos com uma saída em andamento",
                    "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 conta (CVU)",
        "description": "Lista os CVU da entidade. Uma conta pode ter N CVU (por exemplo, um para cada usuário ou comerciante do cliente, para\natribuir recebimentos); a entidade é a titular de todos, e o que entra por qualquer um deles é lançado na mesma conta.\nNa fase 1, quem os cadastra é o Grip Rails.\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 conta.",
            "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 um número de conta",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "O número de conta.",
            "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 uma contraparte",
        "description": "Consulta na COELSA quem é o titular de um CBU, CVU ou alias, se a conta está ativa e se passa nos controles de\ncompliance do Grip Rails. Não movimenta dinheiro.\n\nUma validação `valid` dura 15 minutos (`expires_at`) e pode ser passada em `counterparty_validation_id` ao criar a\ntransferência para não consultar de novo. Um resultado negativo não é um erro HTTP: responde `201` com o `result`\ncorrespondente. Se a COELSA não responder: `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 um alias esperando um CUIT",
                  "value": {
                    "destination": {
                      "type": "alias",
                      "value": "proveedor.ejemplo"
                    },
                    "expected_cuit": "27000000006"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Validação feita (o resultado pode 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 e ativo",
                    "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": "Criar uma transferência de saída",
        "description": "Ordena uma transferência em pesos de uma conta da entidade para um CBU, CVU ou alias.\n\n**Antes de movimentar um peso, o Grip Rails autoriza**, nesta ordem:\n\n1. Conta e entidade ativas, conta não congelada e transferências habilitadas.\n2. Limite por operação.\n3. **Reserva** no ledger (transferência pendente) pelo valor mais os encargos. Sem saldo\n   disponível: `insufficient_funds`.\n4. Titular do destino segundo a COELSA (ou uma validação vigente passada em `counterparty_validation_id`): existe,\n   está ativo, não é a mesma conta e, se você enviou `expected_counterparty_cuit`, coincide.\n5. Listas de sanções (o RePET da Argentina, a ONU e a OFAC) sobre o titular do destino.\n6. Limites diário e mensal da entidade (contam as transferências `reserved`, `submitted` e `completed`).\n7. Regras antifraude.\n\n**Se tudo passar:** `201` com a transferência em `reserved` e o evento `transfer.outgoing.reserved`. O Grip Rails a\nenvia à COELSA em seguida (`submitted`) e a fecha com o aviso da COELSA: `completed` (o dinheiro chegou e a reserva é\nlançada, com o evento `transfer.outgoing.completed`) ou `failed` (a reserva é liberada, não há encargo, evento\n`transfer.outgoing.failed`). Se a COELSA a creditar depois de informá-la como `failed`, o Grip Rails a reabre\n(`submitted` com `status_reason: late_settlement_review`, evento `transfer.outgoing.reopened`) e a fecha como\n`completed`: veja \"Liquidação tardia\" na descrição geral.\n\n**Se o Grip Rails não conseguir confirmar o resultado no momento:** `202` com a transferência em `pending`, ou em\n`submitted` com `status_reason: rail_outcome_unknown` se uma nova tentativa a encontrar já enviada e sem resultado. A\nordem existe e está vinculada à sua Idempotency-Key: não a repita com outra chave. Uma `pending` termina em `reserved`\n(evento `transfer.outgoing.reserved`) ou em `failed` com `failure.code: canceled_by_fcm` (evento\n`transfer.outgoing.failed`).\n\n**Se algo falhar:** `422` com o motivo em `error.code`. A transferência fica guardada em `rejected` (seu id vai em\n`error.transfer_id`) e a reserva, se chegou a ser feita, é liberada. As requisições mal formadas (`400`) não criam nada.\n\n**A COELSA é irreversível:** o Grip Rails não libera uma reserva já enviada sem evidência de rejeição. Se o resultado\nnão chegar, a transferência continua em `submitted` com `status_reason: rail_outcome_unknown` e o dinheiro continua\nreservado até que se resolva. Nunca é reenviada com outro identificador.\n\nSe o destino é uma conta do Grip Rails, a transferência é interna (`rail.name: fcm_book`) e se completa na hora.\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": "Pagamento a um CBU com controle 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 e 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": "Recém-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": "Recebida; o resultado ainda não pode ser confirmado. Não repita com outra 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 transferências de saída",
        "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 a transferência criada com esta Idempotency-Key (funciona também depois dos 35 dias).",
            "schema": {
              "$ref": "#/components/schemas/IdempotencyKeyValue"
            }
          },
          {
            "name": "external_reference",
            "in": "query",
            "required": false,
            "description": "Filtra pela sua referência.",
            "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 transferências de saída.",
            "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 uma transferência de saída",
        "description": "Estado vigente da transferência. É o que se deve consultar ao receber um webhook.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "A transferência.",
            "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": "Creditada pela 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 recebidos",
        "description": "Créditos recebidos nos CVU da entidade. Cada um nasce de um aviso da COELSA verificado (crédito já liquidado na conta\narrecadadora da FCM Payment Solutions S.A.S.) e é lançado no ledger com a sua tarifa como lançamento separado.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/AccountIdQuery"
          },
          {
            "name": "account_number_id",
            "in": "query",
            "required": false,
            "description": "Filtra pelo CVU por onde entrou.",
            "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 recebidos.",
            "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 um crédito recebido",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "O crédito recebido.",
            "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 um CVU de referência",
                    "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 da entidade em ordem crescente de `sequence`, a partir do seguinte a `after_sequence`. Sem filtro de tipo,\n`sequence` é contíguo: guarde o último que você processou e peça a partir daí. Com o filtro `type`, a sequência tem\nsaltos por design (é só para consulta). É a fonte para conciliar; os webhooks são um aviso.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "name": "after_sequence",
            "in": "query",
            "required": false,
            "description": "Devolve os eventos com `sequence` maior que este valor. Por padrão, 0 (a partir do primeiro disponível).",
            "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": "Quantidade 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": "Dois 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 um evento",
        "description": "Serve para confirmar por outra via um webhook recebido.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "O 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": "A Idempotency-Key usada.",
          "schema": {
            "$ref": "#/components/schemas/IdempotencyKeyValue"
          }
        }
      ],
      "get": {
        "operationId": "getIdempotencyKey",
        "tags": [
          "Idempotencia"
        ],
        "summary": "Consultar uma Idempotency-Key",
        "description": "Diz se a chave está em andamento ou concluída, com que requisição foi usada (impressão digital), o que respondemos e que\nobjeto criou. Disponível por 35 dias desde o primeiro uso. As chaves de transferências continuam vinculadas à sua\ntransferência depois desse prazo (veja `GET /v1/outgoing_transfers?idempotency_key=`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "O registro da chave.",
            "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": "Chaves públicas do Grip Rails para verificar webhooks",
        "description": "JWKS (RFC 7517) com as chaves públicas vigentes com que o Grip Rails assina os webhooks. Não exige autenticação.\nAs chaves privadas vivem em KMS e não saem de lá.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "Conjunto de chaves.",
            "headers": {
              "Cache-Control": {
                "description": "Pode ficar em cache por 5 minutos.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "public, max-age=300"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Jwks"
                },
                "examples": {
                  "p256": {
                    "summary": "Uma chave 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 um crédito recebido",
        "description": "Monta um aviso sintético da COELSA para um CVU da entidade e o faz passar pelo mesmo caminho que um real: lançamento no\nledger do sandbox, tarifa, evento `transfer.incoming.posted` e webhook. Só no 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 ARS 15.000",
                  "value": {
                    "account_number_id": "acn_01JA2B3C4D5E6F7G8H9JKMNPQD",
                    "amount": 1500000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Crédito simulado e lançado.",
            "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 o resultado da COELSA para uma transferência",
        "description": "Injeta o aviso de resultado da COELSA (equivalente a `AvisoOperacionFinalizada`) para uma transferência em `submitted`:\n`completed` lança a reserva e `failed` a libera. Sobre uma transferência `failed` que saiu pela COELSA, `completed`\nsimula uma liquidação tardia: o aviso chega depois de liberada a reserva e o Grip Rails reabre a transferência pelo\nmesmo caminho que em produção (débito compensatório do valor, transferências de saída desabilitadas, `submitted` com\n`status_reason: late_settlement_review` e o evento `transfer.outgoing.reopened`). Só no sandbox. Qualquer outro caso\nresponde `400 parameter_invalid`: outro estado, uma `failed` com `outcome: failed`, uma `failed` que nunca saiu para a\nCOELSA ou uma reaberta (quem a fecha é o Grip Rails: veja\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": "A COELSA rejeita por conta inexistente",
                  "value": {
                    "outcome": "failed",
                    "coelsa_code": "7502"
                  }
                },
                "acreditacion_tardia": {
                  "summary": "Sobre uma transferência failed, a COELSA a credita depois (liquidação tardia)",
                  "value": {
                    "outcome": "completed"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado aplicado. Devolve a transferência atualizada.",
            "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 duas pessoas do Grip Rails confirmam uma liquidação tardia",
        "description": "Para uma transferência reaberta por uma liquidação tardia (`submitted` com `status_reason: late_settlement_review`),\nsimula que duas pessoas do Grip Rails confirmam a liquidação: no sandbox são dois operadores sintéticos diferentes que\npropõem e aprovam a conciliação pelo mesmo caminho que em produção. A resposta `202` traz a transferência ainda\nreaberta; alguns segundos depois o Grip Rails a fecha como `completed`, sem custo (`charges` com um `fcm_fee` de `0` e o\nseu motivo), com o evento `transfer.outgoing.completed`, e alguns segundos mais tarde volta a habilitar as suas\ntransferências de saída (`GET /v1/entity` volta a `active`; não se o Grip Rails tiver bloqueado a sua entidade nesse\nmeio-tempo): essa reabilitação automática existe só no sandbox; em produção elas continuam desabilitadas até que o Grip\nRails as reabilite. Só no sandbox. Uma transferência que não está reaberta responde `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": "Duas pessoas do Grip Rails confirmam a liquidação tardia",
                  "value": {
                    "outcome": "completed"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Confirmada por duas pessoas sintéticas. Devolve a transferência ainda reaberta; o Grip Rails a fecha como `completed` em 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 o relógio de teste da entidade",
        "parameters": [
          {
            "$ref": "#/components/parameters/FcmVersion"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          }
        ],
        "responses": {
          "200": {
            "description": "O relógio.",
            "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": "Avançar o relógio de teste",
        "description": "Avança a hora da entidade no sandbox (nunca para trás). Afeta o dia e o mês dos limites, as novas tentativas de\nwebhooks pendentes e os vencimentos simulados. Todas as datas que o sandbox devolve para essa entidade usam este relógio.\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": "Avançar um dia",
                  "value": {
                    "advance_seconds": 86400
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Relógio avançado.",
            "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": "Entrou dinheiro numa conta da entidade",
        "description": "Foi lançado um crédito recebido. Peça `GET /v1/incoming_transfers/{data.id}` para o detalhe.",
        "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": "Recebido. Responda em no máximo 10 s e processe em 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": "Uma transferência de saída foi autorizada e reservada",
        "description": "A autorização aprovou a transferência, e o valor mais os encargos ficaram reservados no ledger.",
        "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": "Recebido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.completed": {
      "post": {
        "operationId": "webhookTransferOutgoingCompleted",
        "tags": [
          "Eventos"
        ],
        "summary": "Uma transferência de saída foi creditada",
        "description": "A COELSA confirmou o crédito no destino e a reserva foi lançada. É irreversível. Uma transferência reaberta por uma\nliquidação tardia chega aqui quando o Grip Rails a fecha, sem custo: o seu único débito é o lançamento compensatório\n(suas referências vão em `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": "Recebido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.failed": {
      "post": {
        "operationId": "webhookTransferOutgoingFailed",
        "tags": [
          "Eventos"
        ],
        "summary": "Uma transferência de saída falhou",
        "description": "A COELSA a rejeitou ou ela expirou, ou o Grip Rails a cancelou antes de enviá-la. A reserva foi liberada e não houve encargo. O motivo está em `failure` do objeto. Se a COELSA a creditar depois, chega `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": "Recebido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    },
    "transfer.outgoing.reopened": {
      "post": {
        "operationId": "webhookTransferOutgoingReopened",
        "tags": [
          "Eventos"
        ],
        "summary": "Uma transferência de saída que tinha falhado foi reaberta",
        "description": "A COELSA creditou uma transferência que já tínhamos informado a você como `failed` (liquidação tardia): o dinheiro\nsaiu. A transferência volta a `submitted` com `status_reason: late_settlement_review`, o valor foi debitado com um\nlançamento compensatório (suas referências vão em `data.ledger_references`) e o Grip Rails a fecha como `completed`\n(evento `transfer.outgoing.completed`) quando duas pessoas confirmam a liquidação. Peça\n`GET /v1/outgoing_transfers/{data.id}` para o 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": "Recebido."
          },
          "default": {
            "description": "Reintento según la política."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "fcm_live_… o fcm_test_…",
        "description": "API key da entidade em `Authorization: Bearer`. Identifica a entidade e o ambiente. O Grip Rails a guarda com hash, e\nela é rotacionada sem interrupção (até duas ativas). Sozinha não basta: toda requisição também vai assinada\n(`requestSignature`).\n"
      },
      "requestSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "Signature",
        "description": "Assinatura da requisição segundo a RFC 9421 (HTTP Message Signatures) com a chave privada do cliente (`ed25519` ou\n`ecdsa-p256-sha256`). Vai com `Signature-Input` e, se houver corpo, com `Content-Digest`. Componentes e parâmetros\nobrigatórios na descrição geral (\"Autenticação\"). O Grip Rails só conhece a chave pública: um vazamento do banco de\ndados do Grip Rails não permite falsificar instruções do cliente.\n"
      }
    },
    "parameters": {
      "FcmVersion": {
        "name": "FCM-Version",
        "in": "header",
        "required": false,
        "description": "Versão por data do contrato. Se faltar, usa-se a versão fixada da entidade.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "examples": [
            "2026-10-15"
          ]
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Chave única por intenção do cliente. Obrigatória em todo POST. Veja \"Idempotência\".",
        "schema": {
          "$ref": "#/components/schemas/IdempotencyKeyValue"
        }
      },
      "SignatureInput": {
        "name": "Signature-Input",
        "in": "header",
        "required": true,
        "description": "Parâmetros da assinatura RFC 9421 (componentes cobertos, `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 dos bytes exatos do corpo, segundo a 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": "Quantidade 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` da página anterior).",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      },
      "CreatedAfter": {
        "name": "created_after",
        "in": "query",
        "required": false,
        "description": "Só objetos criados neste instante ou depois (RFC 3339).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "CreatedBefore": {
        "name": "created_before",
        "in": "query",
        "required": false,
        "description": "Só objetos criados antes deste instante (RFC 3339).",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "AccountIdQuery": {
        "name": "account_id",
        "in": "query",
        "required": false,
        "description": "Filtra por conta.",
        "schema": {
          "$ref": "#/components/schemas/AccountId"
        }
      },
      "AccountIdPath": {
        "name": "account_id",
        "in": "path",
        "required": true,
        "description": "Id da conta.",
        "schema": {
          "$ref": "#/components/schemas/AccountId"
        }
      },
      "AccountNumberIdPath": {
        "name": "account_number_id",
        "in": "path",
        "required": true,
        "description": "Id do número de conta.",
        "schema": {
          "$ref": "#/components/schemas/AccountNumberId"
        }
      },
      "OutgoingTransferIdPath": {
        "name": "outgoing_transfer_id",
        "in": "path",
        "required": true,
        "description": "Id da transferência de saída.",
        "schema": {
          "$ref": "#/components/schemas/OutgoingTransferId"
        }
      },
      "IncomingTransferIdPath": {
        "name": "incoming_transfer_id",
        "in": "path",
        "required": true,
        "description": "Id do crédito recebido.",
        "schema": {
          "$ref": "#/components/schemas/IncomingTransferId"
        }
      },
      "EventIdPath": {
        "name": "event_id",
        "in": "path",
        "required": true,
        "description": "Id do evento.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "WebhookSignature": {
        "name": "FCM-Signature",
        "in": "header",
        "required": true,
        "description": "JWS compacto (JWT) assinado pelo Grip Rails. Veja \"Eventos e webhooks\" para os claims e os passos de verificação.",
        "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 do evento (igual ao `id` do corpo). Chave para deduplicar.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "WebhookEventType": {
        "name": "FCM-Event-Type",
        "in": "header",
        "required": true,
        "description": "Tipo do evento (igual ao `type` do corpo).",
        "schema": {
          "$ref": "#/components/schemas/EventType"
        }
      },
      "WebhookDeliveryId": {
        "name": "FCM-Delivery-Id",
        "in": "header",
        "required": true,
        "description": "Id desta tentativa de entrega (igual ao 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 da tentativa (1 a 25).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 25
        }
      }
    },
    "headers": {
      "FcmRequestId": {
        "description": "Id da requisição no Grip Rails. Cite-o em qualquer consulta ao suporte.",
        "schema": {
          "$ref": "#/components/schemas/RequestId"
        }
      },
      "FcmVersionUsed": {
        "description": "Versão do contrato com que se respondeu.",
        "schema": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
        }
      },
      "IdempotentReplayed": {
        "description": "`true` se é a resposta guardada para essa Idempotency-Key.",
        "schema": {
          "type": "boolean"
        }
      },
      "RetryAfter": {
        "description": "Segundos a esperar antes de tentar de novo.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Requisição mal formada ou parâmetro inválido. Nada foi criado.",
        "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 a API key ou a assinatura, ou elas não são 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": "A credencial é válida, mas não pode fazer isto (IP, ambiente ou entidade suspensa).",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Não existe, ou é de outra entidade (o Grip Rails não distingue os dois casos).",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflito de idempotência.",
        "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": "A autorização rejeitou a transferência. Ela ficou guardada em `rejected` e não saiu dinheiro.",
        "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": "Você ultrapassou o limite de requisições 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": "Erro do Grip Rails. Repita com a mesma Idempotency-Key.",
        "headers": {
          "FCM-Request-Id": {
            "$ref": "#/components/headers/FcmRequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "A COELSA, o ledger ou as transferências não estão disponíveis no momento. Repita com a mesma 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 da entidade e da Idempotency-Key, para que uma nova tentativa chegue ao mesmo objeto.",
        "pattern": "^otr_[0-9A-HJKMNP-TV-Z]{26}$",
        "examples": [
          "otr_01JA2B3C4D5E6F7G8H9JKMNPQV"
        ]
      },
      "IncomingTransferId": {
        "type": "string",
        "description": "Determinístico a partir do id da COELSA do 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": "Valor em centavos de peso argentino. `150000` = ARS 1.500,00.",
        "examples": [
          150000
        ]
      },
      "AmountOrZero": {
        "type": "integer",
        "format": "int64",
        "minimum": 0,
        "maximum": 9007199254740991,
        "description": "Valor em centavos de peso argentino; pode ser zero."
      },
      "Currency": {
        "type": "string",
        "enum": [
          "ARS"
        ],
        "description": "Única moeda da API."
      },
      "Cuit": {
        "type": "string",
        "pattern": "^\\d{11}$",
        "description": "CUIT ou CUIL (identificação fiscal ou trabalhista argentina), 11 dígitos sem hífens.",
        "examples": [
          "27000000006"
        ]
      },
      "BankKey": {
        "type": "string",
        "pattern": "^\\d{22}$",
        "description": "CBU ou CVU (número de conta bancária ou virtual argentino) de 22 dígitos com dígitos verificadores válidos.",
        "examples": [
          "0110599520000001234569"
        ]
      },
      "Alias": {
        "type": "string",
        "pattern": "^[A-Za-z0-9.-]{6,20}$",
        "description": "Alias do sistema da COELSA (o nome legível de um CBU ou CVU).",
        "examples": [
          "proveedor.ejemplo"
        ]
      },
      "LedgerReference": {
        "type": "string",
        "pattern": "^[0-9a-f]{32}$",
        "description": "Referência opaca e estável a um lançamento do ledger (id de 128 bits, em hexadecimal). Deriva de identificadores estáveis (id da COELSA, entidade e Idempotency-Key), por isso não muda\nse o ledger for reconstruído.\n",
        "examples": [
          "7f3a9c2e4b1d8f6a0c5e3b9d7a1f4c2e"
        ]
      },
      "ExternalReference": {
        "type": "string",
        "pattern": "^[A-Za-z0-9._:-]{1,64}$",
        "description": "Referência do cliente para conciliar. Não precisa ser única e não viaja para a COELSA.",
        "examples": [
          "pedido-7781"
        ]
      },
      "Metadata": {
        "type": "object",
        "description": "Até 20 pares chave-valor do cliente. Não coloque dados pessoais.",
        "maxProperties": 20,
        "propertyNames": {
          "pattern": "^[a-z0-9_]{1,40}$"
        },
        "additionalProperties": {
          "type": "string",
          "maxLength": 500
        }
      },
      "Concept": {
        "type": "string",
        "description": "Conceito BCRA da transferência (código de finalidade), que viaja para a COELSA. Lista inicial; pode crescer de forma aditiva.\nVAR diversos, ALQ aluguéis, CUO parcelas, EXP despesas de condomínio, FAC faturas, HAB salários, HON honorários,\nPRE empréstimos, SEG seguros.\n",
        "enum": [
          "VAR",
          "ALQ",
          "CUO",
          "EXP",
          "FAC",
          "HAB",
          "HON",
          "PRE",
          "SEG"
        ],
        "default": "VAR"
      },
      "EntityStatus": {
        "type": "string",
        "description": "`suspended`: pode ler, mas não ordenar transferências.",
        "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 com o qual a entidade é titular dos seus CVU perante a COELSA.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "$ref": "#/components/schemas/EntityStatus"
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "api_version": {
            "type": "string",
            "description": "Versão do contrato fixada para a entidade.",
            "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": "Limites de transferências de saída da entidade, fixados por contrato (o Grip Rails os aprova; não são alterados pela\nAPI). Contam o valor, sem encargos, das transferências `reserved`, `submitted` e `completed`. `null` = sem limite.\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": "Dia de Buenos Aires ao qual corresponde o uso diário."
          },
          "daily_used_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "daily_remaining_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0,
            "description": "`null` se não há limite diário."
          },
          "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` se não há limite mensal."
          }
        }
      },
      "FeeRule": {
        "type": "object",
        "required": [
          "fixed_amount",
          "rate_bps"
        ],
        "properties": {
          "fixed_amount": {
            "$ref": "#/components/schemas/AmountOrZero"
          },
          "rate_bps": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10000,
            "description": "Porcentagem em pontos-base sobre o valor (100 = 1%). A tarifa é fixa + porcentagem, arredondada para baixo ao centavo."
          }
        }
      },
      "FeeSchedule": {
        "type": "object",
        "description": "Tarifa por movimentação, conforme o contrato. É cobrada como lançamento separado no ledger: numa saída, é reservada com a\ntransferência e liberada se ela falhar; numa entrada, é descontada ao lançar e nunca supera o valor recebido.\n",
        "required": [
          "outgoing",
          "incoming"
        ],
        "properties": {
          "outgoing": {
            "$ref": "#/components/schemas/FeeRule"
          },
          "incoming": {
            "$ref": "#/components/schemas/FeeRule"
          }
        }
      },
      "AccountType": {
        "type": "string",
        "description": "`funds`: conta de fundos, a que opera. `guarantee`: conta de garantia (reserva) que o cliente deposita conforme o\ncontrato para cobrir faltas; é visível, mas não é debitada pela API.\n",
        "enum": [
          "funds",
          "guarantee"
        ]
      },
      "AccountStatus": {
        "type": "string",
        "description": "`frozen`: não pode ordenar saídas; as entradas são lançadas.",
        "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 aparece como origem perante a COELSA se a transferência não indicar outro.",
            "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`: cadastro na COELSA em andamento. `inactive`: descadastrado ou inativo na 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 na COELSA. Na fase 1 é sempre a entidade.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Holder"
              }
            ]
          },
          "is_primary": {
            "type": "boolean"
          },
          "external_reference": {
            "description": "Etiqueta que o cliente pediu para este CVU (por exemplo, o id do seu usuário ou comerciante). Sem dados pessoais.",
            "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 uma transferência ou de uma validação.",
        "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 e conta do destino segundo a COELSA, tal como foram verificados ao 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 da instituição financeira do CBU, se a COELSA o informar."
          },
          "alias": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Alias"
              },
              {
                "type": "null"
              }
            ]
          },
          "is_fcm_account": {
            "type": "boolean",
            "description": "`true` se o destino é uma conta do Grip Rails (a transferência é interna)."
          }
        }
      },
      "CounterpartyValidationRequest": {
        "type": "object",
        "required": [
          "destination"
        ],
        "additionalProperties": false,
        "properties": {
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "expected_cuit": {
            "description": "Se vier, o resultado é `holder_mismatch` quando a COELSA informa outro CUIT.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              }
            ]
          }
        }
      },
      "CounterpartyValidationResult": {
        "type": "string",
        "description": "`valid`: titular encontrado, conta ativa e controles em ordem. `not_found`: a COELSA não conhece a conta nem o alias.\n`inactive`: a conta existe, mas não está ativa. `holder_mismatch`: o CUIT não é o esperado. `blocked`: o Grip Rails não\npode operar com essa conta (controle de compliance; sem detalhe).\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 em espanhol para mostrar ao usuário final quando o resultado não é `valid`."
          },
          "counterparty": {
            "description": "Presente se a COELSA informou um titular (`valid`, `inactive` e `holder_mismatch`).",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Counterparty"
              },
              {
                "type": "null"
              }
            ]
          },
          "validated_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Até quando pode ser usada numa transferência (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 da conta que aparece como origem perante a COELSA. Por padrão, o principal da conta.",
            "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 sempre. Se a COELSA informar outro CUIT para o titular, é rejeitada com `destination_holder_mismatch`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Cuit"
              }
            ]
          },
          "counterparty_validation_id": {
            "description": "Validação `valid` vigente (15 minutos) do mesmo destino. Se vencer ou não coincidir, `400 parameter_invalid`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CounterpartyValidationId"
              }
            ]
          },
          "concept": {
            "$ref": "#/components/schemas/Concept"
          },
          "description": {
            "type": "string",
            "maxLength": 140,
            "description": "Texto do cliente. Fica no Grip Rails; na fase 1 não viaja para a COELSA."
          },
          "external_reference": {
            "$ref": "#/components/schemas/ExternalReference"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        }
      },
      "OutgoingTransferStatus": {
        "type": "string",
        "description": "Veja a tabela de estados na descrição geral.",
        "enum": [
          "pending",
          "rejected",
          "reserved",
          "submitted",
          "completed",
          "failed"
        ]
      },
      "OutgoingTransferStatusReason": {
        "type": "string",
        "description": "Só em `submitted`. `awaiting_rail_result`: esperando o aviso da COELSA (normal, segundos).\n`rail_outcome_unknown`: o resultado não chegou no prazo esperado; o Grip Rails está resolvendo com a COELSA e o dinheiro\ncontinua reservado. Não repita com outra Idempotency-Key: você poderia pagar duas vezes.\n`late_settlement_review`: a COELSA creditou a transferência depois de a informarmos a você como `failed` (liquidação\ntardia). O dinheiro saiu e o valor foi debitado com um lançamento compensatório; o Grip Rails a fecha como `completed`\nquando duas pessoas confirmam a liquidação.\n",
        "enum": [
          "awaiting_rail_result",
          "rail_outcome_unknown",
          "late_settlement_review"
        ]
      },
      "ChargeType": {
        "type": "string",
        "enum": [
          "fee",
          "tax"
        ]
      },
      "ChargeCode": {
        "type": "string",
        "description": "`fcm_fee`: tarifa do Grip Rails. `idcb`: imposto sobre débitos e créditos bancários retido pela FCM Payment Solutions S.A.S. como agente de retenção, quando aplicável.",
        "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 quando `status` é `RJCT` (por exemplo AM04, AC03, AC04, AB05, RR04)."
          }
        }
      },
      "AuthorizationCheckName": {
        "type": "string",
        "description": "`account`: entidade e conta habilitadas. `limits`: limites. `funds`: reserva no ledger. `counterparty`: titular do\ndestino na COELSA. `compliance`: listas de sanções e antifraude (informados juntos, sem detalhe).\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`, ou o código de erro da rejeição (por exemplo `insufficient_funds`).",
            "examples": [
              "approved"
            ]
          },
          "message": {
            "type": "string",
            "maxLength": 300
          }
        }
      },
      "Authorization": {
        "type": "object",
        "description": "Decisão da autorização prévia, com o seu motivo. A FCM Payment Solutions S.A.S. também guarda o detalhe completo de cada controle.",
        "required": [
          "decision",
          "decided_at",
          "rationale",
          "checks"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "description": "`approved`, `declined` ou `pending` (a autorização ainda não terminou; `decided_at` é a hora em que ficou pendente).",
            "enum": [
              "approved",
              "declined",
              "pending"
            ]
          },
          "decided_at": {
            "type": "string",
            "format": "date-time"
          },
          "rationale": {
            "$ref": "#/components/schemas/Rationale"
          },
          "checks": {
            "type": "array",
            "description": "Um resultado por controle. `not_run` se não chegou a rodar porque um anterior falhou.",
            "items": {
              "$ref": "#/components/schemas/AuthorizationCheck"
            }
          }
        }
      },
      "Reservation": {
        "type": "object",
        "description": "Reserva no ledger (transferências pendentes) pelo valor mais os encargos.",
        "required": [
          "amount",
          "state",
          "placed_at",
          "resolved_at",
          "ledger_references"
        ],
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "state": {
            "type": "string",
            "description": "`held`: reservada. `posted`: lançada (o dinheiro saiu). `voided`: liberada. Uma transferência reaberta por uma\nliquidação tardia continua `voided` (a reserva foi liberada ao falhar e o valor foi debitado com um lançamento\ncompensatório); quando o Grip Rails a fecha como `completed`, sem custo, ela fica `posted` pelo valor, com as\nreferências do lançamento compensatório.\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`: transferência pela COELSA. `fcm_book`: interna entre contas do Grip Rails.",
            "enum": [
              "coelsa",
              "fcm_book"
            ]
          },
          "operation_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id da operação na COELSA.",
            "maxLength": 64
          },
          "origin_reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "`ori_trx_id` com que o Grip Rails enviou a operação. Não muda entre novas tentativas.",
            "pattern": "^\\d{1,16}$"
          },
          "status_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Último código de estado da COELSA (por exemplo 7541 persistido, 7500 creditado).",
            "maxLength": 8
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finalized_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "FailureCode": {
        "type": "string",
        "description": "`rail_rejected`: a COELSA a rejeitou (detalhe em `rail.status_code` e `iso20022.reason`). `rail_expired`: expirou na\nCOELSA. `destination_closed`: a conta de destino não existe ou está encerrada no momento de creditar.\n`canceled_by_fcm`: o Grip Rails a cancelou antes de enviá-la (corte de emergência, controle posterior à reserva ou uma transferência `pending` que não pôde ser autorizada).\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 aparece como origem perante a COELSA. `null` se foi rejeitada antes de escolhê-lo.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AccountNumberId"
              },
              {
                "type": "null"
              }
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "charges": {
            "type": "array",
            "description": "Encargos desta transferência. Cada um com valor é um lançamento separado no ledger. Uma transferência reaberta por uma liquidação tardia e completada vai sem custo e informa isso com um `fcm_fee` de `0` e o seu motivo.",
            "items": {
              "$ref": "#/components/schemas/Charge"
            }
          },
          "total_debit_amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "destination": {
            "$ref": "#/components/schemas/Destination"
          },
          "counterparty": {
            "description": "Titular verificado. `null` se foi rejeitada antes de consultar o 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` se foi rejeitada antes de reservar.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Reservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "rail": {
            "description": "`null` até ser enviada.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Rail"
              },
              {
                "type": "null"
              }
            ]
          },
          "failure": {
            "description": "Presente só em `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 em que ficou `failed`. Volta a `null` se for reaberta por uma liquidação tardia."
          }
        }
      },
      "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": "Quem pagou, segundo o aviso da COELSA. Qualquer dado pode faltar se a COELSA não o informar.",
        "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": "Conceito BCRA informado pela COELSA, se vier."
          },
          "status": {
            "type": "string",
            "description": "Na fase 1, sempre `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 da COELSA do crédito, ou o `otr_…` de origem se `name` é `fcm_book` (interna entre contas do Grip Rails). É a chave de idempotência do lançamento."
              },
              "business_date": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date",
                "description": "Data de negócio (compensação) informada pela 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 da fase 1. Podem aparecer tipos novos sem aviso de versão; ignore os que você não conhece.\n`transfer.outgoing.reopened`: uma transferência `failed` que a COELSA creditou depois voltou 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": "Referência enxuta ao objeto. Para o estado vigente, peça o 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": "Lançamentos do ledger que produziram o 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": "Contíguo e crescente por entidade, atribuído na ordem em que a mudança foi confirmada."
          },
          "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 o próximo `after_sequence` (a `sequence` do último evento devolvido)."
          }
        }
      },
      "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 do método, do caminho e do corpo canonizado (RFC 8785)."
          },
          "response_status": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 200,
            "maximum": 499
          },
          "resource": {
            "description": "Objeto criado ou afetado, se houver.",
            "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": "Veja a tabela de códigos na descrição geral.",
        "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": "Explicação técnica para quem integra. Não mostrar a usuários finais."
          },
          "display_message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Texto em espanhol adequado para mostrar a um usuário final, ou `null`."
          },
          "param": {
            "type": [
              "string",
              "null"
            ],
            "description": "Campo ou cabeçalho que causou o erro, se aplicável."
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          },
          "retryable": {
            "type": "boolean",
            "description": "`true`: repita a mesma requisição com a mesma Idempotency-Key."
          },
          "doc_url": {
            "type": "string",
            "format": "uri"
          },
          "transfer_id": {
            "description": "Num `422` de transferência, o id do objeto que ficou em `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": "Dados do pagador simulado. Se faltarem, usa-se um 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 da COELSA a simular. Por padrão, 7500 se `completed` e 7699 se `failed`."
          }
        }
      },
      "SimulateLateSettlementReviewRequest": {
        "type": "object",
        "required": [
          "outcome"
        ],
        "additionalProperties": false,
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "completed"
            ],
            "description": "A única saída da revisão de uma liquidação tardia: duas pessoas do Grip Rails confirmam que o dinheiro saiu e a transferência é fechada como `completed`, sem custo."
          }
        }
      },
      "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 da entidade no sandbox."
          },
          "offset_seconds": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Quanto está adiantada em relação à hora real."
          }
        }
      },
      "AdvanceClockRequest": {
        "type": "object",
        "required": [
          "advance_seconds"
        ],
        "additionalProperties": false,
        "properties": {
          "advance_seconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2678400,
            "description": "Segundos a avançar (até 31 dias por requisição)."
          }
        }
      }
    }
  }
}
