Estado de Cuenta

Estado de cuenta estilo bancario

Estado de Cuenta

El Estado de Cuenta proporciona un extracto estilo bancario que muestra todos los movimientos que afectaron el saldo de tu cuenta virtual durante un período especificado.

¿Qué es un Estado de Cuenta?

Piénsalo como un extracto bancario para tu cuenta virtual:

  • Saldo Inicial: Tu saldo al inicio del período
  • Movimientos: Cada débito y crédito que ocurrió
  • Saldo Actualizado: Saldo después de cada movimiento
  • Saldo Final: Tu saldo al final del período

Conceptos Clave

Tipos de Movimiento

TipoDescripciónEfecto en Saldo
creditFondos agregados a la cuentaAumenta saldo
debitFondos removidos de la cuentaDisminuye saldo

Categorías de Movimiento

CategoríaDescripción
PAYINPago de cliente recibido
PAYOUTPago a proveedor enviado
BALANCE_TRANSFERCambio de divisa entre cuentas
SETTLEMENTRetiro automático a banco
ADJUSTMENTCorrección manual de saldo
FEEComisión por servicio
TAXRetención de impuesto
ONRAMPFiat usado para comprar crypto
OFFRAMPCrypto vendido por fiat
REVERSEReversión de transacción
OTHEROtros tipos de movimiento

Endpoint de API

GET /api/v1/organizations/{organizationId}/merchants/{merchantId}/accounts/{accountId}/reports/ledger-statement

Parámetros de Ruta

ParámetroRequeridoDescripción
organizationIdID de organización
merchantIdID de comercio
accountIdID de cuenta virtual

Parámetros de Query

ParámetroRequeridoDefaultDescripción
from-Fecha inicio (YYYY-MM-DD)
to-Fecha fin (YYYY-MM-DD)
granularityNodailyCorte de fecha: daily o monthly
cursorNo-Cursor de paginación de respuesta anterior
limitNo50Items por página (1-100)

Ejemplo Rápido

1const response = await axios.get(
2 `https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-statement`,
3 {
4 params: {
5 from: '2025-01-01',
6 to: '2025-01-31'
7 },
8 headers: { 'Authorization': `Bearer ${token}` }
9 }
10);
11
12console.log('Saldo Inicial:', response.data.openingBalance);
13console.log('Saldo Final:', response.data.closingBalance);
14console.log('Movimientos:', response.data.movements.length);

Entendiendo la Respuesta

1{
2 "accountId": "acc_0031c537-2301-40ab-9153-0f7c48505350",
3 "currency": "CLP",
4 "merchantId": "mrc_2e8f96ab-dbd5-45f9-b4b6-645945daf340",
5 "periodStart": "2025-01-01T00:00:00.000Z",
6 "periodEnd": "2025-01-31T23:59:59.999Z",
7 "openingBalance": "4000000.00",
8 "closingBalance": "5500000.00",
9 "movements": [
10 {
11 "ledgerEntryId": "137",
12 "postedAt": "2025-01-15T10:30:00.000Z",
13 "type": "credit",
14 "amount": "1000000.00",
15 "currency": "CLP",
16 "runningBalance": "5000000.00",
17 "description": "PAYIN de Juan Pérez - Transferencia bancaria recibida",
18 "orderId": "ord_abc123",
19 "category": "PAYIN"
20 },
21 {
22 "ledgerEntryId": "142",
23 "postedAt": "2025-01-20T14:15:00.000Z",
24 "type": "debit",
25 "amount": "500000.00",
26 "currency": "CLP",
27 "runningBalance": "4500000.00",
28 "description": "PAYOUT a Proveedor SA - Pago de factura",
29 "orderId": "ord_def456",
30 "category": "PAYOUT"
31 }
32 ],
33 "pagination": {
34 "cursor": "eyJpZCI6IjE0MiIsImRhdGUiOiIyMDI1LTAxLTIwVDE0OjE1OjAwLjAwMFoifQ==",
35 "hasMore": true,
36 "limit": 50
37 },
38 "generatedAt": "2025-01-31T12:00:00.000Z"
39}

Campos de Respuesta

