> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gallo-pay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Saldo actual por CVU



## OpenAPI

````yaml /openapi.json get /wallet/v1/SaldoActualByCVU/{cvu}
openapi: 3.0.0
info:
  title: Gallo Pay API
  description: >

    Gallo Pay es un **PSP-as-a-Service**: usás nuestras APIs para crear CVUs,
    mover

    pesos (cash-in / cash-out) sobre los rieles de **Coinag / Coelsa** y recibís

    **webhooks firmados** para cada evento de tu operación.


    Esta documentación es la **superficie de integración del PSP**. Podés probar

    endpoints con **Authorize** (tu `x-api-key`) y **Try it out**. No incluye

    APIs internas de plataforma, compliance ni operación del banco.


    Hay dos familias de paths:


    | Familia | Para qué |

    | ------- | -------- |

    | `/v1/...` | API nativa Gallo (cuentas/CVU, transfers, comprobantes) |

    | `/wallet/v1/...` | API wallet (Cuentas, CVU, saldos, comprobantes,
    conciliaciones) |


    Cada cliente (PSP) opera de forma aislada con su propia **API key**. Todos
    los

    recursos (cuentas, transferencias, movimientos, webhooks) quedan
    automáticamente

    acotados a tu tenant — no necesitás enviar ningún identificador de tenant.


    ---


    ## Autenticación


    Todas las llamadas requieren tu API key en el header:


    ```

    x-api-key: gpk_live_xxxxxxxxxxxxxxxxxxxxxxxx

    ```


    - La key es **secreta**: guardala en tu backend, nunca en el frontend.

    - Si sospechás que se filtró, pedí una rotación y la anterior se revoca.

    - Recibirás una key de **sandbox** (`gpk_test_...`) y otra de **producción**
      (`gpk_live_...`).

    ## Entornos


    | Entorno    | Base URL                                   |

    | ---------- | ------------------------------------------ |

    | Sandbox    | `https://sandbox.api.gallo-pay.com`       |

    | Producción | `https://api.gallo-pay.com`               |


    ## Idempotencia


    Las operaciones de escritura (`POST /v1/accounts`, `POST /v1/transfers`)
    exigen

    el header:


    ```

    Idempotency-Key: <uuid-v4 único por operación>

    ```


    Si reintentás con la **misma** `Idempotency-Key`, devolvemos la respuesta

    original (mismo status y body) sin volver a ejecutar la operación. Usá una
    key

    nueva por cada operación distinta y reutilizá la misma ante
    timeouts/reintentos.


    ## Formato de errores


    Todos los errores devuelven este shape:


    ```json

    {
      "statusCode": 400,
      "message": "Idempotency-Key header is required",
      "timestamp": "2026-07-30T12:00:00.000Z"
    }

    ```


    - `message` puede ser un string o un array de strings (errores de
    validación).

    - Cuando el rechazo proviene del banco, incluímos `bankStatus` y `bankBody`.


    | Código | Significado                                             |

    | ------ | ------------------------------------------------------- |

    | 400    | Request inválido / falta header / validación de campos |

    | 401    | API key ausente o inválida                             |

    | 403    | El recurso pertenece a otro tenant                     |

    | 404    | Recurso inexistente                                    |

    | 409    | Conflicto (p. ej. alias ya tomado)                     |

    | 422    | Rechazo de negocio (saldo insuficiente, etc.)          |


    ## Paginación


    Los listados aceptan `limit` (máx. 100, default 50) y `offset`, y devuelven:


    ```json

    { "items": [ ... ], "total": 137, "limit": 50, "offset": 0 }

    ```


    ---


    ## Webhooks


    Configuramos junto a vos una URL HTTPS a la que hacemos `POST` por cada
    evento.

    Cada request incluye estos headers:


    | Header              |
    Descripción                                             |

    | ------------------- |
    ------------------------------------------------------- |

    | `X-Gallo-Signature` | HMAC-SHA256 en hex de
    `${timestamp}.${body}`           |

    | `X-Gallo-Timestamp` | Unix time en **segundos** usado para
    firmar             |

    | `X-Gallo-Event-Id`  | ID único del evento (idempotencia del lado
    receptor)    |

    | `X-Gallo-Event-Type`| Tipo de evento (ver tabla más
    abajo)                    |


    El **body** siempre tiene esta forma:


    ```json

    {
      "eventId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
      "type": "transfer.confirmed",
      "version": "1",
      "occurredAt": "2026-07-30T12:00:00.000Z",
      "tenantId": "3f6d9c1e-8b2a-4a1f-9c3e-6b7a1d2e5f40",
      "data": { }
    }

    ```


    ### Verificar la firma (Node.js)


    ```js

    const crypto = require('crypto');


    function verify(req, secret) {
      const ts = req.headers['x-gallo-timestamp'];
      const sig = req.headers['x-gallo-signature'];
      const body = req.rawBody; // el body crudo, sin re-serializar
      const expected = crypto
        .createHmac('sha256', secret)      // secret = whsec_...
        .update(`${ts}.${body}`)
        .digest('hex');
      return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
    }

    ```


    - Firmá/verificá sobre el **body crudo** (no lo vuelvas a serializar).

    - Rechazá timestamps con demasiada antigüedad (p. ej. > 5 min) para evitar
    replay.

    - Respondé **2xx** rápido. Si respondés error o hay timeout, reintentamos
    con
      backoff exponencial hasta agotar los intentos.

    ### Tipos de evento


    | `type`                    | Cuándo se
    emite                                    |

    | ------------------------- |
    -------------------------------------------------- |

    | `account.created`         | Se creó una
    CVU                                     |

    | `account.alias.updated`   | Se asignó/actualizó el
    alias                        |

    | `account.closed`          | Se dio de baja la
    CVU                               |

    | `account.credited`        | Cash-in acreditado en una
    CVU                       |

    | `transfer.created`        | Se registró una transferencia
    (pending)            |

    | `transfer.sent`           | Enviada a
    Coelsa                                    |

    | `transfer.confirmed`      | Confirmada /
    liquidada                              |

    | `transfer.failed`         | Rechazada /
    fallida                                 |

    | `transfer.reversed`       |
    Reversada                                           |
  version: '1.0'
  contact:
    name: Gallo Pay
    url: https://gallo-pay.com
    email: soporte@gallo-pay.com
