Clients

A client is an end user you onboard onto CoinMENA under your partner account. This page explains the client object, its lifecycle, the KYC status model, and the rules that govern it.

Clients are the core object of the Partner API — every trade, deposit, withdrawal, and balance lookup is scoped to a client. This page explains what a client is, how it moves through its lifecycle, and the rules that govern it.


What Is a Client

A client is an end user of your product, registered under your partner account on CoinMENA. You create clients on their behalf using the Partner API, and from that point forward every trading or funding action is performed for a specific client.

Key points:

  • Clients created through the Partner API are auto-verified — they skip the standard user-facing KYC flow and are immediately eligible to trade and be funded.
  • Only personal accounts can be created through the API. Corporate accounts are onboarded through a separate, out-of-band process — contact [email protected] for corporate onboarding.
  • Each client has two identifiers: CoinMENA's internal id and your own partner_client_id. You use your partner_client_id across every client-scoped endpoint.

Client Lifecycle at a Glance

A typical client moves through these stages:

  1. Create — You submit the client's personal, address, employment, and compliance details. The client is created with status: verified and active: true.
  2. Upload KYC documents — Upload the KYC documents required for the client as part of onboarding. Required document types depend on your setup with CoinMENA.
  3. Fund and trade — The client can now be funded via deposits and can trade.
  4. Update over time — Client details can be updated. Some fields are immutable after creation (see Immutable Fields).
  5. Activate or deactivate — Temporarily disable a client's ability to trade or be funded without deleting the record.

Create vs Update Behavior

The create and update endpoints behave differently. Understand both before integrating:

BehaviorPOST /v1/partner/clients (Create)PUT /v1/partner/clients/{partner_client_id}/ (Update)
What it doesCreates a new client recordReplaces an existing client's full record
Payload modelAll required fields must be sentFull replacement — all required fields must be sent on every update, not just the ones you are changing
Immutable fieldsaccount_type, birth_date, place_of_birth_id are set at creationThe three immutable fields are not accepted in the update payload
Uniqueness checkpartner_client_id, email, phone, government_id_number must be uniqueSame uniqueness rules apply to updated values
On duplicateReturns a duplicate-value error (2016, 2026, 2027, or 2028)Same
⚠️

Update is not a patch

There is no partial update. If you send only the fields you want to change, the other required fields will fail validation. Always re-send the full client payload on every update, minus the three immutable fields.


Required Fields Summary

These fields must be provided when creating a client. There is no shorter minimum — the API will reject a create request missing any of them.

CategoryRequired Fields
Identitypartner_client_id, account_type, name, birth_date
Contactemail, phone
Residency & legalresidency_id, citizenship_id, place_of_birth_id, government_id_number, government_id_doe
Addressaddress (with street, city, postal_code, unit — all required)
Employmentemployment (with status required; other subfields conditional — see Employment)
Compliancetrading_volume, account_purpose

On update, the same fields are required except partner_client_id, account_type, birth_date, and place_of_birth_id (the last three are immutable; partner_client_id is in the URL path).

Optional fields: national_number, residency_visa_number, residency_visa_doe. Residency visa fields become conditionally required — see Countries.


The Client Object

Every client endpoint returns the same client shape. Fields are grouped below for readability.

Identity

FieldTypeConstraintsDescription
idintegerCoinMENA's internal numeric ID for the client
partner_client_idstringmax 255, uniqueYour own reference ID. Used in every client-scoped endpoint path
account_typestringpersonal | corporateAccount type. Only personal is creatable via the API
namestring (nullable)max 255Client's full legal name
birth_datestring (date)YYYY-MM-DD, immutableDate of birth
statusstringenum — see KYC Status ModelCurrent verification status
activebooleanWhether the client can trade and be funded

Contact

FieldTypeConstraintsDescription
emailstringvalid email format, uniqueClient's email address
phonestringinternational format, e.g. +97312345678, uniqueClient's phone number

Residency & Legal

