Cash Out — Initialization
Start an earnings payout: the institution hands cash to the driver, and Presto reduces the driver's available earnings by that amount.
Overview
This is the first of the two Cash Out steps. It:
- Re-validates the driver and the requested amount against the live
available_earningsand the daily payout allowance - Places a hold on the amount so it cannot be withdrawn twice
- Triggers a one-time password (OTP) to the driver's Presto app, proving the driver is present at the counter
- Returns a
transaction_referenceand attl
Nothing is paid out at this point and no money should change hands. Earnings are debited only by Cash Out — Confirmation.
Endpoint details
Method: POST
URL: /api/institutions/v1/drivers/earnings/payout/init
Purpose: Hold an earnings amount, issue an OTP and obtain a transaction reference
All API calls require a valid bearer token. See Authentication.
Request specification
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer {token} |
Content-Type | Yes | application/json |
Idempotency-Key | Yes | UUID v4 identifying this logical operation. Enables safe replay. |
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
driver | object | Yes | Container for driver identification information |
driver.identifier_type | string | Yes | "phone" or "uid" |
driver.identifier | string | Yes | The identifier value, in the format described in Driver Lookup |
amount | number | Yes | Amount the driver is withdrawing. Must be positive, at most available_earnings, up to 3 decimal places |
currency | string | Yes | Currency code. Must match the balances.currency returned by lookup |
institution_reference | string | Yes | Your identifier for this operation, so you can cross-reference it against your own records. Must be unique within your institution. 1–64 characters: letters, digits, hyphens and underscores |
branch_reference | string | No | The institution's own branch or teller identifier, stored by Presto for reconciliation. Max 64 characters |
Example request
// Headers:
// Authorization: Bearer {token}
// Content-Type: application/json
// Idempotency-Key: 2c1d4e6a-77b8-4c9d-91ef-5a3b7c8d9e01
{
"driver": {
"identifier_type": "uid",
"identifier": "10432"
},
"amount": 100.000,
"currency": "LYD",
"institution_reference": "IZI-2026-0914-000188",
"branch_reference": "TUN-CENTRE-VILLE-04"
}
Response specification
Success response
200 OK{
"data": {
"status": "pending",
"type": "earnings_payout",
"transaction_reference": "EP-4T7M1XC9QD",
"institution_reference": "IZI-2026-0914-000188",
"amount": 100.000,
"currency": "LYD",
"driver": {
"uid": "10432",
"name": "MOH... OK...",
"phone": "218920000000"
},
"available_earnings_before": 128.750,
"available_earnings_after_preview": 28.750,
"otp_required": true,
"otp_delivery": "driver_app",
"otp_length": 6,
"ttl": "2026-09-14T18:49:51+00:00"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
status | string | Always "pending" for a successful init |
type | string | Always "earnings_payout" |
transaction_reference | string | Unique reference required by the confirm and status calls |
institution_reference | string | Your own reference, echoed back unchanged |
amount | number | Held amount, echoed back |
currency | string | Currency of the amount |
driver | object | Driver details to display for verification at the counter |
available_earnings_before | number | Earnings balance at the time of the hold |
available_earnings_after_preview | number | Balance that will remain once the payout is confirmed |
otp_required | boolean | Whether an OTP must be supplied on confirm |
otp_delivery | string | Where the driver receives the code. Currently "driver_app" |
otp_length | number | Number of digits in the OTP |
ttl | string | ISO 8601 timestamp when the hold and the OTP expire (15 minutes from init) |
The OTP proves the driver is physically present and consents to the withdrawal. It protects both parties against a payout made against a stolen phone number or a guessed driver ID.
Error responses
403 Forbidden — payout blocked for this driver
{
"message": "Earnings payout is not allowed for this driver"
}
{
"message": "Driver not found"
}
409 Conflict — idempotency key reused with a different payload
{
"message": "Idempotency key already used with a different payload"
}
409 Conflict — institution_reference already used
{
"message": "Institution reference already used",
"institution_reference": "IZI-2026-0914-000188",
"transaction_reference": "EP-4T7M1XC9QD"
}
422 Unprocessable Content — amount exceeds available earnings
{
"message": "The amount may not be greater than the available earnings.",
"errors": {
"amount": [
"The amount may not be greater than the available earnings."
]
}
}
429 Too Many Requests — daily payout limit reached
{
"message": "Daily payout limit reached for this driver"
}
Error handling
| HTTP Status | Error Type | Example Message | When it Occurs / Resolution |
|---|---|---|---|
| 401 | Unauthorized | {"message": "Unauthenticated."} | Missing or invalid token. |
| 403 | Payout blocked | {"message": "Earnings payout is not allowed for this driver"} | Driver suspended or under review. Presto operations must clear it. |
| 404 | Driver not found | {"message": "Driver not found"} | Identifier does not match a driver. |
| 409 | Idempotency conflict | {"message": "Idempotency key already used with a different payload"} | Generate a new key for a new operation. |
| 409 | Duplicate reference | {"message": "Institution reference already used", "transaction_reference": "..."} | You already initialized this operation. Continue with the returned transaction_reference rather than starting over. |
| 422 | Validation error | {"message": "The amount may not be greater than the available earnings.", "errors": { ... }} | Re-run lookup and retry with a valid amount. |
| 429 | Limit reached | {"message": "Daily payout limit reached for this driver"} | Check capabilities.cash_out_daily_remaining from lookup before offering an amount. |
| 500 | Internal server error | {"message": "Failed to process request"} | Retry with backoff. No payout is made by a failed init. |
Implementation tips
- Read
capabilities.cash_out_daily_remainingfrom Driver Lookup and cap the teller's input accordingly, so429is rare. - Never read the OTP aloud or enter it on the driver's behalf — the driver must type or dictate it from their own device.
- Store
transaction_referencebefore calling confirm, so a crash between the two steps is recoverable. - Show the teller a countdown for the 15-minute
ttl; the OTP expires with it.
Next steps
Collect the OTP from the driver, then finalize with Cash Out — Confirmation.