Getting Started
Go from zero to a funded escrow in six steps. Follow along with any HTTP client — no SDK needed.
Base URLs
| Environment | Base URL |
|---|---|
| Development | http://localhost:3005 |
| Staging | https://staging-api.switchlock.co.zw |
| Production | https://api.switchlock.co.zw |
The flow
Steps 1–5 are called from your server. Step 6 is called from the buyer's device.
Register your Company
No API key needed. This bootstraps your entire tenant — a company record, system ledger, all GL accounts, and the first administrator account. A verification email is sent to the admin address automatically.
curl -X POST "https://api.switchlock.co.zw/v1/core/companies" \
-F "name=Acme Marketplace" \
-F "slug=acme" \
-F "adminEmail=admin@acme.co.zw" \
-F "adminFirstName=Jackson" \
-F "adminLastName=Doe" \
-F "adminPassword=SuperSecret123!" \
-F "isMerchant=false"{
"id": "cmp_01HXYZ...",
"name": "Acme Marketplace",
"slug": "acme",
"business_model": "DEVELOPER",
"createdAt": "2026-06-23T09:00:00.000Z"
}isMerchant=true = single seller (retail store). isMerchant=false = marketplace (buyers and sellers are different registered users). This cannot be changed after creation.
| Field | Required | Description |
|---|---|---|
| name | Yes | Human-readable company name |
| slug | Yes | URL-safe identifier, globally unique |
| adminEmail | Yes | Verification email will be sent here |
| adminFirstName | Yes | First name of the admin |
| adminLastName | Yes | Last name of the admin |
| adminPassword | Yes | Min 8 chars — must be strong |
| isMerchant | No | true = single-seller, false = marketplace |
| document | No | Company registration doc (PDF / JPG) |
Verify your Email
Attempting to log in before verifying returns 401 unverified_account — "Please verify your email address." You cannot generate an API key or do anything until this step is complete.
A 6-digit code is emailed to adminEmail immediately after company registration. Submit that code to activate the account.
curl -X POST "https://api.switchlock.co.zw/v1/auth/verify-email" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acme.co.zw",
"code": "847201"
}'{
"message": "Email verified successfully"
}curl -X POST "https://api.switchlock.co.zw/v1/auth/resend-verification" \
-H "Content-Type: application/json" \
-d '{ "email": "admin@acme.co.zw" }'Generate an API Key
Log in with your now-verified admin credentials to get a Bearer token, then exchange it for a permanent API key your server will use for all subsequent calls.
curl -X POST "https://api.switchlock.co.zw/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acme.co.zw",
"password": "SuperSecret123!"
}'{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"userId": "usr_01HXYZ..."
}curl -X POST "https://api.switchlock.co.zw/v1/core/companies/api-keys" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "x-company-id: cmp_01HXYZ..." \
-H "Content-Type: application/json" \
-d '{ "name": "Production Server Key" }'{
"key": "sl_live_a1b2c3d4e5f6...",
"name": "Production Server Key",
"createdAt": "2026-06-23T09:01:00.000Z"
}The key is only shown once — stored as a SHA-256 hash on our end. Copy it to your environment variables immediately. Lost keys must be revoked and regenerated.
Create your first User (the Seller)
Users are the people who hold wallets within your company. Creating a user automatically provisions a ledger with a USD and ZiG account. You should also pass a bank account at creation time — this is where the user's withdrawal payouts will be sent.
The institutionId inside bankAccount must reference a supported bank. Fetch the list before creating users:
curl "https://api.switchlock.co.zw/v1/identity/financial-institutions"[
{ "id": "inst_01HCBZ...", "name": "CBZ Bank", "code": "CBZ" },
{ "id": "inst_01HSTD...", "name": "Standard Chartered", "code": "SCB" },
{ "id": "inst_01HFNB...", "name": "FNB Zimbabwe", "code": "FNB" }
]curl -X POST "https://api.switchlock.co.zw/v1/identity/users" \
-H "x-api-key: sl_live_a1b2c3d4e5f6..." \
-H "x-company-id: cmp_01HXYZ..." \
-F "mobileNumber=+263771234567" \
-F "idNumber=63-123456-A-00" \
-F "firstName=Tendai" \
-F "lastName=Moyo" \
-F "email=tendai@example.co.zw" \
-F 'bankAccount={"institutionId":"inst_01HCBZ...","accountNumber":"1234567890","accountName":"Tendai Moyo","branchCode":"001"}'{
"id": "usr_01HABC...",
"mobileNumber": "+263771234567",
"firstName": "Tendai",
"kycLevel": "BASIC",
"bankAccount": {
"institutionId": "inst_01HCBZ...",
"accountNumber": "1234567890",
"accountName": "Tendai Moyo"
},
"ledger": {
"accounts": [
{ "id": "acc_01HUSD...", "currency": "USD", "balance": "0" },
{ "id": "acc_01HZIG...", "currency": "ZIG", "balance": "0" }
]
}
}| bankAccount field | Required | Description |
|---|---|---|
| institutionId | Yes | ID from GET /v1/identity/financial-institutions |
| accountNumber | Yes | Bank account number |
| accountName | No | Name on the account — used for payout reconciliation |
| branchCode | No | Branch code (required by some banks) |
| branchName | No | Human-readable branch name |
Note the user id — you pass it as sellerId in Step 5. Bank account can also be added or updated later via POST /v1/identity/users/:id/link-id.
Generate a Payment Link
A payment link ties a seller, a product list, and an amount into a shareable URL. Send it to the buyer — they complete the payment without your server being involved again.
curl -X POST "https://api.switchlock.co.zw/v1/payments/generate-escrow-payment-link" \
-H "x-api-key: sl_live_a1b2c3d4e5f6..." \
-H "x-company-id: cmp_01HXYZ..." \
-H "x-idempotency-key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"sellerId": "usr_01HABC...",
"buyerId": "usr_01HBUYER...",
"amount": 25000,
"currency": "USD",
"feePayer": "SELLER",
"externalReference": "ORDER-001",
"items": [
{ "name": "Laptop Stand", "quantity": 1, "pricePerUnit": 25000 }
]
}'{
"id": "lnk_01HPAY...",
"paymentUrl": "https://switchlock.co.zw/checkout/aB3xK9mN2p",
"secureUrlHash": "aB3xK9mN2p",
"totalAmount": "25000",
"currency": "USD",
"status": "PENDING"
}All amounts are in cents — $250.00 = 25000. Send the paymentUrl to your buyer. They complete payment without any additional calls from your server.
Buyer Verifies Identity & Pays
These calls happen on the buyer's side — no API key required. Your server receives a webhook once funds land in escrow.
Load payment details
GET https://api.switchlock.co.zw/v1/payments/link-details/aB3xK9mN2p{
"id": "lnk_01HPAY...",
"status": "PENDING",
"totalAmount": "25000",
"currency": "USD",
"seller": { "firstName": "Tendai", "lastName": "Moyo" },
"items": [{ "name": "Laptop Stand", "quantity": 1, "pricePerUnit": 25000 }]
}Request OTP — identity verification
Buyer enters their mobile number. An OTP is sent via WhatsApp (or SMS fallback). This is how SwitchLock verifies the buyer's identity before funds move.
curl -X POST "https://api.switchlock.co.zw/v1/payments/request-checkout-otp" \
-H "Content-Type: application/json" \
-d '{
"mobileNumber": "+263771234567",
"paymentLinkId": "lnk_01HPAY..."
}'{ "message": "OTP sent to +263771234567 via WhatsApp" }Accept payment — escrow goes FUNDED
curl -X POST "https://api.switchlock.co.zw/v1/payments/accept-payment" \
-H "Content-Type: application/json" \
-d '{
"paymentLinkId": "lnk_01HPAY...",
"mobileNumber": "+263771234567",
"otp": "847201"
}'{
"escrowId": "esc_01HFUND...",
"status": "FUNDED",
"fundedAt": "2026-06-23T09:05:00.000Z",
"totalAmount": "25000",
"currency": "USD"
}Escrow is FUNDED. Funds are held — neither party can move them unilaterally. Release to the seller from your server: POST /v1/escrow/:escrowId/release.
Steps 6A–6C happen automatically inside the WhatsApp bot. The buyer replies with their OTP in the chat — no browser needed. See the WhatsApp Checkout guide.