> For the complete documentation index, see [llms.txt](https://developers.unigox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.unigox.com/api-reference/user-management.md).

# User Management

Endpoints to create and manage user accounts

## Verify API key authentication

> Verifies that the provided API key is valid and authentication is working correctly.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}},"ErrorResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["error_key"],"properties":{"error_key":{"type":"string","description":"Standardized error key for client error handling"}}}}}}},"paths":{"/api/v1/partner/verify-auth":{"get":{"tags":["User Management"],"summary":"Verify API key authentication","description":"Verifies that the provided API key is valid and authentication is working correctly.\n","operationId":"verifyAuth","responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"},"authenticated":{"type":"boolean"}}}}}]}}}},"401":{"description":"Unauthorized - invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```

## Create or get partner user

> Creates a new user relation or returns existing if already created. Returns user\_ref (same as input) for subsequent API calls. Partners can only access their own users.\
> \
> Each partner user must represent one actual payout beneficiary/end customer. Create a separate partner user for each beneficiary. Do not attach payment details for unrelated people to the same \`user\_uuid\`; third-party payouts are not supported.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"CreateUserResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"user_uuid":{"type":"string","format":"uuid","description":"Public UUID of the user. Use this value in all subsequent API calls."},"email":{"type":"string","format":"email"},"kyc_status":{"type":"string","enum":["NOT_INITIATED","IN_PROGRESS","UNDER_REVIEW","VERIFIED","VERIFICATION_REJECTED"]},"created_at":{"type":"string","format":"date-time"}}}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}}}},"paths":{"/api/v1/partner/users":{"post":{"tags":["User Management"],"summary":"Create or get partner user","description":"Creates a new user relation or returns existing if already created. Returns user_ref (same as input) for subsequent API calls. Partners can only access their own users.\n\nEach partner user must represent one actual payout beneficiary/end customer. Create a separate partner user for each beneficiary. Do not attach payment details for unrelated people to the same `user_uuid`; third-party payouts are not supported.\n","operationId":"createPartnerUser","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["user_ref","email"],"properties":{"user_ref":{"type":"string","description":"Partner's unique user ID (usually primary key or UUID)"},"email":{"type":"string","format":"email","description":"User's email address"}}}}}},"responses":{"200":{"description":"User already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserResponse"}}}},"201":{"description":"Successfully created user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserResponse"}}}},"400":{"description":"Bad Request"},"401":{"description":"Unauthorized (missing or invalid X-API-Key)"},"500":{"description":"Internal Server Error"}}}}}}
```

## Partner user by ID

