Users

Users represent individuals registered in the ZB ID system. Each user has a profile, a KYC verification tier, and an account status. A user can hold an email, a phone number, or both, and either one serves as a login channel. Authenticated users can view and update their own profiles, while administrators can look up and manage any user account.


The user model

The profile response contains the information associated with a registered account, including its login channels, verification stamps, KYC tier, status, and assigned roles.

Properties

  • Name
    id
    Type
    string (UUID)
    Description

    Unique identifier for the user. This is the value carried in the sub claim of the user's tokens.

  • Name
    phone
    Type
    string | null
    Description

    The user's phone number (for example, +263771234567). May be null if the account has only an email.

  • Name
    email
    Type
    string | null
    Description

    The user's email address. May be null if the account has only a phone.

  • Name
    firstName
    Type
    string | null
    Description

    The user's first name.

  • Name
    lastName
    Type
    string | null
    Description

    The user's last name.

  • Name
    kycTier
    Type
    string
    Description

    The user's KYC verification level. One of NONE, BASIC, STANDARD, or ENHANCED.

  • Name
    status
    Type
    string
    Description

    The current account status. One of ACTIVE, SUSPENDED, LOCKED, or DEACTIVATED.

  • Name
    roles
    Type
    array
    Description

    Roles assigned to the user, each with an id, name, description, and optional subsidiary scope.

  • Name
    createdAt
    Type
    string (ISO 8601)
    Description

    Timestamp of when the account was created.

  • Name
    emailVerifiedAt
    Type
    string (ISO 8601) | null
    Description

    When the current email was verified, or null if unverified. Changing the email resets this to null.

  • Name
    phoneVerifiedAt
    Type
    string (ISO 8601) | null
    Description

    When the current phone was verified, or null if unverified. Changing the phone resets this to null.

User profile object

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "phone": "+263771234567",
  "email": "[email protected]",
  "firstName": "Tendai",
  "lastName": "Moyo",
  "kycTier": "BASIC",
  "status": "ACTIVE",
  "roles": [
    {
      "id": "a0000000-0000-0000-0000-000000000001",
      "name": "customer",
      "description": "Standard retail customer",
      "subsidiaryScope": null
    }
  ],
  "createdAt": "2026-05-15T08:30:00Z",
  "emailVerifiedAt": "2026-05-16T09:00:00Z",
  "phoneVerifiedAt": null
}

GET/users/me

Get current user

Retrieve the profile of the currently authenticated user. Requires a valid Bearer token.

Request

GET
/users/me
curl https://id.zb.co.zw/users/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "phone": "+263771234567",
  "email": "[email protected]",
  "firstName": "Tendai",
  "lastName": "Moyo",
  "kycTier": "BASIC",
  "status": "ACTIVE",
  "roles": [
    {
      "id": "a0000000-0000-0000-0000-000000000001",
      "name": "customer",
      "description": "Standard retail customer",
      "subsidiaryScope": null
    }
  ],
  "createdAt": "2026-05-15T08:30:00Z",
  "emailVerifiedAt": "2026-05-16T09:00:00Z",
  "phoneVerifiedAt": null
}
GET/users/meTry it

Read your own profile

Uses the token from your last sign-in on the Authentication page. Returns the profile of the signed-in identity. With no token it returns 401.

Runs against the ZB ID STAGING sandbox (id-staging.zb.co.zw). Register a throwaway test account; never use real credentials.

No token yet. Sign in above, or paste one below.
Query parameters

PATCH/users/me

Update current user

Update the profile of the currently authenticated user. Only the fields you include are changed. This endpoint can also add, change, or remove login channels.

Optional attributes

  • Name
    firstName
    Type
    string
    Description

    Updated first name.

  • Name
    lastName
    Type
    string
    Description

    Updated last name.

  • Name
    email
    Type
    string
    Description

    Set or change the email. Must be a valid email address. Stored lowercased and trimmed.

  • Name
    phone
    Type
    string
    Description

    Set or change the phone. Must match ^\+?[0-9]{10,15}$.

  • Name
    removeEmail
    Type
    boolean
    Description

    When true, removes the email from the account. Defaults to false.

  • Name
    removePhone
    Type
    boolean
    Description

    When true, removes the phone from the account. Defaults to false.

