Payments
Deposit funds, generate escrow-backed payment links, manage the checkout flow, and retrieve transaction records. Most endpoints require a valid x-api-key and x-company-id header.
All monetary amounts are expressed in cents. USD 10.00 = 1000. The minimum accepted value is 1.
Deposits
/v1/payments/depositRecord a deposit into a company or user account. Supports idempotency — send an x-idempotency-key header to deduplicate retries.
| Field | Type | Required | Description |
|---|---|---|---|
| userId | uuid | No | Assign deposit to a specific user; omit for a company-level deposit. |
| amount | integer | Yes | Amount in cents (minimum 1). |
| currency | enum | Yes | USD or ZIG. |
| externalReference | string | No | Your system's reference ID for this deposit. |
| userReference | string | No | Human-readable memo shown to the user. |
| isTransit | boolean | No | Mark the deposit as in-transit (not yet settled). Defaults to false. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/deposit" \
-H "x-api-key: zl_sk_your_key_here" \
-H "x-company-id: cmp_01HXYZ..." \
-H "Content-Type: application/json" \
-d '{
"userId": "string",
"amount": 1000,
"currency": "string",
"externalReference": "string",
"userReference": "string",
"isTransit": true
}'{
"id": "txn_01hx...",
"type": "DEPOSIT",
"amount": "5000",
"currency": "USD",
"status": "COMPLETED",
"createdAt": "2026-06-23T10:00:00.000Z"
}Escrow Payment Links
Generate a shareable URL that takes a buyer through a hosted checkout, funding an escrow automatically on completion.
/v1/payments/generate-escrow-payment-linkCreate an escrow-backed payment link. Returns a hash the buyer visits to pay.
| Field | Type | Required | Description |
|---|---|---|---|
| buyerId | uuid | Yes | UUID of the buyer user. |
| sellerId | uuid | No | UUID of the seller; uses company default if omitted. |
| amount | integer | Yes | Total amount in cents. |
| currency | enum | Yes | USD or ZIG. |
| items | array | Yes | Line items — each with name, quantity, pricePerUnit. |
| externalReference | string | No | Your internal reference for this order. |
| userReference | string | No | Memo shown to the buyer at checkout. |
| splitPlan | object | No | Custom fee split: system_fee_cents, service_fee_cents, seller_payout_cents. Must sum to amount. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/generate-escrow-payment-link" \
-H "x-api-key: zl_sk_your_key_here" \
-H "x-company-id: cmp_01HXYZ..." \
-H "Content-Type: application/json" \
-d '{
"buyerId": "string",
"sellerId": "string",
"amount": 1000,
"currency": "string",
"items": [],
"externalReference": "string",
"userReference": "string",
"splitPlan": {}
}'{
"hash": "pay_8f3kz...",
"url": "https://checkout.switchlock.com/pay/pay_8f3kz...",
"expiresAt": "2026-06-30T10:00:00.000Z",
"escrowId": "esc_01hx..."
}/v1/payments/link-details/:hashFetch the current state and metadata of a payment link by its hash.
| Field | Type | Required | Description |
|---|---|---|---|
| hash | string (path) | Yes | The hash returned when the link was generated. |
curl -X GET "https://api.switchlock.co.zw/v1/payments/link-details/value"{
"hash": "pay_8f3kz...",
"status": "PENDING",
"amount": 5000,
"currency": "USD",
"buyer": { "id": "...", "name": "Tendai M." },
"items": [{ "name": "Web Design", "quantity": 1, "pricePerUnit": 5000 }]
}Checkout Flow
These endpoints power the hosted checkout UI. They are all public — no API key required. Call them in sequence to guide a buyer through identity verification and payment acceptance.
These endpoints are intended for the hosted checkout front end. Calling them directly from a server integration is not the standard flow — use generate-escrow-payment-link instead.
/v1/payments/request-checkout-otpSend a one-time password to the buyer's WhatsApp number to verify identity before checkout.
| Field | Type | Required | Description |
|---|---|---|---|
| whatsappNumber | string | Yes | Buyer's WhatsApp number in E.164 format (e.g. +263771234567). |
curl -X POST "https://api.switchlock.co.zw/v1/payments/request-checkout-otp" \
-H "Content-Type: application/json" \
-d '{
"whatsappNumber": "string"
}'{ "sent": true, "expiresIn": 300 }/v1/payments/register-checkout-userRegister a new buyer during checkout if they are not yet in the system.
| Field | Type | Required | Description |
|---|---|---|---|
| mobileNumber | string | Yes | Buyer's mobile number. |
| idNumber | string | Yes | Zimbabwean National ID number. |
| firstName | string | No | Buyer's first name. |
| lastName | string | No | Buyer's last name. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/register-checkout-user" \
-H "Content-Type: application/json" \
-d '{
"mobileNumber": "string",
"idNumber": "string",
"firstName": "string",
"lastName": "string"
}'{ "userId": "usr_01hx...", "status": "REGISTERED" }/v1/payments/accept-paymentAccept a pending payment link after the buyer has verified their identity.
| Field | Type | Required | Description |
|---|---|---|---|
| paymentSlug | string | Yes | Hash of the payment link to accept. |
| phoneNumber | string | No | Buyer's phone number (used for mobile money). |
| whatsappNumber | string | No | Buyer's WhatsApp number. |
| otp | string | No | OTP received via WhatsApp. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/accept-payment" \
-H "Content-Type: application/json" \
-d '{
"paymentSlug": "string",
"phoneNumber": "string",
"whatsappNumber": "string",
"otp": "string"
}'{ "status": "ACCEPTED", "escrowId": "esc_01hx...", "transactionId": "txn_..." }/v1/payments/reject-paymentReject a pending payment link — funds are not captured.
| Field | Type | Required | Description |
|---|---|---|---|
| paymentSlug | string | Yes | Hash of the payment link to reject. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/reject-payment" \
-H "Content-Type: application/json" \
-d '{
"paymentSlug": "string"
}'{ "status": "REJECTED" }EFT Checkout
Powered by OppwaInitiate and verify card or EFT payments through the Oppwa (HPS) gateway. The webhook endpoint is called server-to-server by Oppwa.
/v1/payments/eft-pay/initiateStart an EFT checkout session for a given payment link. Returns a checkoutId to mount the Oppwa widget.
| Field | Type | Required | Description |
|---|---|---|---|
| paymentSlug | string | Yes | Hash of the payment link to fund via EFT. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/eft-pay/initiate" \
-H "Content-Type: application/json" \
-d '{
"paymentSlug": "string"
}'{ "checkoutId": "ch_8f3kz..." }/v1/payments/eft-pay/verifyVerify an EFT payment after the Oppwa widget completes. Called client-side with the resourcePath from the widget callback.
| Field | Type | Required | Description |
|---|---|---|---|
| resourcePath | string | Yes | The resourcePath provided by the Oppwa widget on completion (e.g. /v1/checkouts/{id}/payment). |
curl -X POST "https://api.switchlock.co.zw/v1/payments/eft-pay/verify" \
-H "Content-Type: application/json" \
-d '{
"resourcePath": "string"
}'{ "status": "COMPLETED", "transactionId": "txn_..." }/v1/payments/eft-pay/webhookOppwa server-to-server webhook. SwitchLock uses the id in the payload to re-verify the payment securely. Always returns 200 OK.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | No | Checkout ID from Oppwa (preferred). |
| payload | object | No | Fallback: Oppwa may nest the ID here as payload.id. |
curl -X POST "https://api.switchlock.co.zw/v1/payments/eft-pay/webhook" \
-H "Content-Type: application/json" \
-d '{
"id": "string",
"payload": {}
}'{ "status": "OK" }Transactions
/v1/payments/transaction/:idRetrieve a single transaction record by its UUID.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string (path) | Yes | UUID of the transaction to retrieve. |
curl -X GET "https://api.switchlock.co.zw/v1/payments/transaction/value" \
-H "x-api-key: zl_sk_your_key_here" \
-H "x-company-id: cmp_01HXYZ..."{
"id": "txn_01hx...",
"type": "ESCROW_HOLD",
"amount": "10000",
"currency": "USD",
"status": "COMPLETED",
"metadata": {},
"createdAt": "2026-06-23T10:00:00.000Z"
}Authentication
All non-public endpoints require two headers on every request.
x-api-key: your_api_key_here
x-company-id: your_company_uuidPublic endpoints (marked Public above) do not require these headers — they are accessible from a browser directly.