FieldTypeConstraintsDescription
residency_idstringcountry ID from /v1/public/countriesCountry of residence
citizenship_idstringcountry ID from /v1/public/countriesCountry of citizenship
place_of_birth_idstringcountry ID, immutableCountry of birth
national_numberstring (nullable)max 255National ID number, where applicable
government_id_numberstringmax 255, uniqueGovernment-issued ID number
government_id_doestring (date)YYYY-MM-DDGovernment ID expiry date
residency_visa_numberstring (nullable)max 255Residency visa number, if applicable
residency_visa_doestring (nullable)YYYY-MM-DDResidency visa expiry date, if applicable

Address

All address subfields are required strings, maximum 255 characters each.

FieldTypeDescription
streetstringStreet name and number
citystringCity of residence
postal_codestringPostal or ZIP code
unitstringApartment, suite, or unit number

Employment

FieldTypeConstraintsDescription
statusstringenumemployed, self_employed, unemployed, housewife, retired
companystring (nullable)max 255Employer or company name (conditional)
job_industrystring (nullable)max 255Industry sector (conditional)
job_levelstring (nullable)max 255Seniority level (conditional)
job_titlestring (nullable)max 255Job title (conditional)

See Employment — Validation Rules for the conditional requirements.

Compliance Metadata

FieldTypeConstraintsDescription
trading_volumestringmax 255Expected monthly trading volume bracket
account_purposearray of stringsmin 1 item, enumOne or more stated purposes for the account

Timestamps

FieldTypeDescription
created_atstring (datetime)When the client record was created
verified_atstring (datetime, nullable)When the client was verified. null if not yet verified

Example

{
  "id": 12345,
  "partner_client_id": "user_12345",
  "account_type": "personal",
  "status": "verified",
  "active": true,
  "name": "John Doe",
  "email": "[email protected]",
  "phone": "+97312345678",
  "residency_id": "bh",
  "citizenship_id": "bh",
  "place_of_birth_id": "bh",
  "birth_date": "1990-01-15",
  "government_id_number": "1234567890",
  "government_id_doe": "2028-01-15",
  "address": {
    "street": "123 Main St",
    "city": "Manama",
    "postal_code": "12345",
    "unit": "4A"
  },
  "employment": {
    "status": "employed",
    "company": "Acme Corp",
    "job_industry": "information_technology_telco",
    "job_level": "senior",
    "job_title": "Software Engineer"
  },
  "trading_volume": "10001_25000",
  "account_purpose": ["short_term_trading", "converting_crypto_to_fiat"],
  "created_at": "2024-06-01T10:00:00Z",
  "verified_at": "2024-06-01T10:00:00Z"
}

Account Types

The API supports two account types, but only one is creatable through the Partner API:

Account TypeCreatable via APINotes
personalYesThe standard end-user account. Created with POST /v1/partner/clients
corporateNoOnboarded through a separate process. Contact CoinMENA to set one up

If you submit any value other than personal to the create endpoint, the request is rejected with a validation error.


Client Identity — Two IDs

Every client has two identifiers that serve different purposes:

IdentifierTypeOwnerUsed For
idintegerCoinMENAInternal reference. Returned in responses but not used in request paths
partner_client_idstringYouYour own reference ID. Used in every client-scoped endpoint path and body
📘

Always use partner_client_id in request paths

Every client-scoped endpoint — GET /v1/partner/clients/{partner_client_id}/, PUT /v1/partner/clients/{partner_client_id}/activation, GET /v1/partner/clients/{partner_client_id}/documents, etc. — takes your partner_client_id in the path, not CoinMENA's internal id. Store partner_client_id in your system as the primary client reference.

Your partner_client_id must be unique across your partner account. Reusing an existing partner_client_id on create returns error 2026 — it does not return or overwrite the existing client. See the Error Codes guide.


KYC Status Model

The status field reflects a client's KYC verification state. Partner-created clients start at verified and stay there unless CoinMENA's compliance team changes the state.

StatusMeaning
verifiedClient has passed verification and can trade and be funded
unverifiedClient has been created but has not completed verification
under_reviewVerification is in progress — compliance is reviewing the client
partially_verifiedClient has completed some but not all verification steps
docs_under_reviewSupporting documents are being reviewed
not_supportedClient cannot be verified — typically due to an unsupported country or regulatory restriction
under_ageClient is below the legal age required by the applicable jurisdiction
rejectedClient failed verification and cannot be onboarded
📘

Partner-created clients are verified on creation

