Orange DOCS
Users

Manage users and KYC

User management lets tenant partners create and manage users, upload KYC/KYB documents, and issue per-user scoped tokens. Every endpoint needs a JWT bearer token — see Authentication for tenant vs. user-scoped tokens.

💡
Prefer the profile endpoints for self-service. Once a user holds a user token, use /profile for their own data rather than routing through /users/:id — the profile endpoints act on whoever holds the token.
Recommended usage pattern
Use caseEndpointToken
User edits their own profilePATCH /profileUser token
User reads their own profileGET /profileUser token
User manages their own M-PesaPOST/PATCH/DELETE /profile/mpesaUser token
User uploads a KYC documentPOST /users/{userId}/kyc-documentsUser token
User creates a paymentPOST /paymentsUser token
Admin reads any user's profileGET /users/{userId}Tenant token
Admin edits any user's profilePATCH /users/{userId}Tenant token
Admin disables a userDELETE /users/{userId}Tenant token
Admin lists all usersGET /usersTenant token

The user object

Create User needs only an email and name; everything else is filled in later via Update User and returned by Get User.

Create — required
email*
string
User email — idempotency key
name*
string
Display name
Profile fields (patchable · returned)
entityTypeoptional
enum
individual or business
firstNameoptional
string
Given name
middleNameoptional
string
Middle name
lastNameoptional
string
Family name
doboptional
string
Date of birth, YYYY-MM-DD
phoneNumberoptional
string
Contact number
nationalityoptional
string[]
ISO 3166-1 alpha-3 codes
birthCountryoptional
string
ISO 3166-1 alpha-3
addressoptional
object
Nested address (returned); set via addressLine* on PATCH
idDocumentTypeoptional
string
e.g. passport
idDocumentNumberoptional
string
Document number
lnUrloptional
string
Lightning address
sectoroptional
string
Business / occupation sector
businessoptional
object
Required when entityType is business
businessPersonsoptional
array
Directors / UBOs (business)
user
{
  "userId": "ccc00000-0000-0000-0000-000000000003",
  "email": "alice@example.com",
  "entityType": "individual",
  "firstName": "Alice",
  "middleName": null,
  "lastName": "Smith",
  "dob": "1990-01-15",
  "nationality": ["GBR"],
  "birthCountry": "GBR",
  "address": {
    "line1": "1 Example Street",
    "line2": null,
    "city": "London",
    "state": null,
    "postalCode": "EC1A 1BB",
    "country": "GBR"
  },
  "idDocumentType": "passport",
  "idDocumentNumber": "123456789",
  "sector": "technology",
  "business": null,
  "businessPersons": [],
  "createdAt": "2026-05-07T12:00:00.000Z",
  "updatedAt": "2026-05-07T12:00:00.000Z"
}

The business object

Sent in business when entityType is business. The address shape below is reused by registeredAddress, tradingAddress, and each person's address.

business
companyName*
string
Legal company name
type*
enum
LIMITED · PARTNERSHIP · SOLE_TRADER · CHARITY · TRUST · LLP · OTHER
registrationNumber*
string
Company registration number
phone*
string
Company phone number
tradingNameoptional
string
Trading / DBA name if different
registrationDateoptional
string
ISO-8601 date (YYYY-MM-DD)
websiteoptional
string
Company website
registeredAddressoptional
object
Address object (see below)
tradingAddressoptional
object
Address object (see below)
address object
line1
string
Street address
line2
string
Apt / suite (optional)
city
string
City
state
string
State / province
postalCode
string
Postal / ZIP code
country
string
ISO 3166-1 alpha-3
business
{
  "companyName": "Acme Ltd",
  "tradingName": "Acme",
  "type": "LIMITED",
  "registrationNumber": "12345678",
  "registrationDate": "2018-04-15",
  "phone": "+442071234567",
  "website": "https://acme.example",
  "registeredAddress": {
    "line1": "1 Example Street",
    "city": "London",
    "postalCode": "EC1A 1BB",
    "country": "GBR"
  }
}

Business persons

The businessPersons array lists directors, shareholders, UBOs and secretaries. At least one director and one ubo are required.

businessPersons[] entry
types*
string[]
director · shareholder · ubo · secretary
ownershipoptional
number
Equity % 0–100 (shareholders / UBOs)
personoptional
object
Personal details (see below)
person object
firstName
string
Given name
middleName
string
Middle name
lastName
string
Family name
dob
string
YYYY-MM-DD
email
string
Email
phone
string
Phone
nationality
string[]
ISO 3166-1 alpha-3 codes
birthCountry
string
ISO 3166-1 alpha-3
address
object
Address object
idDocumentType
enum
PASSPORT · NATIONAL_ID · DRIVERS_LICENCE · WORK_PERMIT
idDocumentNumber
string
Document number
businessPersons
[
  {
    "types": ["director", "ubo"],
    "ownership": 100,
    "person": {
      "firstName": "Alice",
      "lastName": "Smith",
      "dob": "1984-12-08",
      "nationality": ["GBR"],
      "birthCountry": "GBR",
      "idDocumentType": "PASSPORT",
      "idDocumentNumber": "123456789"
    }
  }
]

