How it works
The API has four objects. Everything else is either a lookup (balance, usage, bank catalog) or a block that travels inside a request (the sender).
Quote ───────────┐ POST /v1/quotes → quote.id (quote) │ 1 use, ~60 s POST /v1/beneficiaries → beneficiary.id ▼ POST /v1/payouts → payment.id Beneficiary ──► Payout ──────► Event ─► your webhookUrl (consumes the quote) (beneficiary) (payment) (event) ⋮ asynchronous │ POST your webhookUrl ← event └─► history (payment.events[])The event is payment.settled, payment.failed or payment.reversed. The
beneficiary is optional: it can go inline in POST /v1/payouts.
Fixes how much is delivered, how much we charge and how much is debited from
you. POST /payouts does not accept any amount. You send amount in deliver
(what the beneficiary receives) or in spend (what you are charged), never
in both; the response is the same in either case, and GET /quotes/{id}
returns it identically.
- Single use. Consuming it twice returns
409 quote_already_consumed. - It expires. TTL ~60 s. After
expires_at,422 quote_expired. - Quoting is free: it does not reserve balance, does not consume limits and does not generate billable usage.
| Field | Type | What it is |
|---|---|---|
id |
uuid | What you send as quoteId when paying out |
fixed |
deliver · spend |
Which side you fixed |
spend |
{ asset, amount } |
What you are charged |
deliver |
{ asset, amount } |
What the beneficiary receives |
fee |
{ asset, amount } |
Our fee, always in the delivered asset |
rate |
object · null | { value, market, spread_bps }, or null if there is no conversion |
status |
open · consumed · expired |
|
expires_at · created_at |
ISO-8601 | Past expires_at it is no longer usable |
Fixing deliver, the fee is added on top; fixing spend, what arrives comes
from the rate minus the fee. See quote in bolívares.
Beneficiary
Section titled “Beneficiary”Who gets paid. Registration is idempotent on (national ID, bank, method): resending the same data returns the same beneficiary with
created: false.
| Field | Type | What it is |
|---|---|---|
id |
uuid | What you send as beneficiaryId when paying out |
full_name |
string | Name exactly as the destination bank has it |
national_id |
string | Cédula or RIF: V/E/J/G/P + 6 to 9 digits |
bank_code |
string | Destination bank, 4 digits (0102, 0134, 0138…) |
account_number |
string · null | 20-digit account starting with bank_code. Required for transferencia |
phone |
string · null | Mobile 04XXXXXXXXX. Required for pago móvil; optional for bank transfer |
asset · country |
string | BS · VE |
status |
active · blocked |
A blocked beneficiary returns 422 beneficiary_blocked |
payout_count |
int | Payouts that reached them successfully |
last_success_at · last_failure_reason |
ISO-8601 · string | Their history |
created_at |
ISO-8601 |
Payout
Section titled “Payout”A payment. It consumes a quote and delivers the amount to the beneficiary.
| Field | Type | What it is |
|---|---|---|
id |
uuid | |
status |
see states | submitted is the normal outcome |
status_reason |
string · null | Why it is where it is |
beneficiary_id |
uuid · null | To whom |
customer_id |
uuid · null | Which of your users it belongs to, if you sent it |
payout_asset · payout_amount |
BS · string |
What the beneficiary receives |
source_asset · source_amount |
string | What was debited from you: amount plus fee |
fee_amount |
string | Our fee. 0 on a failed payment: the entry was fully reversed |
method |
pago_movil · transferencia |
The method it went out through |
bank_reference |
string · null | The receipt the beneficiary sees at their bank. It exists once the transfer completes; it is the only transfer identifier we publish |
compensated |
bool | Whether the accounting entry was reversed |
settled_at |
ISO-8601 · null | When the money went out |
created_at |
ISO-8601 | When you requested it |
events[] |
array | Transition history (only in GET /payments/{id}) |
Each element of events[]:
| Field | What it is |
|---|---|
from_status · to_status |
The transition |
reason |
ledger_committed, payout_accepted, payout_accepted_async, resolved_by_reaper, payout_failed, payout_returned, payout_reported_failure… |
actor |
api (your call) · network (the payment network notified us) · reaper (our resolution process) · system |
metadata |
Context for the transition. On a payout, methodRequested and methodUsed |
created_at |
When |
Every webhook leaves a queryable event, with the details of each attempt.
| Field | Type | What it is |
|---|---|---|
id |
string | Deduplicate on this. It also travels in x-event-id |
event_type |
string | payment.settled · payment.failed · payment.reversed |
aggregate_type · aggregate_id |
string | Which object it is about (payment + its id) |
payload |
object | The body we sent (only in GET /events/{id}) |
status |
pending · published · dead |
dead = your failed queue |
attempts |
int | Attempts used |
last_error |
string · null | Why the last one failed |
next_attempt_at · published_at · dead_at |
ISO-8601 · null | |
deliveries[] |
array | Each attempt with its HTTP code and latency |
See webhooks.
Blocks that are not objects
Section titled “Blocks that are not objects”sender (who orders the transfer) travels inside POST /payouts: it is
not a resource and has no id. See
pay out. Your position
(GET /treasury/position) and your usage (GET /limits/usage) are live
figures: they have no id and no queryable history.