Onboarding a Client
End-to-end walkthrough for onboarding a new client on CoinMENA — from creation to optional document upload and final verification. Follow the steps in order.
This guide walks you through onboarding a single client from scratch. By the end, you will have a verified, active client under your partner account with all required KYC documents on file, ready to be funded and to trade.
For the concepts behind the client object, KYC status, and validation rules, see the Clients guide.
What You Will Have at the End
- A client record under your partner account with
status: verifiedandactive: true - A
partner_client_idyou control, used in every future call for this client - The required KYC documents uploaded and on file for the client
- A client ready to be funded and to trade — no additional activation step required
Before You Start
You need the following in place before running any of the calls below.
Prerequisites checklist
- You have your Partner ID (provided by CoinMENA after your account is created)
- You have your Ed25519 private key, and your public key has already been shared with CoinMENA
- You can generate request signatures using the method described in the Authentication guide
- You know which country IDs are supported — fetch them from
GET /v1/public/countries(IDs are lowercase short codes likebh,sa,ae) - You have the KYC documents ready for the client — your onboarding with CoinMENA defines which document types are required
Environment and signing
| Item | Details |
|---|---|
| Environment | Production: https://external-api.coinmena.comSandbox: contact [email protected] for credentials |
| Signed headers | All signed requests need X-Partner-ID, X-Timestamp, and X-Signature. See the Authentication guide to generate them |
Placeholders in the cURL examplesReplace
your_partner_idwith your actual Partner ID, and<your_generated_signature>with the Base64 signature you compute per the Authentication guide. Every request below needs its own fresh timestamp and signature.
The Flow at a Glance
Onboarding is a three-step flow. Complete all three steps in order for every client.
- Create the client → receive the client record, persist your
partner_client_id - Upload the required KYC documents → upload every document type CoinMENA requires for this client
- Confirm the client is ready → fetch the client and verify
status: verified+active: true
All onboarding operations are synchronousEvery step below returns a final response. There is no pending or async state — if the API returns a success response, the operation is complete and the change is effective immediately.
Step 1 — Create the Client
Submit the client's details to POST /v1/partner/clients. All required fields must be present — the API rejects partial payloads.
curl -X POST "https://external-api.coinmena.com/v1/partner/clients" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654321000" \
-H "X-Signature: <your_generated_signature>" \
-H "Content-Type: application/json" \
-d '{
"partner_client_id": "user_12345",
"account_type": "personal",
"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"]
}'Response — 201 Created
201 Created{
"result": {
"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"
}
}What to Persist
Store these fields on your side — they are what you need for every future call involving this client:
| Field | Why You Need It |
|---|---|
partner_client_id | Your reference ID. Used in every client-scoped endpoint path |
id | CoinMENA's internal numeric ID. Useful as a secondary reference |
status | Should be verified on creation. Re-check later if a flow depends on it |
active | Should be true on creation. Toggle via the activation endpoint if needed |
created_at | Useful for your own audit and reporting |
Uniqueness rules — what makes creation failThe following fields must be unique across your partner account. Reusing a value returns a specific error:
partner_client_id→20262027phone→2028government_id_number→2016The API does not return the existing client on a duplicate — it rejects the request. If you suspect a duplicate was intentional, fetch the existing client via
GET /v1/partner/clients/{partner_client_id}/.
Three fields are immutable after creation
account_type,birth_date, andplace_of_birth_idcannot be changed later. Double-check these values before sending the request. If any are wrong after creation, contact [email protected].
Step 2 — Upload the Required KYC Documents
Upload every KYC document type required by your onboarding with CoinMENA. The document upload endpoint accepts multipart/form-data. Front file is required; back file is optional (include it for two-sided documents such as national IDs).
The example below shows uploading a government_id. Repeat this call for each document type CoinMENA requires for the client — for example, you may also need to upload proof_of_address, residency_visa, source_of_funds, or others depending on your onboarding setup.
curl -X POST "https://external-api.coinmena.com/v1/partner/clients/user_12345/documents" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654322000" \
-H "X-Signature: <your_generated_signature>" \
-F "type=government_id" \
-F "front_file=@/path/to/id_front.jpg" \
-F "back_file=@/path/to/id_back.jpg"Response — 201 Created
201 Created{
"result": {
"id": 1001,
"type": "government_id",
"front_file": "https://s3.me-south-1.amazonaws.com/private-bucket/clients/12345/government_id/abc.jpg?X-Amz-Expires=900&X-Amz-Signature=...",
"back_file": "https://s3.me-south-1.amazonaws.com/private-bucket/clients/12345/government_id/def.jpg?X-Amz-Expires=900&X-Amz-Signature=...",
"created_at": "2024-06-01T10:01:00Z"
}
}
Presigned URLs expire after 900 secondsThe
front_fileandback_fileURLs in the response are presigned S3 URLs valid for 15 minutes. Do not store them — fetch the document metadata again when you need fresh URLs.
Supported Document Types
| Type | Description |
|---|---|
government_id | Government-issued ID (passport, national ID) |
proof_of_address | Utility bill, bank statement, or similar |
residency_visa | Residency visa document |
source_of_funds | Documentation proving source of funds |
bank_statement | Official bank statement |
inquiry_report | Inquiry or background report |
Accepted formats: JPEG, PNG, HEIC, HEIF, PDF. Maximum 5 MB per file.
Verify the Uploads
After uploading, you can list the documents attached to the client to confirm all required types are on file:
curl -X GET "https://external-api.coinmena.com/v1/partner/clients/user_12345/documents" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654323000" \
-H "X-Signature: <your_generated_signature>"The response lists every document currently on file for the client with its type, id, and presigned URLs.
Step 3 — Confirm the Client Is Ready
Fetch the client to confirm the record exists and the two flags you care about are set correctly. This is a sanity check — the GET call does not trigger any state change.
curl -X GET "https://external-api.coinmena.com/v1/partner/clients/user_12345/" \
-H "X-Partner-ID: your_partner_id" \
-H "X-Timestamp: 1737654324000" \
-H "X-Signature: <your_generated_signature>"Response — 200 OK
200 OK{
"result": {
"id": 12345,
"partner_client_id": "user_12345",
"status": "verified",
"active": true,
"name": "John Doe",
"email": "[email protected]"
}
}Check both of the following on the returned record:
status: "verified"— the client is verified and allowed to transactactive: true— the client is not deactivated
When both conditions hold, onboarding is complete. The client is ready for funding (see the Funding & Reconciliation guide) and trading (see the Executing a Trade guide).
What Can Go Wrong
The most common errors during onboarding and what to do about them.
| Error | Code | Likely Cause | Fix |
|---|---|---|---|
| Client is under the legal age | 2021 | birth_date is below the jurisdiction's legal age | Verify the date of birth before submitting |
| Invalid residency / citizenship / place-of-birth country | 2022 / 2023 / 2024 | Country ID not supported, or not accepted for that field | Use a country ID from GET /v1/public/countries. IDs are lowercase |
| Residency visa number and expiry are required | 2025 | Residency country differs from citizenship but visa details are missing | Submit both residency_visa_number and residency_visa_doe |
Duplicate partner_client_id | 2026 | The reference ID is already used under your partner account | Use a new unique reference |
| Duplicate government ID / email / phone | 2016 / 2027 / 2028 | Another client already has this value | Verify the duplicate is intentional, otherwise use different values |
| Validation error | 422 | A required field is missing or has the wrong format | Inspect msg_detail to find the failing field, then fix it |
| Invalid client ID on document upload | 2008 | partner_client_id in the URL does not match a client under your partner account | Verify you are using the same partner_client_id you set on creation |
| Unauthorized | 401 | Bad signature, expired timestamp, or IP not whitelisted | Work through the Authentication troubleshooting checklist |
For the complete list, see the Error Codes guide.
Updated 1 day ago
| Next Step | Description |
|---|---|
| Funding & Reconciliation | Fund the client so they can trade |
| Executing a Trade | Run the client's first trade end-to-end |
| Clients | Full reference for the client object, validation rules, and documents |
