SwitchLock Docs

Authentication

SwitchLock uses two authentication mechanisms depending on the caller type, plus two context headers that scope requests to the right company and prevent duplicate operations.

Headers at a glance

x-api-key

Your server-to-server API key. Identifies and authenticates your backend application. Use this for all programmatic integrations.

Required
Authorization: Bearer <token>

A short-lived JWT issued at login. Used by the dashboard and admin interfaces. Not recommended for automated server integrations.

Optional
x-company-id

Scopes the request to a specific tenant. Required on almost every authenticated endpoint. Your API key is pre-associated with a company, but this header must still be sent.

Required
x-idempotency-key

A client-generated UUID for financial mutations (deposits, withdrawals, payment link generation). Prevents duplicate operations on retries. Required on treasury endpoints.

Optional

API Key Authentication

API keys are the primary authentication method for server-to-server integrations. They are generated per company, hashed with SHA-256 before storage, and never retrievable after initial creation.

curl -X GET "https://api.switchlock.co.zw/v1/ledger/user/{userId}/accounts" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6g7h8i9j0..." \
  -H "x-company-id: cmp_01HXYZ..."
Key Prefixes

Keys are prefixed sl_live_ (production) or sl_test_ (staging) for easy identification in your logs.

Rotation

You can have multiple active keys per company. Rotate by generating a new key and then revoking the old one.

Hashed Storage

We store a SHA-256 hash of your key. We cannot recover it for you — only you know the raw value.

Never expose your API key in client-side code (browser JavaScript, mobile apps, or public repositories). All calls must originate from your server. A leaked key gives full access to all company funds and user data.

Bearer Token (Dashboard / Admin)

The SwitchLock dashboard and admin flows use short-lived JWTs. You obtain one by logging in as a Company Administrator. These tokens are scoped to the admin's company and role, and expire after a short window.

curl -X POST "https://api.switchlock.co.zw/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@yourcompany.co.zw",
    "password": "YourPassword"
  }'
Response
{
  "accessToken":  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  // short-lived (~15 min)
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  // longer-lived
  "userId": "adm_01HXYZ..."
}
curl -X GET "https://api.switchlock.co.zw/v1/core/companies/me" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "x-company-id: cmp_01HXYZ..."
curl -X POST "https://api.switchlock.co.zw/v1/auth/refresh" \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "userId": "adm_01HXYZ..."
  }'

For server-to-server integrations, use API keys — not Bearer tokens. Tokens are intended for admin dashboards and browser sessions. They expire and require refresh cycles which add complexity to server code.

Company Context — x-company-id

SwitchLock is multi-tenant. Almost every endpoint that reads or writes data requires a company scope. The x-company-id header tells the API which tenant's data to operate on.

Header format
x-company-id: cmp_01HXYZ...Required

Super Admins can pass any x-company-id to operate across tenants. Regular API keys are tied to a single company and the header must match — mismatches return 403 Forbidden.

Your company ID is returned in the response when you register (POST /v1/core/companies) and in every login response.

Idempotency Keys

Financial mutations are risky to retry — a network timeout does not mean the request failed. Idempotency keys solve this: send the same key on a retry and SwitchLock returns the original response without executing the operation again.

Header format
x-idempotency-key: 550e8400-e29b-41d4-a716-446655440000

Use a UUID v4 generated per-request. Keys expire after 24 hours.

EndpointKey Required?
POST /v1/payments/depositRequired
POST /v1/payments/generate-escrow-payment-linkRequired
POST /v1/escrow/:id/releaseRequired
POST /v1/treasury/withdrawRequired
POST /v1/treasury/bank/captureRequired
POST /v1/escrow/initiateRecommended

If you send a request without an idempotency key to a protected endpoint, the API returns 400 Bad Requestx-idempotency-key header is required. Always generate a fresh UUID per operation, not per session.

Public Endpoints

Some endpoints are intentionally public — they are designed to be called from a buyer's browser or WhatsApp integration where no server secret is available.

EndpointPurpose
POST /v1/auth/loginAdmin dashboard login
POST /v1/auth/refreshRefresh access token
POST /v1/core/companiesRegister a new company (tenant)
GET /v1/payments/link-details/:hashGet payment link details for checkout page
POST /v1/payments/request-checkout-otpRequest OTP for buyer verification
POST /v1/payments/register-checkout-userSelf-register a buyer at checkout
POST /v1/payments/accept-paymentBuyer accepts and funds the payment link
POST /v1/payments/eft-pay/initiateInitiate EFT payment from checkout page
POST /v1/payments/eft-pay/webhookEFT provider webhook (Oppwa/HyperPay)
GET /v1/whatsapp/webhookMeta webhook verification challenge
POST /v1/whatsapp/webhookIncoming WhatsApp message handler
GET /healthHealth check

Authentication Errors

401
Unauthorized

Missing or invalid API key / Bearer token. Check that your x-api-key header is present and the key has not been revoked.

403
Forbidden

Your key is valid but does not have permission for this operation. Commonly seen when the x-company-id doesn't match the key's company.

400
Bad Request

A required header is missing, most commonly x-idempotency-key on a financial mutation endpoint.