SwitchLock Docs

Getting Started

Go from zero to a funded escrow in six steps. Follow along with any HTTP client — no SDK needed.

Base URLs

EnvironmentBase URL
Developmenthttp://localhost:3005
Staginghttps://staging-api.switchlock.co.zw
Productionhttps://api.switchlock.co.zw

The flow

Steps 1–5 are called from your server. Step 6 is called from the buyer's device.

1
Your server · Public endpoint

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"
Response — 201 Created
{
  "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.

FieldRequiredDescription
nameYesHuman-readable company name
slugYesURL-safe identifier, globally unique
adminEmailYesVerification email will be sent here
adminFirstNameYesFirst name of the admin
adminLastNameYesLast name of the admin
adminPasswordYesMin 8 chars — must be strong
isMerchantNotrue = single-seller, false = marketplace
documentNoCompany registration doc (PDF / JPG)
2
Admin inbox · Required before login

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"
  }'
Response — 200 OK
{
  "message": "Email verified successfully"
}
Didn't receive the code?
curl -X POST "https://api.switchlock.co.zw/v1/auth/resend-verification" \
  -H "Content-Type: application/json" \
  -d '{ "email": "admin@acme.co.zw" }'
3
Your server

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!"
  }'
Response
{
  "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" }'
Response — copy this key now
{
  "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.

4
Your server

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.

Get valid institution IDs first

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"
Response (excerpt)
[
  { "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"}'
Response — 201 Created
{
  "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 fieldRequiredDescription
institutionIdYesID from GET /v1/identity/financial-institutions
accountNumberYesBank account number
accountNameNoName on the account — used for payout reconciliation
branchCodeNoBranch code (required by some banks)
branchNameNoHuman-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.

5
Your server

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 }
    ]
  }'
Response — 201 Created
{
  "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.

6
Buyer's device — browser or WhatsApp

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.

6A

Load payment details

Public — no API key
GET https://api.switchlock.co.zw/v1/payments/link-details/aB3xK9mN2p
Response
{
  "id": "lnk_01HPAY...",
  "status": "PENDING",
  "totalAmount": "25000",
  "currency": "USD",
  "seller": { "firstName": "Tendai", "lastName": "Moyo" },
  "items": [{ "name": "Laptop Stand", "quantity": 1, "pricePerUnit": 25000 }]
}
6B

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..."
  }'
Response
{ "message": "OTP sent to +263771234567 via WhatsApp" }
6C

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"
  }'
Response — escrow is now FUNDED
{
  "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.

Buyer is on WhatsApp?

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.

Next steps