servers:
  - url: https://api.dev.gallo-pay.com
    description: Homologación / dev
  - url: https://api.prod.gallo-pay.com
    description: Producción
  - url: https://api.dev.gallo-pay.com
    description: Sandbox / homologación
security: []
tags:
  - name: accounts
    description: CVUs, alias, saldos y movimientos (`/v1`)
  - name: transfers
    description: Transferencias de salida / P2P interno (`/v1`)
  - name: ledger-comprobantes
    description: Tipos y comprobantes de ledger nativos (`/v1`)
  - name: wallet-cuentas
    description: Cuentas wallet (`/wallet/v1`)
  - name: wallet-cvu
    description: CVU / alias wallet (`/wallet/v1`)
  - name: wallet-saldo
    description: Saldo en pesos y comprobantes (`/wallet/v1`)
  - name: wallet-conciliar
    description: Consultas y conciliaciones (`/wallet/v1`)
paths:
  /wallet/v1/SaldoActualByCVU/{cvu}:
    get:
      tags:
        - wallet-saldo
      summary: Saldo actual por CVU
      operationId: WalletSaldoController_saldoByCvu
      parameters:
        - name: cvu
          required: true
          in: path
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletSaldoResponse'
        '400':
          description: Request inválido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: API key ausente o inválida
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - api-key: []
components:
  schemas:
    WalletSaldoResponse:
      type: object
      properties:
        saldo:
          type: number
          description: Saldo disponible
        availableBalance:
          type: string
        heldBalance:
          type: string
        totalBalance:
          type: string
        cvu:
          type: string
        idCuenta:
          type: number
      required:
        - saldo
    ErrorResponse:
      type: object
      properties:
        statusCode:
          type: number
          example: 400
        message:
          type: object
          example: Idempotency-Key header is required
          description: Mensaje legible. Puede ser un string o un array de strings.
        timestamp:
          type: string
          example: '2026-07-30T12:00:00.000Z'
        bankStatus:
          type: number
          example: 400
          description: Código HTTP devuelto por el banco Coinag/Coelsa (si aplica).
        bankBody:
          type: object
          description: Cuerpo crudo devuelto por el banco (si aplica).
      required:
        - statusCode
        - message
        - timestamp
  securitySchemes:
    api-key:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Tu API key de PSP (`gpk_live_...` o `gpk_test_...`). Authorize arriba y
        usá Try it out.

````