Clients created through POST /v1/partner/clients are assigned status: verified automatically — they do not need to go through the standard user-facing KYC flow. The other statuses are included for completeness and may appear on client records managed by CoinMENA's compliance team. Partners cannot trigger status transitions through the API.


Active vs Inactive

The active flag controls whether a client can trade or be funded. It is independent of status:

  • active: true — Client can calculate quotes, execute trades, deposit, and withdraw.
  • active: false — Client is blocked from all trading and funding actions. Requests return error 2010The client is deactivated.

Toggle a client's active state using PUT /v1/partner/clients/{partner_client_id}/activation with {"active": true} or {"active": false}.

Use deactivation to temporarily suspend a client — for example, while investigating suspicious activity or pausing access pending account review. Deactivation is reversible; it does not delete the client record.


Immutable Fields

Three fields cannot be changed after a client is created:

FieldWhy It Is Immutable
account_typeAccount type is set at creation and cannot be switched between personal and corporate
birth_dateFundamental identity attribute — changes are not permitted for compliance reasons
place_of_birth_idFundamental identity attribute — changes are not permitted for compliance reasons

These fields are not accepted in the PUT /v1/partner/clients/{partner_client_id}/ update payload. Submitting them will not update the record; CoinMENA's schema validation ignores immutable fields on update.

⚠️

Get these right on creation

Because these fields are immutable, double-check them before calling POST /v1/partner/clients. A wrong birth_date or place_of_birth_id cannot be corrected through the API — contact [email protected] if a correction is needed.


Employment — Validation Rules

Employment is a required object on client creation and update. The fields you must (or must not) send depend on the status value:

StatusRequired FieldsDisallowed Fields
employedcompany, job_industry, job_level, job_title
self_employedcompany, job_industry, job_titlejob_level
unemployedcompany, job_industry, job_level, job_title
housewifecompany, job_industry, job_level, job_title
retiredcompany, job_industry, job_level, job_title

status itself is required for every employment submission.

Some employment subfields accept any string but should be submitted using CoinMENA's recommended enum values to align with the compliance model:

  • job_industry — submit one of CoinMENA's recommended industry codes (e.g. information_technology_telco, banking_financial_services)
  • job_level — submit one of CoinMENA's recommended seniority levels (e.g. senior, manager, director)

See the API Reference for the full list of recommended values.


Countries — Residency, Citizenship, Place of Birth

Every client has three country fields, and each must resolve to a valid country ID from CoinMENA's supported list.

📘

Country ID format

Country IDs are lowercase short codes returned by GET /v1/public/countries — for example bh (Bahrain), sa (Saudi Arabia), ae (United Arab Emirates). Always fetch the list from the public endpoint rather than hardcoding IDs — the supported list can change. Do not use uppercase ISO codes or 3-letter codes; they will be rejected.

FieldSourceImmutable After Creation
residency_idGET /v1/public/countriesNo
citizenship_idGET /v1/public/countriesNo
place_of_birth_idGET /v1/public/countriesYes

If the country is not supported or unsupported for the given field, creation or update fails:

Error CodeTrigger
2022residency_id is not a supported country
2023citizenship_id is not a supported country
2024place_of_birth_id is not a supported country (creation only — field is immutable)

Residency Visa

When the client's residency country differs from their citizenship country, you must also submit their residency visa details:

  • residency_visa_number — residency visa document number
  • residency_visa_doe — residency visa expiry date (YYYY-MM-DD)

Missing visa details when required returns error 2025Residency visa number and expiry are required.


Trading Volume & Account Purpose

Two compliance-related fields are required on every client create and update:

trading_volume

A string representing the client's expected monthly trading volume. Although the field accepts any string, you should submit one of CoinMENA's recommended volume brackets to align with the compliance model — e.g. 1000_10000, 10001_25000, 25001_100000.

See the API Reference for the full list of recommended bracket values.

account_purpose

An array of one or more strings indicating what the client intends to use the account for. Accepted values:

ValueDescription
short_term_tradingShort-term crypto trading
long_term_investmentLong-term investment in digital assets
converting_crypto_to_fiatConverting existing crypto holdings to fiat
cross_border_transactionsSending or receiving cross-border payments

At least one value must be provided. Multiple values are allowed.


Documents