> Get user details including KYC status and payment profiles using the user\_uuid returned during user creation. Partners can only access their own users.

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"GetUserResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"user_uuid":{"type":"string","format":"uuid","description":"Public UUID of the user. Use this value in all subsequent API calls."},"email":{"type":"string","format":"email"},"created_at":{"type":"string","format":"date-time"},"kyc":{"type":"object","properties":{"status":{"type":"string","enum":["NOT_INITIATED","IN_PROGRESS","UNDER_REVIEW","VERIFIED","VERIFICATION_REJECTED"],"description":"Current partner-facing KYC status. `UNDER_REVIEW` means the customer is under\nmanual compliance review — not yet cleared, and unlike `IN_PROGRESS` (automated,\nusually a couple of minutes) it can take up to 24 hours. The internal review\nstate name is never exposed.\n"},"kyc_method":{"type":"string","enum":["direct_data","external_token","handoff"],"description":"KYC submission method used"},"first_name":{"type":"string","description":"User's first name from KYC data"},"last_name":{"type":"string","description":"User's last name from KYC data"},"country_code":{"type":"string","description":"User's country code (ISO 2-letter) from KYC data"},"rejection_reason":{"type":"string","nullable":true,"description":"Reason for KYC rejection (if status is VERIFICATION_REJECTED)"},"updated_at":{"type":"string","format":"date-time","description":"Last update timestamp for KYC status"}}},"payment_profiles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"rail":{"type":"string"},"currency":{"type":"string"},"institution_name":{"type":"string","nullable":true},"institution_id":{"type":"string","nullable":true,"description":"Institution identifier (our internal slug)"},"details":{"type":"object","additionalProperties":true}}}}}}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}}}},"paths":{"/api/v1/partner/users/{user_uuid}":{"get":{"tags":["User Management"],"summary":"Partner user by ID","description":"Get user details including KYC status and payment profiles using the user_uuid returned during user creation. Partners can only access their own users.","operationId":"getPartnerUser","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetUserResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"}}}}}}
```

## Submit KYC data for a partner user

> Submit KYC (Know Your Customer) data for a partner user. Supports three methods:\
> \- direct\_data: Partner submits PII data directly, user is verified\
> \- external\_token: Partner provides external KYC provider credentials (SumSub token or Persona inquiry\_id)\
> \- handoff: Unigox handles KYC verification and generates verification URL\
> \
> \*\*Important for EUR/AUD/GBP off-ramp:\*\* EUR, AUD, and GBP payouts require the user's\
> physical address. Include \`address\`, \`city\`, and \`postal\_code\` in the PII data\
> when submitting KYC. If not provided at submission time, you can add them later with\
> \`PATCH /partner/users/{user\_uuid}/kyc\`. Without address, EUR/AUD/GBP orders will be created\
> with status \`pending\_address\` until the address is provided.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"KYCSubmitDirectData":{"type":"object","required":["method","data"],"properties":{"method":{"type":"string","enum":["direct_data"]},"data":{"type":"object","required":["pii"],"properties":{"pii":{"type":"object","required":["first_name","last_name","country_code"],"properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"country_code":{"type":"string"},"dob":{"type":"string","format":"date","description":"Date of birth (YYYY-MM-DD). Optional, but when provided it must be a real date in the past and indicate an age of at least 18. A future, malformed, or under-18 date is rejected with HTTP 400 (see error responses below)."},"middle_name":{"type":"string"},"phone_number":{"type":"string","description":"E.164 format"},"id_number":{"type":"string","description":"Government identity/registry number. Enables the **NIN/BVN + selfie** verification option: instead of uploading an ID-document image, the customer proves identity with this number plus a live selfie (no ID photo). AiPrise validates the number against the national registry (NIN->NIMC, BVN->NIBSS) and face-matches the selfie against the registry photo. After this submission, upload only a `selfie` (document_type=selfie) to the documents endpoint - verification starts automatically. Supported for the registry number types listed under `id_type`, in the countries those registries cover."},"id_type":{"type":"string","description":"Registry type for `id_number`. For the NIN/BVN + selfie option it must be one of the listed registry types (image-only IDs such as passport/driver licence are NOT accepted - those use the ID-image flow). An unsupported/missing value returns `400 { \"error_key\": \"invalid_identity_number_type\" }`.","enum":["NIN","NIN_SLIP","BVN","NATIONAL_ID","VOTER_ID","TAX_ID","KENYA_KRA_PIN"]},"address":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City. Required for EUR/AUD/GBP offramp (auto-populates into payment details)."},"postal_code":{"type":"string"}}}}}}},"KYCSubmitExternalToken":{"type":"object","required":["method","data"],"properties":{"method":{"type":"string","enum":["external_token"]},"data":{"type":"object","required":["provider"],"description":"Provider-specific fields:\n- SumSub: requires `token` (SumSub share token)\n- Persona: requires `inquiry_id` (Persona inquiry ID, e.g. inq_xxx)\n","properties":{"provider":{"type":"string","enum":["sumsub","persona"],"description":"KYC provider name"},"token":{"type":"string","description":"SumSub share token (required when provider=sumsub)"},"inquiry_id":{"type":"string","description":"Persona inquiry ID (required when provider=persona). This is the inq_xxx identifier returned by Persona when the inquiry was created."}}}}},"KYCSubmitHandoff":{"type":"object","required":["method","data"],"properties":{"method":{"type":"string","enum":["handoff"]},"data":{"type":"object","properties":{"pii":{"type":"object","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"country_code":{"type":"string"}}}}}}},"KYCSubmitResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"kyc_status":{"type":"string","enum":["NOT_INITIATED","IN_PROGRESS","UNDER_REVIEW","VERIFIED","VERIFICATION_REJECTED"],"description":"A submission may asynchronously move to `UNDER_REVIEW` (manual compliance review,\nup to 24 hours) via the status endpoint and the `user.kyc.updated` webhook — distinct\nfrom `IN_PROGRESS` (automated, usually a couple of minutes). Treat both as not cleared.\n"},"message":{"type":"string"},"verification_url":{"type":"string","format":"uri","nullable":true,"description":"Verification URL (only returned for handoff method)"}}}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}},"ErrorResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["error_key"],"properties":{"error_key":{"type":"string","description":"Standardized error key for client error handling"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/kyc-submissions":{"post":{"tags":["User Management"],"summary":"Submit KYC data for a partner user","description":"Submit KYC (Know Your Customer) data for a partner user. Supports three methods:\n- direct_data: Partner submits PII data directly, user is verified\n- external_token: Partner provides external KYC provider credentials (SumSub token or Persona inquiry_id)\n- handoff: Unigox handles KYC verification and generates verification URL\n\n**Important for EUR/AUD/GBP off-ramp:** EUR, AUD, and GBP payouts require the user's\nphysical address. Include `address`, `city`, and `postal_code` in the PII data\nwhen submitting KYC. If not provided at submission time, you can add them later with\n`PATCH /partner/users/{user_uuid}/kyc`. Without address, EUR/AUD/GBP orders will be created\nwith status `pending_address` until the address is provided.\n","operationId":"submitKYC","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/KYCSubmitDirectData"},{"$ref":"#/components/schemas/KYCSubmitExternalToken"},{"$ref":"#/components/schemas/KYCSubmitHandoff"}]}}}},"responses":{"200":{"description":"KYC submitted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KYCSubmitResponse"}}}},"400":{"description":"Bad Request — invalid method, missing required data, or a date of birth that fails validation. The response body is `{ \"success\": false, \"data\": { \"error_key\": \"...\", \"message\": \"...\" } }`. Possible `error_key` values include: `underage_not_allowed` — \"User must be at least 18 years old. The provided date_of_birth indicates an age under 18.\"; and `invalid_date_of_birth` — \"date_of_birth is invalid. Provide a real date in YYYY-MM-DD format that is in the past.\" `invalid_identity_number_type` — \"id_type is required for NIN/BVN + selfie verification and must be one of the supported identity number types (e.g. NIN, BVN).\"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"500":{"description":"Internal Server Error"}}}}}}
```

## Upload KYC document for a partner user

> Upload a KYC document for a partner user. Choose one of two upload methods:\
> \
> \---\
> \
> \### Method 1: File Upload\
> Send the document as a file attachment.\
> \`\`\`\
> POST /api/v1/partner/users/{user\_uuid}/kyc/documents\
> Content-Type: multipart/form-data\
> \
> document: \<file>\
> document\_type: identity\_front\
> \`\`\`\
> \
> \### Method 2: Single URL Upload\
> Send a URL pointing to one document image.\
> \`\`\`json\
> {\
> &#x20; "upload\_method": "url\_link",\
> &#x20; "document\_type": "identity\_front",\
> &#x20; "url": "<https://example.com/id-front.jpg"\\>
> }\
> \`\`\`\
> \
> \### Method 3: Batch URL Upload\
> Upload multiple documents in one call (up to 10).\
> \`\`\`json\
> {\
> &#x20; "upload\_method": "url\_link",\
> &#x20; "documents": \[\
> &#x20;   { "document\_type": "identity\_front", "url": "<https://example.com/id-front.jpg>" },\
> &#x20;   { "document\_type": "selfie", "url": "<https://example.com/selfie.jpg>" }\
> &#x20; ]\
> }\
> \`\`\`\
> \
> \*\*URL requirements:\*\* HTTPS only, 10MB per file, JPEG/PNG/GIF/PDF.\
> \
> \---\
> \
> \*\*Supported \`document\_type\` values\*\* — the API accepts exactly the following (this is the\
> complete, finite list; anything else is rejected). \*\*Required:\*\* a \`selfie\` \*\*and\*\* one\
> identity-document front (\`identity\_front\` or any equivalent ID type listed below). All other\
> values are optional (document back sides and alternative ID types).\
> \
> \*\*NIN/BVN + selfie option (verify with a registry number instead of an ID image).\*\* This is a\
> \*\*two-step flow across two endpoints\*\* — the registry number is submitted as \*\*text\*\*, never\
> uploaded as a file:\
> \
> &#x20; 1\. On the \*\*submit-KYC\*\* endpoint (\`POST .../kyc-submissions\`, method \`direct\_data\`), send the\
> &#x20;    customer's data \*\*plus\*\* \`id\_number\` (the registry number, as a string) and \`id\_type\`\
> &#x20;    (e.g. \`NIN\`, \`BVN\`). No image is uploaded in this step.\
> &#x20; 2\. On \*\*this\*\* documents endpoint, upload \*\*only a \`selfie\`\*\* (\`document\_type: selfie\`) — \*\*no\
> &#x20;    ID-document image\*\*. The registry number from step 1 satisfies the identity requirement, so\
> &#x20;    verification starts automatically (national-registry lookup + selfie face-match against the\
> &#x20;    registry photo).\
> \
> The three upload methods below (multipart / single URL / batch URL) are for \*\*image files\*\* only\
> — they are not how the registry number is sent (that is the \`id\_number\` text field in step 1).\
> \
> \`document\_type\` only selects which slot (front / back / selfie) an image occupies. It is \*\*not\*\*\
> used as a document-category and it does \*\*not\*\* set the country: our verification system detects\
> the actual document type from the image, and the country is taken from the customer's KYC profile\
> (their identity/address country), independent of this value. The country names below are naming\
> hints to help you choose — they are not enforced, so a country-specific value is never required.\
> \
> \- Generic identity document — \*\*general\*\* (any country): \`identity\_front\`, \`identity\_back\`\
> \- Passport — \*\*general\*\* (any country): \`passport\`, \`passport\_front\`\
> \- National ID — \*\*general\*\* (any country; covers e.g. Nigeria's NIN card, Kenya national ID,\
> &#x20; India Aadhaar): \`national\_id\`, \`national\_id\_front\`, \`national\_id\_back\`\
> \- Driver license — \*\*general\*\* (any country): \`driver\_license\`, \`driver\_license\_front\`, \`driver\_license\_back\`\
> \- Voter ID — \*\*general\*\* (any country): \`voter\_id\`, \`voter\_id\_front\`, \`voter\_id\_back\`\
> \- Resident card — \*\*general\*\* (any country): \`resident\_card\`, \`resident\_card\_front\`, \`resident\_card\_back\`\
> \- ID card — \*\*general\*\* (any country; catch-all for local cards without their own type below,\
> &#x20; e.g. Indonesia KTP, Pakistan Nadra Card): \`id\_card\`, \`id\_card\_front\`, \`id\_card\_back\`\
> \- Ghana card — \*\*Ghana\*\* (NIA biometric national ID): \`ghana\_card\`, \`ghana\_card\_front\`, \`ghana\_card\_back\`\
> \- Ghana SSNIT card — \*\*Ghana\*\* (social-security card): \`ghana\_ssnit\_card\`, \`ghana\_ssnit\_card\_front\`, \`ghana\_ssnit\_card\_back\`\
> \- Kenya alien card — \*\*Kenya\*\* (non-citizen resident ID): \`kenya\_alien\_card\`, \`kenya\_alien\_card\_front\`, \`kenya\_alien\_card\_back\`\
> \- Green book — \*\*South Africa\*\* (legacy green barcoded ID book): \`green\_book\`, \`green\_book\_front\`, \`green\_book\_back\`\
> \- Tax ID — \*\*general\*\* label (primary example: India PAN card): \`tax\_id\`, \`tax\_id\_front\`, \`tax\_id\_back\`\
> \- Colombia PPT — \*\*Colombia\*\* (Permiso por Protección Temporal): \`colombia\_ppt\`, \`colombia\_ppt\_front\`, \`colombia\_ppt\_back\`\
> \- Selfie — \*\*general\*\* (any country): \`selfie\`\
> \
> Any front-side identity type above (e.g. \`passport\`, \`national\_id\`, \`tax\_id\`) satisfies the ID\
> requirement — not only the literal \`identity\_front\`. \*\*Nigeria's NIN\*\* is submitted as\
> \`national\_id\` (with the customer's country set to Nigeria); there is no separate \`nin\` value.\
> \
> \*\*Automatic Verification:\*\* After an identity document + \`selfie\` + KYC data are present, the\
> service queues verification processing and returns immediately. The identity document can be\
> any accepted ID type above, not only \`identity\_front\` (e.g. \`passport\` + \`selfie\` triggers\
> verification). A \`200\` response means the documents were accepted; it is not a final\
> verification result. Asynchronous verification checks can move the user to\
> \`VERIFICATION\_REJECTED\` after this response.\
> \
> To trigger verification explicitly, or to check exactly what is still missing, call\
> \`POST /api/v1/partner/users/{user\_uuid}/kyc/verify\` (below).\
> \
> Obtain the eventual outcome by polling\
> \`GET /api/v1/partner/users/{user\_uuid}/verification-status\` or consuming the\
> \`user.kyc.updated\` webhook. The upload response does not include a verification session ID\
> or \`kyc\_status\`, because asynchronous state can change immediately after acceptance.<br>

````json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"KycDocumentType":{"type":"string","description":"Complete set of document types accepted by the partner KYC upload endpoint. `document_type` only selects the upload slot (front/back/selfie); it is not a document-category and does not set the country — our verification system detects the document type from the image, and the country comes from the customer's KYC profile. Values named after a country (`ghana_card`, `ghana_ssnit_card`, `kenya_alien_card`, `green_book`, `colombia_ppt`) are country-specific hints; all others (`passport`, `national_id`, `driver_license`, `voter_id`, `resident_card`, `id_card`, `tax_id`, `identity_front`/`identity_back`, `selfie`) are general — any country. Nigeria's NIN is submitted as `national_id`.","enum":["identity_front","identity_back","selfie","passport","passport_front","national_id","national_id_front","national_id_back","driver_license","driver_license_front","driver_license_back","voter_id","voter_id_front","voter_id_back","resident_card","resident_card_front","resident_card_back","id_card","id_card_front","id_card_back","ghana_card","ghana_card_front","ghana_card_back","ghana_ssnit_card","ghana_ssnit_card_front","ghana_ssnit_card_back","kenya_alien_card","kenya_alien_card_front","kenya_alien_card_back","green_book","green_book_front","green_book_back","tax_id","tax_id_front","tax_id_back","colombia_ppt","colombia_ppt_front","colombia_ppt_back"]}}},"paths":{"/api/v1/partner/users/{user_uuid}/kyc/documents":{"post":{"tags":["User Management"],"summary":"Upload KYC document for a partner user","description":"Upload a KYC document for a partner user. Choose one of two upload methods:\n\n---\n\n### Method 1: File Upload\nSend the document as a file attachment.\n```\nPOST /api/v1/partner/users/{user_uuid}/kyc/documents\nContent-Type: multipart/form-data\n\ndocument: <file>\ndocument_type: identity_front\n```\n\n### Method 2: Single URL Upload\nSend a URL pointing to one document image.\n```json\n{\n  \"upload_method\": \"url_link\",\n  \"document_type\": \"identity_front\",\n  \"url\": \"https://example.com/id-front.jpg\"\n}\n```\n\n### Method 3: Batch URL Upload\nUpload multiple documents in one call (up to 10).\n```json\n{\n  \"upload_method\": \"url_link\",\n  \"documents\": [\n    { \"document_type\": \"identity_front\", \"url\": \"https://example.com/id-front.jpg\" },\n    { \"document_type\": \"selfie\", \"url\": \"https://example.com/selfie.jpg\" }\n  ]\n}\n```\n\n**URL requirements:** HTTPS only, 10MB per file, JPEG/PNG/GIF/PDF.\n\n---\n\n**Supported `document_type` values** — the API accepts exactly the following (this is the\ncomplete, finite list; anything else is rejected). **Required:** a `selfie` **and** one\nidentity-document front (`identity_front` or any equivalent ID type listed below). All other\nvalues are optional (document back sides and alternative ID types).\n\n**NIN/BVN + selfie option (verify with a registry number instead of an ID image).** This is a\n**two-step flow across two endpoints** — the registry number is submitted as **text**, never\nuploaded as a file:\n\n  1. On the **submit-KYC** endpoint (`POST .../kyc-submissions`, method `direct_data`), send the\n     customer's data **plus** `id_number` (the registry number, as a string) and `id_type`\n     (e.g. `NIN`, `BVN`). No image is uploaded in this step.\n  2. On **this** documents endpoint, upload **only a `selfie`** (`document_type: selfie`) — **no\n     ID-document image**. The registry number from step 1 satisfies the identity requirement, so\n     verification starts automatically (national-registry lookup + selfie face-match against the\n     registry photo).\n\nThe three upload methods below (multipart / single URL / batch URL) are for **image files** only\n— they are not how the registry number is sent (that is the `id_number` text field in step 1).\n\n`document_type` only selects which slot (front / back / selfie) an image occupies. It is **not**\nused as a document-category and it does **not** set the country: our verification system detects\nthe actual document type from the image, and the country is taken from the customer's KYC profile\n(their identity/address country), independent of this value. The country names below are naming\nhints to help you choose — they are not enforced, so a country-specific value is never required.\n\n- Generic identity document — **general** (any country): `identity_front`, `identity_back`\n- Passport — **general** (any country): `passport`, `passport_front`\n- National ID — **general** (any country; covers e.g. Nigeria's NIN card, Kenya national ID,\n  India Aadhaar): `national_id`, `national_id_front`, `national_id_back`\n- Driver license — **general** (any country): `driver_license`, `driver_license_front`, `driver_license_back`\n- Voter ID — **general** (any country): `voter_id`, `voter_id_front`, `voter_id_back`\n- Resident card — **general** (any country): `resident_card`, `resident_card_front`, `resident_card_back`\n- ID card — **general** (any country; catch-all for local cards without their own type below,\n  e.g. Indonesia KTP, Pakistan Nadra Card): `id_card`, `id_card_front`, `id_card_back`\n- Ghana card — **Ghana** (NIA biometric national ID): `ghana_card`, `ghana_card_front`, `ghana_card_back`\n- Ghana SSNIT card — **Ghana** (social-security card): `ghana_ssnit_card`, `ghana_ssnit_card_front`, `ghana_ssnit_card_back`\n- Kenya alien card — **Kenya** (non-citizen resident ID): `kenya_alien_card`, `kenya_alien_card_front`, `kenya_alien_card_back`\n- Green book — **South Africa** (legacy green barcoded ID book): `green_book`, `green_book_front`, `green_book_back`\n- Tax ID — **general** label (primary example: India PAN card): `tax_id`, `tax_id_front`, `tax_id_back`\n- Colombia PPT — **Colombia** (Permiso por Protección Temporal): `colombia_ppt`, `colombia_ppt_front`, `colombia_ppt_back`\n- Selfie — **general** (any country): `selfie`\n\nAny front-side identity type above (e.g. `passport`, `national_id`, `tax_id`) satisfies the ID\nrequirement — not only the literal `identity_front`. **Nigeria's NIN** is submitted as\n`national_id` (with the customer's country set to Nigeria); there is no separate `nin` value.\n\n**Automatic Verification:** After an identity document + `selfie` + KYC data are present, the\nservice queues verification processing and returns immediately. The identity document can be\nany accepted ID type above, not only `identity_front` (e.g. `passport` + `selfie` triggers\nverification). A `200` response means the documents were accepted; it is not a final\nverification result. Asynchronous verification checks can move the user to\n`VERIFICATION_REJECTED` after this response.\n\nTo trigger verification explicitly, or to check exactly what is still missing, call\n`POST /api/v1/partner/users/{user_uuid}/kyc/verify` (below).\n\nObtain the eventual outcome by polling\n`GET /api/v1/partner/users/{user_uuid}/verification-status` or consuming the\n`user.kyc.updated` webhook. The upload response does not include a verification session ID\nor `kyc_status`, because asynchronous state can change immediately after acceptance.\n","operationId":"uploadPartnerKYCDocument","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"Public UUID of the user","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["document","document_type"],"properties":{"document":{"type":"string","format":"binary","description":"Document file (JPEG, PNG, GIF, or PDF, max 10MB)"},"document_type":{"$ref":"#/components/schemas/KycDocumentType"}}}},"application/json":{"schema":{"oneOf":[{"title":"Single URL Upload","description":"Upload one document by providing an HTTPS URL.","type":"object","required":["upload_method","document_type","url"],"properties":{"upload_method":{"type":"string","enum":["url_link"]},"document_type":{"$ref":"#/components/schemas/KycDocumentType"},"url":{"type":"string","format":"uri","description":"HTTPS URL of the image. 10MB max."}}},{"title":"Batch URL Upload","description":"Upload multiple documents in one call (up to 10).","type":"object","required":["upload_method","documents"],"properties":{"upload_method":{"type":"string","enum":["url_link"]},"documents":{"type":"array","maxItems":10,"items":{"type":"object","required":["document_type","url"],"properties":{"document_type":{"$ref":"#/components/schemas/KycDocumentType"},"url":{"type":"string","format":"uri"}}}}}}]}}}},"responses":{"200":{"description":"Documents accepted; verification starts asynchronously once all required documents are available","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"oneOf":[{"title":"Single document accepted","type":"object","required":["document_id","document_type","file_name","message"],"properties":{"document_id":{"type":"string","description":"Document identifier"},"document_type":{"type":"string"},"file_name":{"type":"string"},"message":{"type":"string","description":"Confirms that the document was accepted for processing."}}},{"title":"Batch documents accepted","type":"object","required":["uploaded","message"],"properties":{"uploaded":{"type":"array","items":{"type":"object","properties":{"document_type":{"type":"string"},"document_id":{"type":"string"},"file_name":{"type":"string"},"status":{"type":"string","enum":["uploaded"]}}}},"errors":{"type":"array","description":"Per-document failures, omitted when every document succeeds.","items":{"type":"object","properties":{"document_type":{"type":"string"},"error":{"type":"string"}}}},"message":{"type":"string"}}}]}}}}}},"400":{"description":"Bad Request - invalid file type, missing document, or user not ready for uploads"},"401":{"description":"Unauthorized"},"404":{"description":"User not found or no active KYC session"},"500":{"description":"Internal Server Error"}}}}}}
````

## Trigger KYC verification and check readiness

> Explicitly start KYC verification for a partner user on the \`direct\_data\` image flow, or check\
> what is still missing. Verification \*\*also\*\* starts automatically once an identity document +\
> selfie + KYC data are present (see the document upload endpoint) — this endpoint is an\
> explicit control and readiness check, not the only path. No request body.\
> \
> The response tells you the state:\
> \
> \- \*\*Ready, started:\*\* \`{ "ready": true, "status": "IN\_PROGRESS", "message": "Verification started." }\`.\
> &#x20; Idempotent — if a run is already in flight, the message is \`"Verification is already in progress."\`\
> &#x20; and no duplicate run is created.\
> \- \*\*Already verified:\*\* \`{ "ready": true, "status": "VERIFIED", "message": "User is already verified." }\`.\
> \- \*\*Not ready:\*\* \`{ "ready": false, "missing": \["identity\_document", "selfie"], "message": "..." }\`.\
> &#x20; The \`missing\` items are generic: \`identity\_document\` (any accepted ID type), \`selfie\`, \`kyc\_data\`.\
> \
> If the user has not submitted KYC with the \`direct\_data\` method yet, this returns \`400\` — submit\
> KYC via \`POST /api/v1/partner/users/{user\_uuid}/kyc-submissions\` first.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}}},"paths":{"/api/v1/partner/users/{user_uuid}/kyc/verify":{"post":{"tags":["User Management"],"summary":"Trigger KYC verification and check readiness","description":"Explicitly start KYC verification for a partner user on the `direct_data` image flow, or check\nwhat is still missing. Verification **also** starts automatically once an identity document +\nselfie + KYC data are present (see the document upload endpoint) — this endpoint is an\nexplicit control and readiness check, not the only path. No request body.\n\nThe response tells you the state:\n\n- **Ready, started:** `{ \"ready\": true, \"status\": \"IN_PROGRESS\", \"message\": \"Verification started.\" }`.\n  Idempotent — if a run is already in flight, the message is `\"Verification is already in progress.\"`\n  and no duplicate run is created.\n- **Already verified:** `{ \"ready\": true, \"status\": \"VERIFIED\", \"message\": \"User is already verified.\" }`.\n- **Not ready:** `{ \"ready\": false, \"missing\": [\"identity_document\", \"selfie\"], \"message\": \"...\" }`.\n  The `missing` items are generic: `identity_document` (any accepted ID type), `selfie`, `kyc_data`.\n\nIf the user has not submitted KYC with the `direct_data` method yet, this returns `400` — submit\nKYC via `POST /api/v1/partner/users/{user_uuid}/kyc-submissions` first.\n","operationId":"runPartnerKYCVerification","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"Public UUID of the user","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Readiness result. Either verification was triggered / is already running / the user is\nalready verified, or the user is not ready and `missing` lists what to provide.\n","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"ready":{"type":"boolean"},"status":{"type":"string","enum":["IN_PROGRESS","VERIFIED"],"description":"Present when `ready` is true."},"missing":{"type":"array","description":"Present when `ready` is false — the required items still to provide.","items":{"type":"string","enum":["identity_document","selfie","kyc_data"]}},"message":{"type":"string"}}}}}}}},"400":{"description":"Bad Request - the user has not submitted KYC with the direct_data method yet"},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"500":{"description":"Internal Server Error"}}}}}}
```

## Update KYC data for a partner user

> Update optional PII fields on existing KYC data. The user stays verified.\
> Only optional fields can be updated.\
> Required fields (first\_name, last\_name, country\_code) cannot be changed.\
> \
> For EUR/AUD/GBP offramp, provide address, city, and postal\_code here.\
> These will auto-populate into payment details for EUR/AUD/GBP payouts.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}}},"paths":{"/api/v1/partner/users/{user_uuid}/kyc":{"patch":{"tags":["User Management"],"summary":"Update KYC data for a partner user","description":"Update optional PII fields on existing KYC data. The user stays verified.\nOnly optional fields can be updated.\nRequired fields (first_name, last_name, country_code) cannot be changed.\n\nFor EUR/AUD/GBP offramp, provide address, city, and postal_code here.\nThese will auto-populate into payment details for EUR/AUD/GBP payouts.\n","operationId":"updateKYC","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City"},"postal_code":{"type":"string"},"dob":{"type":"string","format":"date","description":"Date of birth (YYYY-MM-DD). Must be in the past and indicate an age of at least 18; a future, malformed, or under-18 date is rejected with HTTP 400."},"phone_number":{"type":"string","description":"E.164 format"},"middle_name":{"type":"string"},"id_number":{"type":"string"},"id_type":{"type":"string","enum":["NATIONAL_ID","DRIVER_LICENSE","PASSPORT"]}}}}}},"responses":{"200":{"description":"KYC data updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"updated_fields":{"type":"array","items":{"type":"string"}},"message":{"type":"string"}}}}}}}},"400":{"description":"Bad request — no valid fields, attempting to change a required field, or a date of birth that fails validation. Body: `{ \"success\": false, \"data\": { \"error_key\": \"...\", \"message\": \"...\" } }`. DOB-related `error_key` values: `underage_not_allowed` (age under 18) and `invalid_date_of_birth` (malformed or future date)."},"401":{"description":"Unauthorized"},"404":{"description":"User not found"}}}}}}
```

## Verification status for a partner user

> Get the current verification status for a partner user. This endpoint returns the current status,\
> verification URL (if available), and other relevant information. Optionally, you can provide a\
> verification\_id to check a specific verification session.\
> \
> Status values:\
> \- \`NOT\_INITIATED\` — no verification started yet\
> \- \`PENDING\_DOCUMENTS\` — waiting for the customer to submit documents\
> \- \`IN\_PROGRESS\` — automated verification is underway (usually a couple of minutes)\
> \- \`UNDER\_REVIEW\` — under manual compliance review; the customer is being reviewed by our team\
> &#x20; and is NOT yet cleared. Unlike \`IN\_PROGRESS\` (automated, usually a couple of minutes), this can\
> &#x20; take up to 24 hours. Keep polling; treat as not cleared.\
> \- \`VERIFIED\` — verification passed; the customer is approved\
> \- \`FAILED\` — verification could not be completed due to an error\
> \- \`VERIFICATION\_REJECTED\` — verification completed with a rejection outcome\
> \
> Non-terminal states (\`NOT\_INITIATED\`, \`PENDING\_DOCUMENTS\`, \`IN\_PROGRESS\`, \`UNDER\_REVIEW\`) mean the\
> customer is not cleared yet — keep polling. A manual compliance review is now surfaced as the\
> friendly \`UNDER\_REVIEW\` (the internal review-state name is still never exposed) so you can tell a\
> long human review apart from a quick automated check and set the right expectation with your\
> customer.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"VerificationStatusResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string","enum":["NOT_INITIATED","PENDING_DOCUMENTS","IN_PROGRESS","UNDER_REVIEW","VERIFIED","FAILED","VERIFICATION_REJECTED"],"description":"Current verification status.\n\n- `NOT_INITIATED` — no verification started\n- `PENDING_DOCUMENTS` — awaiting customer document submission\n- `IN_PROGRESS` — automated verification underway (usually a couple of minutes); treat as not cleared yet\n- `UNDER_REVIEW` — under manual compliance review; the customer is being reviewed by our team and is NOT yet cleared. Unlike `IN_PROGRESS` (automated, usually a couple of minutes), this can take up to 24 hours. Keep polling; treat as not cleared.\n- `VERIFIED` — approved\n- `FAILED` — terminal error\n- `VERIFICATION_REJECTED` — completed with rejection\n"},"verification_url":{"type":"string","format":"uri","nullable":true,"description":"Verification URL (for handoff method)"},"verification_seconds_left":{"type":"integer","nullable":true,"description":"Seconds remaining for verification session (if applicable)"},"provider_messages":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Status messages or rejection reasons"}}}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/verification-status":{"get":{"tags":["User Management"],"summary":"Verification status for a partner user","description":"Get the current verification status for a partner user. This endpoint returns the current status,\nverification URL (if available), and other relevant information. Optionally, you can provide a\nverification_id to check a specific verification session.\n\nStatus values:\n- `NOT_INITIATED` — no verification started yet\n- `PENDING_DOCUMENTS` — waiting for the customer to submit documents\n- `IN_PROGRESS` — automated verification is underway (usually a couple of minutes)\n- `UNDER_REVIEW` — under manual compliance review; the customer is being reviewed by our team\n  and is NOT yet cleared. Unlike `IN_PROGRESS` (automated, usually a couple of minutes), this can\n  take up to 24 hours. Keep polling; treat as not cleared.\n- `VERIFIED` — verification passed; the customer is approved\n- `FAILED` — verification could not be completed due to an error\n- `VERIFICATION_REJECTED` — verification completed with a rejection outcome\n\nNon-terminal states (`NOT_INITIATED`, `PENDING_DOCUMENTS`, `IN_PROGRESS`, `UNDER_REVIEW`) mean the\ncustomer is not cleared yet — keep polling. A manual compliance review is now surfaced as the\nfriendly `UNDER_REVIEW` (the internal review-state name is still never exposed) so you can tell a\nlong human review apart from a quick automated check and set the right expectation with your\ncustomer.\n","operationId":"getVerificationStatus","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}},{"name":"verification_id","in":"query","required":false,"description":"Optional verification session ID. If not provided, the latest verification session for the user will be checked.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved verification status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"500":{"description":"Internal Server Error"}}}}}}
```