Endpoints

7 calls
POST /tokens/user

Issue user token

Mint a 24-hour user-scoped JWT tied to a specific user — it can only read and write that one user's data. Requires a tenant token.

Request body
userId*
string
Cognito UUID of the target user
⚠️
Errors: 400 userId missing · 401 invalid token · 403 no tenant / caller used a user token · 404 user not found / cross-tenant / inactive.
POST /tokens/user
{ "userId": "ccc00000-0000-0000-0000-000000000003" }
POST /users

Create user

Create a user under the caller's tenant. Idempotent — returns the existing record (200) if the email is already registered, otherwise 201. Requires a tenant token.

Request body
email*
string
User email — idempotency key
name*
string
Display name
POST /users
{
  "email": "alice@example.com",
  "name": "Alice Smith"
}
GET /users

List users

List users in the caller's tenant. Disabled users are excluded by default. offsetMarker is null on the last page; pass it as offset for the next page. Requires a tenant token.

Query parameters
limitoptional
integer
Max results 1–100 (default 100)
offsetoptional
string
Pagination cursor from previous response
statusoptional
enum
active (default) or inactive
GET /users
{
  "items": [
    {
      "id": "5605d7f3-8cf3-4e68-a4d7-e816284098be",
      "userId": "ccc00000-0000-0000-0000-000000000003",
      "email": "alice@example.com",
      "name": "Alice Smith",
      "userRole": "Normal User",
      "status": "Active",
      "createdAt": "2026-05-07T12:00:00.000Z",
      "updatedAt": "2026-05-07T12:00:00.000Z"
    }
  ],
  "offsetMarker": "eyJhIjoiYiJ9"
}
GET /users/{userId}

Retrieve a user

Read a user's full profile (the user object above). A user token is accepted only when its userId claim matches the path. Cross-tenant and disabled users both return 404.

GET /users/{userId}
{
  "userId": "ccc00000-0000-0000-0000-000000000003",
  "email": "alice@example.com",
  "entityType": "individual",
  "firstName": "Alice",
  "middleName": null,
  "lastName": "Smith",
  "dob": "1990-01-15",
  "nationality": ["GBR"],
  "birthCountry": "GBR",
  "address": {
    "line1": "1 Example Street",
    "line2": null,
    "city": "London",
    "state": null,
    "postalCode": "EC1A 1BB",
    "country": "GBR"
  },
  "idDocumentType": "passport",
  "idDocumentNumber": "123456789",
  "sector": "technology",
  "business": null,
  "businessPersons": [],
  "createdAt": "2026-05-07T12:00:00.000Z",
  "updatedAt": "2026-05-07T12:00:00.000Z"
}
PATCH /users/{userId}

Update a user

Patch a profile — include only the fields you want to change. Address is set with flat addressLine1/addressCity/… fields. When entityType is business, business is required and businessPersons must include at least one director and one UBO. Unknown fields return 400. User tokens must match the path userId.

💡
The response is the full updated profile — same shape as Get User.
PATCH /users/{userId}
{
  "firstName": "Alice",
  "lastName": "Smith",
  "dob": "1990-01-15",
  "nationality": ["GBR"],
  "addressLine1": "1 Example Street",
  "addressCity": "London",
  "addressPostalCode": "EC1A 1BB",
  "addressCountry": "GBR",
  "idDocumentType": "passport",
  "idDocumentNumber": "123456789"
}
DELETE /users/{userId}

Delete (disable) a user

Disables the user's Cognito account and sets status to Inactive. Disabled users are hidden from List Users and return 404 on all user endpoints. A user cannot disable their own account. Requires a tenant token.

⚠️
Errors: 400 can't disable own account · 401 invalid token · 403 no tenant / user token · 404 not found · 500 Cognito error (safe to retry).
DELETE /users/{userId}
{
  "id": "5605d7f3-8cf3-4e68-a4d7-e816284098be",
  "userId": "ccc00000-0000-0000-0000-000000000003",
  "email": "alice@example.com",
  "name": "Alice Smith",
  "status": "Inactive",
  "updatedAt": "2026-05-07T18:00:00.000Z"
}
POST /users/{userId}/kyc-documents

Upload KYC document

Upload a KYC/KYB identity document as multipart/form-data. User tokens must match the path userId.

Form fields
file*
binary
PDF, PNG, JPEG or JPG. Max 10 MB.
documentType*
string
See values below
Document types
ValueDescription
passportPassport
national_idNational identity card
drivers_licenseDriver's licence
proof_of_addressUtility bill, bank statement, etc.
selfieSelfie / liveness photo
cert_of_incorpCertificate of incorporation
articlesArticles of association
board_resolutionBoard resolution
ubo_registerUBO register
otherOther supporting document

documentType is case-insensitive and normalised to lowercase.

upload
curl -X POST /users/{userId}/kyc-documents \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@passport.pdf;type=application/pdf" \
  -F "documentType=passport"