Detalle de Movimiento
El endpoint de Detalle de Movimiento proporciona un recibo detallado para un movimiento específico del libro mayor, perfecto para documentación de auditoría, soporte al cliente y comprobantes contables.
¿Qué es un Recibo de Movimiento?
Cada movimiento en tu estado de cuenta tiene un ledgerEntryId único. Usa este ID para obtener información detallada sobre esa transacción específica, incluyendo:
- Saldo antes y después del movimiento
- Detalles del comercio y cuenta
- Referencias a órdenes o liquidaciones asociadas
- Descripción legible
Casos de Uso
Cuándo usar Detalle de Movimiento:
- Documentación de auditoría: Generar comprobantes de transacciones específicas
- Soporte al cliente: Recuperar rápidamente detalles de transacciones para consultas
- Comprobante contable: Proporcionar recibos detallados para contabilidad
- Resolución de disputas: Documentar detalles de transacciones para disputas
- Cumplimiento: Mantener registros detallados para requisitos regulatorios
Endpoint de API
GET /api/v1/organizations/{organizationId}/merchants/{merchantId}/accounts/{accountId}/reports/ledger-entry/{ledgerEntryId}Parámetros de Ruta
| Parámetro | Requerido | Descripción |
|---|---|---|
organizationId | Sí | ID de organización |
merchantId | Sí | ID de comercio |
accountId | Sí | ID de cuenta virtual |
ledgerEntryId | Sí | ID de entrada del libro mayor (del estado de cuenta) |
Ejemplo Rápido
const response = await axios.get(
`https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-entry/137`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
console.log('ID de Entrada:', response.data.ledgerEntryId);
console.log('Monto:', response.data.amount, response.data.currency);
console.log('Saldo Antes:', response.data.balanceBefore);
console.log('Saldo Después:', response.data.balanceAfter);
console.log('Descripción:', response.data.description);response = requests.get(
f'https://api.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/accounts/{account_id}/reports/ledger-entry/137',
headers={'Authorization': f'Bearer {token}'}
)
data = response.json()
print(f"ID de Entrada: {data['ledgerEntryId']}")
print(f"Monto: {data['amount']} {data['currency']}")
print(f"Saldo Antes: {data['balanceBefore']}")
print(f"Saldo Después: {data['balanceAfter']}")
print(f"Descripción: {data['description']}")curl -X GET 'https://api.koywe.com/api/v1/organizations/org3_xxx/merchants/mrc_xxx/accounts/acc_xxx/reports/ledger-entry/137' \
-H 'Authorization: Bearer TU_TOKEN'Entendiendo la Respuesta
{
"ledgerEntryId": "137",
"accountId": "acc_0031c537-2301-40ab-9153-0f7c48505350",
"merchantId": "mrc_2e8f96ab-dbd5-45f9-b4b6-645945daf340",
"merchantName": "Acme Corporation",
"type": "credit",
"amount": "1000000.00",
"currency": "CLP",
"postedAt": "2025-01-15T10:30:00.000Z",
"description": "PAYIN de Juan Pérez - Transferencia bancaria recibida",
"category": "PAYIN",
"references": {
"orderId": "ord_abc123",
"settlementId": null
},
"balanceBefore": "4000000.00",
"balanceAfter": "5000000.00",
"generatedAt": "2025-01-31T12:00:00.000Z"
}Explicación de Campos de Respuesta
| Campo | Descripción |
|---|---|
ledgerEntryId | Identificador único de esta entrada del libro mayor |
merchantId | ID del comercio asociado con la cuenta |
merchantName | Nombre del comercio legible |
type | credit (aumenta saldo) o debit (disminuye saldo) |
amount | Monto de la transacción |
currency | Símbolo de moneda |
postedAt | Marca de tiempo cuando se registró el movimiento |
description | Descripción legible |
category | Categoría de movimiento (PAYIN, PAYOUT, SETTLEMENT, etc.) |
references.orderId | ID de orden asociada (si aplica) |
references.settlementId | ID de liquidación asociada (si aplica) |
balanceBefore | Saldo de cuenta antes de este movimiento |
balanceAfter | Saldo de cuenta después de este movimiento |
Los campos balanceBefore y balanceAfter proporcionan prueba lista para auditoría de cómo la transacción afectó el saldo de la cuenta.
Flujo de Trabajo: Del Estado de Cuenta al Detalle
El flujo típico es primero obtener un estado de cuenta, luego obtener detalles de entradas específicas:
Ejemplo Completo: Del Estado al Detalle
async function obtenerReciboTransaccion(orgId, merchantId, accountId, date, token) {
// Paso 1: Obtener estado de cuenta para la fecha
const statementResponse = await axios.get(
`https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-statement`,
{
params: {
from: date,
to: date
},
headers: { 'Authorization': `Bearer ${token}` }
}
);
const movements = statementResponse.data.movements;
console.log(`Encontrados ${movements.length} movimientos en ${date}`);
// Paso 2: Obtener detalles de cada movimiento
const recibos = [];
for (const movement of movements) {
console.log(`\nObteniendo detalles para entrada ${movement.ledgerEntryId}...`);
const detailResponse = await axios.get(
`https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-entry/${movement.ledgerEntryId}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
const recibo = detailResponse.data;
recibos.push(recibo);
// Imprimir recibo
console.log('='.repeat(50));
console.log('RECIBO DE TRANSACCIÓN');
console.log('='.repeat(50));
console.log(`ID Entrada: ${recibo.ledgerEntryId}`);
console.log(`Fecha: ${recibo.postedAt}`);
console.log(`Comercio: ${recibo.merchantName}`);
console.log(`Tipo: ${recibo.type.toUpperCase()}`);
console.log(`Categoría: ${recibo.category}`);
console.log(`Monto: ${recibo.amount} ${recibo.currency}`);
console.log('-'.repeat(50));
console.log(`Saldo Antes: ${recibo.balanceBefore} ${recibo.currency}`);
console.log(`Saldo Después: ${recibo.balanceAfter} ${recibo.currency}`);
console.log('-'.repeat(50));
console.log(`Descripción: ${recibo.description}`);
if (recibo.references.orderId) {
console.log(`ID Orden: ${recibo.references.orderId}`);
}
if (recibo.references.settlementId) {
console.log(`ID Liquidación: ${recibo.references.settlementId}`);
}
console.log('='.repeat(50));
}
return recibos;
}
// Uso: Obtener todos los recibos del 15 de enero 2025
const recibos = await obtenerReciboTransaccion(
'org3_xxx',
'mrc_xxx',
'acc_xxx',
'2025-01-15',
token
);def obtener_recibo_transaccion(org_id, merchant_id, account_id, date, token):
# Paso 1: Obtener estado de cuenta para la fecha
statement_response = requests.get(
f'https://api.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/accounts/{account_id}/reports/ledger-statement',
params={'from': date, 'to': date},
headers={'Authorization': f'Bearer {token}'}
)
movements = statement_response.json()['movements']
print(f"Encontrados {len(movements)} movimientos en {date}")
# Paso 2: Obtener detalles de cada movimiento
recibos = []
for movement in movements:
print(f"\nObteniendo detalles para entrada {movement['ledgerEntryId']}...")
detail_response = requests.get(
f"https://api.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/accounts/{account_id}/reports/ledger-entry/{movement['ledgerEntryId']}",
headers={'Authorization': f'Bearer {token}'}
)
recibo = detail_response.json()
recibos.append(recibo)
# Imprimir recibo
print('=' * 50)
print('RECIBO DE TRANSACCIÓN')
print('=' * 50)
print(f"ID Entrada: {recibo['ledgerEntryId']}")
print(f"Fecha: {recibo['postedAt']}")
print(f"Comercio: {recibo['merchantName']}")
print(f"Tipo: {recibo['type'].upper()}")
print(f"Categoría: {recibo['category']}")
print(f"Monto: {recibo['amount']} {recibo['currency']}")
print('-' * 50)
print(f"Saldo Antes: {recibo['balanceBefore']} {recibo['currency']}")
print(f"Saldo Después: {recibo['balanceAfter']} {recibo['currency']}")
print('-' * 50)
print(f"Descripción: {recibo['description']}")
if recibo['references'].get('orderId'):
print(f"ID Orden: {recibo['references']['orderId']}")
if recibo['references'].get('settlementId'):
print(f"ID Liquidación: {recibo['references']['settlementId']}")
print('=' * 50)
return recibos
# Uso
recibos = obtener_recibo_transaccion(
'org3_xxx',
'mrc_xxx',
'acc_xxx',
'2025-01-15',
token
)Encontrar el ID de Entrada del Libro Mayor
El ledgerEntryId está disponible en la respuesta del estado de cuenta. Así es cómo encontrar una entrada específica:
// Encontrar entrada del libro mayor por orden asociada
const statement = await getLedgerStatement(orgId, merchantId, accountId, from, to, token);
const targetOrderId = 'ord_abc123';
const entry = statement.movements.find(m => m.orderId === targetOrderId);
if (entry) {
console.log(`Encontrada entrada ${entry.ledgerEntryId} para orden ${targetOrderId}`);
// Ahora obtener detalles
const recibo = await getLedgerEntryDetails(orgId, merchantId, accountId, entry.ledgerEntryId, token);
}// Encontrar entrada del libro mayor por monto y fecha aproximada
const statement = await getLedgerStatement(orgId, merchantId, accountId, from, to, token);
const targetAmount = '1000000.00';
const targetDate = '2025-01-15';
const entry = statement.movements.find(m =>
m.amount === targetAmount &&
m.postedAt.startsWith(targetDate)
);
if (entry) {
console.log(`Encontrada entrada ${entry.ledgerEntryId}`);
}Manejo de Errores
Errores Comunes:
404 Not Found: El ID de entrada del libro mayor no existe o no pertenece a la cuenta especificada403 Forbidden: La entrada no pertenece al comercio o permisos insuficientes401 Unauthorized: Token inválido o expirado
async function obtenerEntradaSegura(orgId, merchantId, accountId, entryId, token) {
try {
const response = await axios.get(
`https://api.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/${accountId}/reports/ledger-entry/${entryId}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return response.data;
} catch (error) {
if (error.response?.status === 404) {
console.error(`Entrada del libro mayor ${entryId} no encontrada`);
return null;
}
if (error.response?.status === 403) {
console.error(`Acceso denegado a entrada ${entryId}`);
return null;
}
throw error;
}
}