## Payment details for a partner user

> Retrieve all payment details (payment profiles) for a partner user. Returns all saved beneficiary details that can be used for offramp operations. Partners can only access their own users.

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"GetPaymentDetailsResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentProfile"},"description":"List of all payment profiles for the user"}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}},"PaymentProfile":{"type":"object","properties":{"payment_details_id":{"type":"string","description":"Payment details ID. Use this value in offramp/onramp quote requests."},"rail":{"type":"string","description":"Payment rail identifier"},"currency":{"type":"string","description":"Fiat currency code"},"institution_name":{"type":"string","nullable":true,"description":"Institution (bank) name if applicable"},"institution_id":{"type":"string","nullable":true,"description":"Institution identifier (our internal slug)"},"details":{"type":"object","description":"Payment details (account number, VPA, IBAN, etc.)","additionalProperties":true}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/payment-details":{"get":{"tags":["User Management"],"summary":"Payment details for a partner user","description":"Retrieve all payment details (payment profiles) for a partner user. Returns all saved beneficiary details that can be used for offramp operations. Partners can only access their own users.","operationId":"getPaymentDetails","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Successfully retrieved payment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetPaymentDetailsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"500":{"description":"Internal Server Error"}}}}}}
```

## Create payment details for a partner user

> Create payment details (beneficiary details) for a partner user. Used for offramp operations where crypto is converted to fiat and sent to the user's payment account. Partners can only access their own users.\
> \
> Payment details must belong to the same beneficiary represented by \`user\_uuid\`. Do not attach phone numbers, bank accounts, wallets, or other payout instruments for unrelated people to the same partner user. If you need to pay a different person, create a separate partner user for that beneficiary first.\
> \
> Institution handling:\
> \- for most rails, \`institution\_id\` must be provided from \`/api/v1/supported/institutions\`\
> \- partners may omit \`institution\_id\` only for the explicitly supported rails below; the backend will assign the generic \`other-bank\` payment method automatically\
> \
> Currently supported omission rails:\
> \- \`iban-sepa\`\
> \- \`nip-nigeria\`<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"CreatePaymentDetailsRequest":{"description":"Conditional request schema for partner payment details. `institution_id` may be omitted for `iban-sepa`, `nip-nigeria`, and `imps-neft-india`.","oneOf":[{"$ref":"#/components/schemas/CreatePaymentDetailsRequestInstitutionOptional"},{"$ref":"#/components/schemas/CreatePaymentDetailsRequestInstitutionRequired"}]},"CreatePaymentDetailsRequestInstitutionOptional":{"allOf":[{"$ref":"#/components/schemas/CreatePaymentDetailsRequestBase"},{"type":"object","properties":{"rail":{"type":"string","enum":["iban-sepa","nip-nigeria","imps-neft-india"],"description":"Payment rail identifier for rails that support omission of `institution_id`"},"institution_id":{"type":"string","description":"Optional for `iban-sepa`, `nip-nigeria`, and `imps-neft-india`.\nFor `iban-sepa`/`nip-nigeria`, if omitted the backend assigns the generic `other-bank` payment method automatically.\nFor `imps-neft-india` it is ignored entirely (resolves to the generic `imps-or-neft-transfer` method); the bank is taken from `details.bank_name` + `details.ifsc_code`.\n"}}}]},"CreatePaymentDetailsRequestBase":{"type":"object","required":["currency","rail","details"],"properties":{"currency":{"type":"string","description":"ISO 3-letter fiat currency code (e.g., INR, EUR, USD)"},"rail":{"type":"string","description":"Payment rail identifier (e.g., \"upi-india\", \"iban-sepa\", \"imps-neft-india\")"},"details":{"type":"object","description":"Payment details object with fields specific to the payment network (e.g., account_number, vpa, iban, full_name)","additionalProperties":true},"country_code":{"type":"string","description":"Optional ISO 2-letter country code"}}},"CreatePaymentDetailsRequestInstitutionRequired":{"allOf":[{"$ref":"#/components/schemas/CreatePaymentDetailsRequestBase"},{"type":"object","required":["institution_id"],"properties":{"rail":{"type":"string","description":"Payment rail identifier for rails that require institution selection","not":{"enum":["iban-sepa","nip-nigeria","imps-neft-india"]}},"institution_id":{"type":"string","description":"Institution (payment method) identifier - our internal slug (e.g., \"wise\", \"hdfc-bank\", \"revolut\", \"uala\", \"banco-santander-argentina\").\nRequired for all rails except `iban-sepa`, `nip-nigeria`, and `imps-neft-india`.\nIf omitted for any other rail, the API returns a validation error.\nFor rails with multiple formats (e.g., CVU/CBU), the format is automatically determined based on the payment method type of this institution.\n"}}}]},"CreatePaymentDetailsResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentProfile"}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}},"PaymentProfile":{"type":"object","properties":{"payment_details_id":{"type":"string","description":"Payment details ID. Use this value in offramp/onramp quote requests."},"rail":{"type":"string","description":"Payment rail identifier"},"currency":{"type":"string","description":"Fiat currency code"},"institution_name":{"type":"string","nullable":true,"description":"Institution (bank) name if applicable"},"institution_id":{"type":"string","nullable":true,"description":"Institution identifier (our internal slug)"},"details":{"type":"object","description":"Payment details (account number, VPA, IBAN, etc.)","additionalProperties":true}}},"ErrorResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["error_key"],"properties":{"error_key":{"type":"string","description":"Standardized error key for client error handling"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/payment-details":{"post":{"tags":["User Management"],"summary":"Create payment details for a partner user","description":"Create payment details (beneficiary details) for a partner user. Used for offramp operations where crypto is converted to fiat and sent to the user's payment account. Partners can only access their own users.\n\nPayment details must belong to the same beneficiary represented by `user_uuid`. Do not attach phone numbers, bank accounts, wallets, or other payout instruments for unrelated people to the same partner user. If you need to pay a different person, create a separate partner user for that beneficiary first.\n\nInstitution handling:\n- for most rails, `institution_id` must be provided from `/api/v1/supported/institutions`\n- partners may omit `institution_id` only for the explicitly supported rails below; the backend will assign the generic `other-bank` payment method automatically\n\nCurrently supported omission rails:\n- `iban-sepa`\n- `nip-nigeria`\n","operationId":"createPaymentDetails","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentDetailsRequest"}}}},"responses":{"201":{"description":"Payment details created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentDetailsResponse"}}}},"400":{"description":"Bad Request - invalid payment details or unsupported combination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found"},"422":{"description":"Recipient details are incomplete or invalid for the payout corridor. The recipient fields you supply are validated against the provider's per-corridor requirements; if a required field is missing or malformed, the recipient is not created and the offending field names are listed in the error message. Fix the details and resubmit. Address fields auto-populated from KYC are not part of this check (a missing address does not block creation — see the KYC endpoints).","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string","description":"Human-readable message naming the missing or invalid recipient fields."}}}}}},"500":{"description":"Internal Server Error"}}}}}}
```

