SwitchLock Docs
Identity/KYC

KYC Verification

Zimbabwe's financial regulations require identity verification before users can transact above basic thresholds. SwitchLock's KYC system is built around the national ID document — here's how to collect it, submit it, and respond when the status changes.

Why KYC is required

ZIMRA compliance

Zimbabwe's Anti-Money Laundering Act requires identity records for transactions above regulated thresholds. Verified users can transact without hitting platform-wide limits.

Fraud prevention

Normalized ID deduplication means one physical person can only hold one verified identity across the platform, regardless of how they format their ID number.

Escrow trust

Both parties in an escrow transaction should be verifiable. KYC level 2 confirms a human reviewed the documents — not just that a file was uploaded.

KYC levels explained

The kyc_level field on a user record is a number. Each level reflects a distinct state of identity assurance.

1
BasicAuto-assigned

Assigned automatically when a user is created and their national ID number is linked. No document is required to reach this level — the ID number alone is sufficient.

Unlocks: basic account creation, wallet access. Document upload moves this user to PENDING review.

Admin reviews uploaded document
2
VerifiedManually approved

A SUPER_ADMIN has reviewed the uploaded document and confirmed the identity. Set by calling POST /v1/identity/admin/users/:id/approve with { "approved": true }.

Unlocks: higher transaction limits, eligibility for all escrow types.

BlacklistedPlatform-wide block

Set on the NationalIdentity record, not on the user. This means the block follows the physical ID — any future attempt to register a new account with the same ID number will fail with a 403 Forbidden.

Set via: POST /v1/identity/admin/users/:id/status with { "status": "BLACKLISTED" }.

Zimbabwe National ID format

Zimbabwe national IDs follow a structured format. SwitchLock accepts the ID in any common formatting — dashes, spaces, or no separator — and normalizes it before storage.

ID anatomy
63-1234567-F-15
63
Province code

Two-digit code for the registration province. 63 = Harare.

1234567
Serial number

Seven-digit unique serial within the province.

F
Gender

M = Male, F = Female.

15
District

Two-digit registration district code.

Normalization — all of these resolve to the same record
InputStored as
63-1234567-F-15631234567F15
63 1234567 F 15631234567F15
631234567f15631234567F15
631234567F15631234567F15

ID normalization happens server-side — you do not need to pre-process the ID number your user enters. Pass it exactly as the user typed it; the API will strip dashes, spaces, and lowercase letters before storing.

Uploading documents

Documents can be attached at user creation time or uploaded separately. The field name is always document. Both endpoints use multipart/form-data.

DocumentField nameFormats acceptedNotes
National ID scandocumentJPEG, PNG, PDFRequired for KYC review. Front of the ID card. Stored in private signed storage.
Identity document (alt)documentJPEG, PNG, PDFUse the same field if replacing an existing document — the new file overwrites the previous URL on the NationalIdentity record.
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-1234567-F-15" \
  -F "firstName=Tendai" \
  -F "lastName=Moyo" \
  -F "document=@/path/to/id-front.jpg;type=image/jpeg"
curl -X POST "https://api.switchlock.co.zw/v1/identity/users/usr_01HABC.../document" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -F "document=@/path/to/id-front.jpg;type=image/jpeg"

Re-linking a national ID

If a user's ID number needs to be updated — for example, after an ID reissue — use the link-id endpoint. This is also called automatically during user creation; you only need it directly if you want to update the ID after the fact.

curl -X POST "https://api.switchlock.co.zw/v1/identity/users/usr_01HABC.../link-id" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -H "Content-Type: application/json" \
  -d '{
    "idNumber": "63-1234567-F-15",
    "customReference": "reissue-2026"
  }'
Response — 200 OK
{
  "id": "usr_01HABC...",
  "identity": {
    "id": "nid_631234567F15",
    "id_number": "631234567F15",
    "status": "CLEAR"
  }
}

If the national ID being linked has a status of BLACKLISTED, this call returns403 Forbidden. The block is on the identity record — not the user account — so no workaround exists through your API.

Review timeline and status changes

KYC review is asynchronous. After a document is uploaded, a SUPER_ADMIN reviews it in the SwitchLock admin panel and approves or rejects. There is no polling endpoint — your integration should be designed to check kyc_level when a user attempts a protected action.

1
User created

kyc_level = 1. No document yet.

2
Document uploaded

Still kyc_level = 1. User appears in admin queue with status PENDING.

3
Admin review

SUPER_ADMIN opens the document via the signed URL in the admin dashboard.

4a
Approved

kyc_level set to 2. User status moves to APPROVED in admin filters.

4b
Rejected

kyc_level reset to 1. User remains in PENDING state. Upload a new document to re-enter the queue.

There is no automatic webhook for KYC status changes in the current release. To notify your users when their status updates, poll GET /v1/identity/users/:id at intervals, or trigger a check when the user next opens your app.

Admin: approve or reject a KYC submission

These endpoints require a SUPER_ADMIN role. They are used by the SwitchLock dashboard, but you can also call them directly if you are building your own admin interface.

curl -X POST "https://api.switchlock.co.zw/v1/identity/admin/users/usr_01HABC.../approve" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -H "Content-Type: application/json" \
  -d '{ "approved": true }'
Response — 200 OK
{
  "id": "usr_01HABC...",
  "kyc_level": 2
}
curl -X POST "https://api.switchlock.co.zw/v1/identity/admin/users/usr_01HABC.../approve" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -H "Content-Type: application/json" \
  -d '{ "approved": false }'
Response — 200 OK
{
  "id": "usr_01HABC...",
  "kyc_level": 1
}
curl -X POST "https://api.switchlock.co.zw/v1/identity/admin/users/usr_01HABC.../status" \
  -H "x-api-key: sl_live_a1b2c3d4e5f6..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "BLACKLISTED" }'
Response — 200 OK
{
  "id": "usr_01HABC...",
  "identity": {
    "id": "nid_631234567F15",
    "status": "BLACKLISTED"
  }
}
ActionBodyResulting kyc_levelIdentity status
Approve{ "approved": true }2Unchanged (CLEAR)
Reject{ "approved": false }1Unchanged (CLEAR)
Blacklist{ "status": "BLACKLISTED" }UnchangedBLACKLISTED — blocks future link-id calls

Next steps