Inyo

Referencia de la API

Todos los endpoints están bajo /organizations/{tenant}/ en el host de la API de wallet (https://{FQDN}). Todas las solicitudes requieren el header X-API-KEY. Todos los POST requieren un header Idempotency-Key.


Billeteras

MétodoRutaDescripción
GET/walletsLista las billeteras de tu tenant
POST/walletsCrea una billetera (owner_type, owner_ref, name)
GET/wallets/{id}Obtiene una billetera
GET/wallets/{id}/balanceSaldos por activo (?asset=USD opcional)
GET/wallets/{id}/entriesMovimientos del libro contable — paginados (50 por página), filtrables por asset, journal_kind y rango de fechas

Las billeteras creadas a través de la API siempre tienen kind: operational. Los demás tipos de cuenta (subcuentas de retención, suspense, origen externo) son gestionados por el sistema y solo aparecen en los movimientos del libro contable.

Movimiento de Dinero

MétodoRutaDescripción
POST/depositsRegistra un origen externo y lo divide entre billeteras de forma atómica
POST/holdsPreautoriza (coloca una retención)
GET/holds/{id}Obtiene una retención junto con su historial de capturas
POST/holds/{id}/captureCaptura parte o la totalidad de una retención hacia una cuenta de destino
POST/holds/{id}/voidAnula la porción restante (no capturada) de una retención
POST/captures/{captureJournalUuid}/refundReembolsa contra una captura específica (se permite parcial)
POST/transfersTransferencia del mismo activo entre billeteras
POST/fx-conversionsConversión entre activos con rate y rate_source explícitos

Tipos de journal: deposit, preauth, capture, void, refund, transfer, fx_conversion.

Estados de retención: open, partially_captured, captured, voided. (expired está reservado; la expiración actualmente no se aplica automáticamente — anula las retenciones expiradas de forma explícita.)

Tipos de origen de depósito: wire, ach_debit, card, stablecoin_deposit.


Montos y Activos

  • Todos los montos son strings JSON, decimales con hasta 8 posiciones. Los campos amount de las respuestas también son strings — nunca los parsees como números JSON (pérdida de precisión).
  • Activos soportados: USD, USDC, EUR, MXN.
  • Los saldos se actualizan atómicamente con la escritura del journal — una respuesta exitosa significa que el saldo refleja la operación.

Manejo de Errores

Todos los errores devuelven un cuerpo JSON:

{
  "error": "ERROR_CODE",
  "message": "Human-readable explanation."
}
HTTPerrorCuándo ocurre
400MISSING_IDEMPOTENCY_KEYPOST sin header Idempotency-Key
401UNAUTHORIZEDX-API-KEY faltante o inválida
403FORBIDDENLa API key no coincide con el {tenant} de la URL
404NOT_FOUNDLa billetera, retención o captura referenciada no existe (o no está en tu tenant)
409INVALID_HOLD_STATECapturar una retención anulada, anular una capturada, etc.
422VALIDATION_ERROREl payload falló la validación — el campo errors lista los problemas por campo
422INSUFFICIENT_FUNDSLa preautorización o transferencia excede el saldo available de la billetera
422INVALID_ASSETasset_code desconocido o no soportado
422INVALID_ACCOUNTLa cuenta referenciada no es válida para la operación
422LEDGER_IMBALANCELas divisiones no suman el monto del origen, u otra violación de la partida doble
500INTERNAL_ERRORError del lado del servidor — contacta a soporte con el timestamp y los detalles de la solicitud

Para VALIDATION_ERROR, la respuesta incluye un desglose por campo:

{
  "error": "VALIDATION_ERROR",
  "message": "The wallet id field must be a uuid.",
  "errors": {
    "wallet_id": ["The wallet id field must be a uuid."]
  }
}

Idempotencia

Cada endpoint POST requiere un header Idempotency-Key. Si envías dos solicitudes con la misma clave, la segunda devuelve exactamente la respuesta de la primera — no se crea un journal duplicado.

Por qué importa: las fallas de red son silenciosas. Una solicitud que expira después de enviarse pero antes de recibir la respuesta te deja sin saber si la operación tuvo éxito. Reintentar con la misma clave siempre es seguro.

Cómo nombrar las claves: cualquier string único de hasta 191 caracteres. La mejor práctica es un identificador estable y significativo por operación:

  • deposit-BANK-WIRE-98765432 para una transferencia bancaria específica
  • capture-INV-4521 para una factura específica
  • refund-INV-4521-partial-1 para un reembolso específico

Nunca reutilices una clave para operaciones diferentes. Reutilizar invoice-4521-refund para un reembolso de $50 y luego para uno de $100 devuelve la respuesta de $50 la segunda vez — el reembolso de $100 nunca ocurre.

Las claves se almacenan por journal, con alcance limitado a tu tenant, y nunca expiran.


Trazabilidad

  • Cada respuesta de journal incluye parentJournalId cuando revierte o continúa otra operación — sigue la cadena reembolso → captura → preautorización para obtener un rastro de auditoría completo.
  • Cada movimiento incluye lineageRef — los IDs de origen (consumidos por FIFO) que financiaron ese movimiento específico.
  • Los journals de depósito incluyen el UUID del origen creado en metadata.source_uuid para referencia cruzada.

Notas de Roadmap

  • Los webhooks para cambios de saldo están en el roadmap — mientras tanto, consulta los saldos o los movimientos mediante polling.
  • El escrow estilo marketplace (visible para ambas partes) está planeado como una variante separada de las retenciones estilo tarjeta — contacta a Inyo si lo necesitas.