## Get a single payment detail for a partner user

> Retrieve one payment detail (payment profile) by its \`payment\_details\_id\`, returning the same shape as one element of the list endpoint (\`rail\`, \`currency\`, \`institution\_name\`, \`institution\_id\`, \`details\`).\
> \
> Use this when you already hold a \`payment\_details\_id\` instead of listing every payment detail for the user — it stays fast on accounts with many saved payment details.\
> \
> Partners can only access their own users. A payment detail that belongs to a different user (or another partner) returns \`404\` rather than revealing that it exists.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}},"schemas":{"GetPaymentDetailResponse":{"allOf":[{"$ref":"#/components/schemas/APIResponse"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentProfile"}}}]},"APIResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Indicates if the request was successful"},"data":{"description":"Response data (structure varies by endpoint) or error information if success is false"}}},"PaymentProfile":{"type":"object","properties":{"payment_details_id":{"type":"string","description":"Payment details ID. Use this value in offramp/onramp quote requests."},"rail":{"type":"string","description":"Payment rail identifier"},"currency":{"type":"string","description":"Fiat currency code"},"institution_name":{"type":"string","nullable":true,"description":"Institution (bank) name if applicable"},"institution_id":{"type":"string","nullable":true,"description":"Institution identifier (our internal slug)"},"details":{"type":"object","description":"Payment details (account number, VPA, IBAN, etc.)","additionalProperties":true}}},"ErrorResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["error_key"],"properties":{"error_key":{"type":"string","description":"Standardized error key for client error handling"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/payment-details/{payment_details_id}":{"get":{"tags":["User Management"],"summary":"Get a single payment detail for a partner user","description":"Retrieve one payment detail (payment profile) by its `payment_details_id`, returning the same shape as one element of the list endpoint (`rail`, `currency`, `institution_name`, `institution_id`, `details`).\n\nUse this when you already hold a `payment_details_id` instead of listing every payment detail for the user — it stays fast on accounts with many saved payment details.\n\nPartners can only access their own users. A payment detail that belongs to a different user (or another partner) returns `404` rather than revealing that it exists.\n","operationId":"getPaymentDetailById","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}},{"name":"payment_details_id","in":"path","required":true,"description":"The payment_details_id returned when creating or listing payment details.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved the payment detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetPaymentDetailResponse"}}}},"400":{"description":"Bad Request - malformed payment_details_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found, or payment detail not found / not owned by this user"},"500":{"description":"Internal Server Error"}}}}}}
```

## Delete payment details for a partner user

> Delete a specific payment details (payment profile) for a partner user by its ID. Partners can only access their own users.

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Endpoints to create and manage user accounts"}],"servers":[{"url":"https://api-staging.unigox.com","description":"Sandbox server"},{"url":"https://api.unigox.com","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Partner API key for authentication. Required for all partner account endpoints."}}},"paths":{"/api/v1/partner/users/{user_uuid}/payment-details/{payment_details_id}":{"delete":{"tags":["User Management"],"summary":"Delete payment details for a partner user","description":"Delete a specific payment details (payment profile) for a partner user by its ID. Partners can only access their own users.","operationId":"deletePaymentDetails","parameters":[{"name":"user_uuid","in":"path","required":true,"description":"The user_uuid returned by POST /partner/users. Partners can only access their own users.","schema":{"type":"string","format":"uuid"}},{"name":"payment_details_id","in":"path","required":true,"description":"The payment_details_id returned when creating payment details.","schema":{"type":"string"}}],"responses":{"200":{"description":"Payment details deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"User not found or payment details not found"},"409":{"description":"Conflict - payment details linked to active offers"},"500":{"description":"Internal Server Error"}}}}}}
```
