Appearance
Settlement execution
Settlement execution confirms a previously generated settlement quote and initiates the settlement process. Before executing, a valid quote must be obtained through the Settlement estimation step.
Settlement lifecycle
A settlement moves through a fixed sequence of statuses. Each status change triggers a SETTLEMENT_STATUS_CHANGE webhook.
┌─────────────────────────────┐
│ CREATED │
│ Quote generated, awaiting │
│ partner confirmation │
└──────────┬──────────────────┘
│
┌────────────────┼───────────────────┐
│ confirmed │ not confirmed
│ within 15 min │ within 15 min
▼ ▼
┌────────────────┐ ┌─────────────────┐
│ CONFIRMED │ │ EXPIRED │
│ Awaiting token │ │ Quote no longer │
│ transfer on- │ │ valid — create │
│ chain │ │ a new quote │
└───────┬────────┘ └─────────────────┘
│
│ tokens received
▼
┌────────────────┐
│ PROCESSING │
│ Settlement in │
│ progress │
└───────┬────────┘
│
▼
┌────────────────┐
│ SENT │
│ Fiat sent to │
│ bank account │
└───────┬────────┘
│
▼
┌────────────────┐
│ FINISHED │
│ Settlement │ ← terminal state ✓
│ complete │
└────────────────┘
┌────────────────┐
│ ERROR │ ← requires manual handling by BRRR support
└────────────────┘Status reference
| Status | Description | Terminal? | Action required |
|---|---|---|---|
CREATED | Quote generated, awaiting partner execution | No | Call Execute Settlement |
CONFIRMED | Quote confirmed, awaiting on-chain token transfer | No | Send tokens to receiveAddress before receivedDeadline |
EXPIRED | Quote not confirmed within 15 minutes | Yes | Create a new quote — expired quotes cannot be reused |
PROCESSING | Tokens received, fiat settlement in progress | No | No action needed — wait for SENT |
SENT | Fiat transferred to the designated bank account | No | No action needed — wait for FINISHED |
FINISHED | Settlement fully complete | Yes | No further action required |
ERROR | Settlement failed and requires manual review | Yes | Contact support@holyheld.com with the quoteId |
Timing
| Step | Typical duration |
|---|---|
CREATED → CONFIRMED | Immediate (partner-controlled, 15-minute window) |
CONFIRMED → PROCESSING | Seconds to minutes after on-chain transfer is detected |
PROCESSING → SENT | Minutes to hours depending on banking rails |
SENT → FINISHED | Typically immediate after bank confirmation |
Token transfer deadline
After executing a settlement (CONFIRMED state), you must send the token transfer to the receiveAddress before the receivedDeadline timestamp. If the deadline passes without a transfer being received, the settlement will not proceed. A new quote must be created.
Handling ERROR settlements
If a settlement reaches ERROR status:
- Do not retry the same
quoteId— it cannot be re-executed - Note the
quoteIdfor your records - Contact support@holyheld.com with the
quoteIdto initiate manual review - Create a new quote only after confirming with BRRR support that the original transaction did not partially settle
Safe retry algorithm
If a network error prevents you from receiving the Execute Settlement response, never retry blindly. Use this sequence:
1. Call GET /partner/settlement/status/{quoteId}
2. Check the status:
┌──────────────────┬─────────────────────────────────────────────┐
│ Status │ Action │
├──────────────────┼─────────────────────────────────────────────┤
│ CREATED │ Execute was not received — safe to retry │
│ EXPIRED │ Quote expired — create a new quote │
│ CONFIRMED │ Execute was accepted — do NOT retry execute │
│ PROCESSING │ Settlement in progress — do NOT retry │
│ SENT │ Fiat sent — do NOT retry │
│ FINISHED │ Settlement complete — do NOT retry │
│ ERROR │ Contact support — do NOT retry with same ID │
└──────────────────┴─────────────────────────────────────────────┘
3. Only call Execute Settlement again if step 2 returns CREATED.
For any other non-error status, the settlement has been accepted.javascript
async function safeExecuteSettlement(quoteId, executePayload) {
try {
return await fetch('https://api.brrr.network/api/v4/partner/settlement/execute', {
method: 'POST',
headers: { 'X-Api-Key': process.env.BRRR_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(executePayload),
});
} catch (networkError) {
// Network error — check whether execute was received before retrying
const statusRes = await fetch(
`https://api.brrr.network/api/v4/partner/settlement/status/${quoteId}`,
{ headers: { 'X-Api-Key': process.env.BRRR_API_KEY } }
);
if (statusRes.status === 404) {
// Quote unknown — safe to create a new quote and retry
throw new Error('Quote not found — create a new quote');
}
const { payload } = await statusRes.json();
if (payload.status === 'CREATED') {
// Execute was not received — safe to retry
return safeExecuteSettlement(quoteId, executePayload);
}
if (payload.status === 'EXPIRED') {
throw new Error('Quote expired — create a new quote');
}
// Any other status means execute was accepted
return { alreadyAccepted: true, status: payload.status };
}
}Confirming settlement
After calling Execute Settlement, the response contains:
receiveAddress— the BRRR wallet address you must send tokens to. Always use the address from this response — never cache a value from a previous settlement.totalAmountIn— the exact token amount to transfer on-chainreceivedDeadline— Unix timestamp after which the settlement expires if no transfer is received
Once the required token amount is received on-chain, BRRR automatically advances the settlement through PROCESSING → SENT → FINISHED.
Monitoring status
Poll Get Settlement Status every 15–30 seconds, or rely on SETTLEMENT_STATUS_CHANGE webhooks. Both mechanisms reflect the same state.
Webhook ordering
Settlement status webhooks may arrive out of order. Always use the timestamp field to determine whether an incoming event is more recent than your stored state. See Webhooks — Event ordering for a handler example.
Next steps
Once settlements are working end-to-end, review the Go-Live Checklist before enabling real users. When you need to remove a customer or address from monitoring, see Offboarding.