KYC documents are uploaded per client and are managed through a separate set of endpoints. Documents are part of the client lifecycle — upload the document types required by your setup with CoinMENA for each client you onboard. See the Onboarding a Client guide for the end-to-end walkthrough.

Supported Document Types

TypeDescription
government_idGovernment-issued ID (passport, national ID)
proof_of_addressUtility bill, bank statement, or similar
residency_visaResidency visa document
source_of_fundsDocumentation proving source of funds
bank_statementOfficial bank statement
inquiry_reportInquiry or background report

Upload Rules

  • Front file: required
  • Back file: optional — include for two-sided documents like national IDs
  • Accepted formats: JPEG, PNG, HEIC, HEIF, PDF
  • Maximum size: 5 MB per file

Presigned URLs for Download

When you retrieve a document via GET /v1/partner/clients/{partner_client_id}/documents/{document_id}, the response contains presigned S3 URLs in front_file and back_file. These URLs:

  • Are signed and scoped to the document
  • Expire after 900 seconds (15 minutes)
  • Should be fetched on-demand — do not store the URLs in your database

If a presigned URL expires, re-request the document metadata to get a fresh URL.

Filtering

List documents for a client with GET /v1/partner/clients/{partner_client_id}/documents. The type query parameter accepts multiple values, so you can narrow results to one or several document types in a single request.


Validation Errors (422)

When a create or update request fails schema validation, the API returns 422 with a msg_detail array listing every field-level failure:

{
  "code": 422,
  "msg": "Validation Error",
  "msg_detail": [
    {
      "loc": ["body", "email"],
      "msg": "Input should be a valid email",
      "type": "email_parsing"
    },
    {
      "loc": ["body", "address", "street"],
      "msg": "Field required",
      "type": "missing"
    }
  ]
}

Use the loc array to identify the exact field that failed — it reflects the nested path of the field in your request body. See the Error Codes guide for the full 422 reference.


Common Mistakes

The most frequent issues partners hit when creating or updating clients:

MistakeFix
Submitting uppercase or 3-letter country codesUse the lowercase short codes returned by GET /v1/public/countries (e.g. bh, not BH or BHR)
Treating update as a partial PATCHRe-send the full payload on every update — missing required fields will fail validation
Submitting account_type: corporate on createOnly personal is creatable via the API. Contact CoinMENA for corporate onboarding
Sending account_type, birth_date, or place_of_birth_id on updateThese fields are immutable — strip them from the update payload
Reusing a partner_client_id for a different clientEach partner_client_id must be unique per partner. Duplicates return 2026
Missing residency_visa_number or residency_visa_doe when residency ≠ citizenshipSubmit both fields when the client's residency and citizenship differ — missing them returns 2025
Sending job_level for a self_employed statusjob_level is not allowed for self_employed — see the Employment validation table
Forgetting one of the four address subfieldsstreet, city, postal_code, and unit are all required — missing any returns a 422
Using splits like first_name / last_nameThe API uses a single name field with the client's full legal name

Where Clients Are Used

The partner_client_id is the link between a client and every downstream operation. A client is required for:

  • Balances — retrieve partner_client_id-scoped asset balances
  • Quotes — calculate a trade quote on behalf of a client
  • Orders — execute a quote and retrieve the resulting order
  • Deposits — credit fiat to a client's account
  • Withdrawals — debit fiat from a client's account
  • Documents — upload and retrieve KYC documents for a client

If the client is deactivated (active: false) or not yet verified, these downstream operations return 2010 or 2009 respectively.


Related Error Codes

The most common client-related errors:

CodeTrigger
2008Invalid client ID — client not found under your partner account
2009The client is not yet verified
2010The client is deactivated
2016Government ID is already being used by another approved client
2021Client is under the legal age
2022Invalid residency country
2023Invalid citizenship country
2024Invalid place of birth country
2025Residency visa number and expiry are required
2026A client with this partner_client_id already exists
2027A client with this email already exists
2028A client with this phone already exists

See the Error Codes guide for the full reference, including HTTP status codes and affected endpoints.



What’s Next
Next StepDescription
TradingAsset pairs, quotes, and how to execute trades on behalf of a client
FundingDeposit and withdraw fiat balances for your clients
Error CodesFull reference for every error the API returns