CampoDescripción
openingBalanceSaldo al inicio del período
closingBalanceSaldo al final del período
movements[]Array de movimientos individuales
movements[].ledgerEntryIdID único (usar para recibo detallado)
movements[].runningBalanceSaldo después de este movimiento
movements[].typecredit o debit
movements[].categoryCategoría de movimiento (PAYIN, PAYOUT, etc.)
pagination.cursorUsar para siguiente página
pagination.hasMoreSi existen más páginas

Paginación

El estado de cuenta usa paginación basada en cursor. Para obtener todos los movimientos:

1async function obtenerTodosLosMovimientos(orgId, merchantId, accountId, from, to, token) {
2 const todosLosMovimientos = [];
3 let cursor = null;
4
5 do {
6 const response = await axios.get(
7 `https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-statement`,
8 {
9 params: {
10 from,
11 to,
12 limit: 100,
13 ...(cursor && { cursor })
14 },
15 headers: { 'Authorization': `Bearer ${token}` }
16 }
17 );
18
19 const data = response.data;
20 todosLosMovimientos.push(...data.movements);
21
22 cursor = data.pagination.hasMore ? data.pagination.cursor : null;
23
24 console.log(`Obtenidos ${data.movements.length} movimientos, total: ${todosLosMovimientos.length}`);
25
26 } while (cursor);
27
28 return todosLosMovimientos;
29}
30
31// Uso
32const movimientos = await obtenerTodosLosMovimientos(orgId, merchantId, accountId, '2025-01-01', '2025-01-31', token);
33console.log('Total movimientos:', movimientos.length);

Opciones de Granularidad

El parámetro granularity controla cómo se aplican los límites de fecha:

GranularidadInicio del PeríodoFin del Período
dailyInicio del día (00:00:00)Fin del día (23:59:59)
monthlyPrimer día del mesÚltimo día del mes

Usa granularidad monthly para reportes de conciliación de fin de mes para asegurar límites de período consistentes.


Ejemplo de Integración Completa

Node.js
1async function generarEstadoMensual(orgId, merchantId, accountId, year, month, token) {
2 // Calcular rango de fechas del mes
3 const from = `${year}-${String(month).padStart(2, '0')}-01`;
4 const lastDay = new Date(year, month, 0).getDate();
5 const to = `${year}-${String(month).padStart(2, '0')}-${lastDay}`;
6
7 console.log(`Generando estado de cuenta para ${from} a ${to}`);
8
9 // Obtener primera página
10 const response = await axios.get(
11 `https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-statement`,
12 {
13 params: {
14 from,
15 to,
16 granularity: 'monthly',
17 limit: 100
18 },
19 headers: { 'Authorization': `Bearer ${token}` }
20 }
21 );
22
23 const statement = response.data;
24
25 // Resumen
26 console.log('='.repeat(50));
27 console.log('ESTADO DE CUENTA MENSUAL');
28 console.log('='.repeat(50));
29 console.log(`Cuenta: ${statement.accountId}`);
30 console.log(`Moneda: ${statement.currency}`);
31 console.log(`Período: ${statement.periodStart} a ${statement.periodEnd}`);
32 console.log('-'.repeat(50));
33 console.log(`Saldo Inicial: ${statement.openingBalance}`);
34 console.log(`Saldo Final: ${statement.closingBalance}`);
35 console.log('-'.repeat(50));
36
37 // Calcular totales
38 let totalCreditos = 0;
39 let totalDebitos = 0;
40
41 statement.movements.forEach(m => {
42 const amount = parseFloat(m.amount);
43 if (m.type === 'credit') {
44 totalCreditos += amount;
45 } else {
46 totalDebitos += amount;
47 }
48
49 console.log(`${m.postedAt} | ${m.type.toUpperCase().padEnd(6)} | ${m.amount.padStart(15)} | ${m.category} | ${m.description.substring(0, 30)}`);
50 });
51
52 console.log('-'.repeat(50));
53 console.log(`Total Créditos: ${totalCreditos.toFixed(2)}`);
54 console.log(`Total Débitos: ${totalDebitos.toFixed(2)}`);
55 console.log(`Cambio Neto: ${(totalCreditos - totalDebitos).toFixed(2)}`);
56 console.log('='.repeat(50));
57
58 return statement;
59}
60
61// Uso: Generar estado de enero 2025
62const statement = await generarEstadoMensual(
63 'org3_xxx',
64 'mrc_xxx',
65 'acc_xxx',
66 2025,
67 1,
68 token
69);

Próximos Pasos