Channel semantics

  • Setting an identifier that already belongs to another user returns 409 CONFLICT.
  • Changing an identifier to a new value resets its verified stamp (emailVerifiedAt or phoneVerifiedAt) to null. Submitting the identifier's current value is a no-op and leaves the stamp untouched.
  • Setting and removing the same channel in one request (for example, email plus removeEmail: true) returns 400 BAD_REQUEST with Cannot set and remove the same identifier.
  • Removing your last remaining login identifier returns 400 BAD_REQUEST with Cannot remove your only login identifier. A user must always keep at least one of email or phone.

Request

PATCH
/users/me
curl -X PATCH https://id.zb.co.zw/users/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "lastName": "Moyo-Ncube",
    "email": "[email protected]"
  }'

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "phone": "+263771234567",
  "email": "[email protected]",
  "firstName": "Tendai",
  "lastName": "Moyo-Ncube",
  "kycTier": "BASIC",
  "status": "ACTIVE",
  "roles": [
    {
      "id": "a0000000-0000-0000-0000-000000000001",
      "name": "customer",
      "description": "Standard retail customer",
      "subsidiaryScope": null
    }
  ],
  "createdAt": "2026-05-15T08:30:00Z",
  "emailVerifiedAt": null,
  "phoneVerifiedAt": null
}

Conflict (409)

{
  "error": "CONFLICT",
  "message": "Email already registered to another account, log in with that email instead",
  "status": 409,
  "timestamp": "2026-07-10T10:21:00.321Z"
}

Removing your only identifier (400)

{
  "error": "BAD_REQUEST",
  "message": "Cannot remove your only login identifier",
  "status": 400,
  "timestamp": "2026-07-10T10:22:00.111Z"
}

GET/users/{id}

Get user by ID

Retrieve a user by their unique ID. This endpoint requires the admin:users scope.

Request

GET
/users/{id}
curl https://id.zb.co.zw/users/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "phone": "+263771234567",
  "email": "[email protected]",
  "firstName": "Tendai",
  "lastName": "Moyo",
  "kycTier": "BASIC",
  "status": "ACTIVE",
  "roles": [
    {
      "id": "a0000000-0000-0000-0000-000000000001",
      "name": "customer",
      "description": "Standard retail customer",
      "subsidiaryScope": null
    }
  ],
  "createdAt": "2026-05-15T08:30:00Z",
  "emailVerifiedAt": "2026-05-16T09:00:00Z",
  "phoneVerifiedAt": null
}

GET/users/phone/{phone}

Look up user by phone

Look up a user by their phone number. The phone number must be URL-encoded (for example, %2B263771234567 for +263771234567). This endpoint requires the admin:users scope.

Request

GET
/users/phone/{phone}
curl https://id.zb.co.zw/users/phone/%2B263771234567 \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "phone": "+263771234567",
  "email": "[email protected]",
  "firstName": "Tendai",
  "lastName": "Moyo",
  "kycTier": "BASIC",
  "status": "ACTIVE",
  "roles": [
    {
      "id": "a0000000-0000-0000-0000-000000000001",
      "name": "customer",
      "description": "Standard retail customer",
      "subsidiaryScope": null
    }
  ],
  "createdAt": "2026-05-15T08:30:00Z",
  "emailVerifiedAt": "2026-05-16T09:00:00Z",
  "phoneVerifiedAt": null
}

PATCH/users/{id}/status

Update user status

Update the account status of a user. This endpoint requires the admin:users scope. Use it to suspend, lock, reactivate, or deactivate accounts.

Required attributes

  • Name
    status
    Type
    string
    Description

    The new account status. One of ACTIVE, SUSPENDED, LOCKED, or DEACTIVATED.

  • Name
    reason
    Type
    string
    Description

    Optional. A description of why the status is changing, stored for audit purposes.

Setting the status to SUSPENDED or DEACTIVATED revokes all of the user's active sessions. Setting it back to ACTIVE clears the failed-attempt counter and any lock. The response is a confirmation message, not the full user object.

Request

PATCH
/users/{id}/status
curl -X PATCH https://id.zb.co.zw/users/550e8400-e29b-41d4-a716-446655440000/status \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "status": "SUSPENDED",
    "reason": "Suspicious activity detected on account"
  }'

Response

{
  "message": "User status updated to SUSPENDED"
}

Was this page helpful?