> 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

Create and manage your customers, put them through KYC, hold their payout details — and issue the fiat accounts they are paid into.

All of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with the `user_uuid` every route below takes in its path; KYC verifies them; and an account is opened for that same person. There is no second identity to register and no separate customer record for banking — the person Unigox verified is the person the account belongs to.

### Fiat accounts

Issue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and incoming payments. Every account is reached through the customer that holds it — which is why these routes live here rather than under a product of their own, and why an account id on its own will not read an account. It is an optional product that Unigox activates per partner, it covers individuals rather than companies, and money movement is not on this API. The [Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end to end, what has to be switched on before you start, and the error codes.

## 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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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\`.\
> \
> A partner user is the SENDER. To pay someone else, do not create a shell user for the payee — register a recipient (\`/api/v1/partner/recipients\`) and quote against it. See the Third-party payouts guide.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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 every subsequent call** — it is the\n`{user_uuid}` in `/partner/users/{user_uuid}/…`.\n"},"id":{"type":"string","format":"uuid","description":"The same value as `user_uuid`, kept for integrations written before that name\nexisted. Either can be read; they never differ.\n"},"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`.\n\nA partner user is the SENDER. To pay someone else, do not create a shell user for the payee — register a recipient (`/api/v1/partner/recipients`) and quote against it. See the Third-party payouts guide.\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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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.\
> \
> \*\*Sender identity (consumer-to-consumer payout rails).\*\* Chinese mobile wallets\
> (Alipay, WeChat Pay) settle person to person: the receiving wallet must show the\
> paying customer as the remitter, not Unigox. \`POST /offramp/initiate\` returns\
> \`422 SENDER\_IDENTITY\_REQUIRED\` when the customer's record cannot name them, listing\
> the fields to send here in \`error.details.kyc\_fields\`. \`gender\`, \`nationality\`,\
> \`id\_issue\_country\` and \`source\_of\_funds\` exist for that flow, alongside \`dob\`,\
> \`phone\_number\`, \`id\_number\`, \`id\_type\` and the address fields the same rails need.\
> Send them once, then retry the order.\
> \
> The values are normalized before they are stored, and a value the rail would reject\
> is a \`400\` here rather than a failed payout later: \`gender\` accepts \`M\`/\`F\`\
> (\`MALE\`/\`FEMALE\` are folded in), \`nationality\` and \`id\_issue\_country\` take an ISO\
> 3166-1 alpha-2 code, and \`source\_of\_funds\` takes one of the listed slugs.\
> \
> Length is the exception, because the ceiling belongs to the payout rail and this record is\
> not tied to one: a value too long for a corridor is accepted here and comes back from that\
> corridor's \`initiate\` as a listed field, with the ceiling in \`error.details.field\_limits\`.\
> \
> The record belongs to the customer, not to a payout destination — never send another\
> person's details here to satisfy a payout.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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\n**Sender identity (consumer-to-consumer payout rails).** Chinese mobile wallets\n(Alipay, WeChat Pay) settle person to person: the receiving wallet must show the\npaying customer as the remitter, not Unigox. `POST /offramp/initiate` returns\n`422 SENDER_IDENTITY_REQUIRED` when the customer's record cannot name them, listing\nthe fields to send here in `error.details.kyc_fields`. `gender`, `nationality`,\n`id_issue_country` and `source_of_funds` exist for that flow, alongside `dob`,\n`phone_number`, `id_number`, `id_type` and the address fields the same rails need.\nSend them once, then retry the order.\n\nThe values are normalized before they are stored, and a value the rail would reject\nis a `400` here rather than a failed payout later: `gender` accepts `M`/`F`\n(`MALE`/`FEMALE` are folded in), `nationality` and `id_issue_country` take an ISO\n3166-1 alpha-2 code, and `source_of_funds` takes one of the listed slugs.\n\nLength is the exception, because the ceiling belongs to the payout rail and this record is\nnot tied to one: a value too long for a corridor is accepted here and comes back from that\ncorridor's `initiate` as a listed field, with the ceiling in `error.details.field_limits`.\n\nThe record belongs to the customer, not to a payout destination — never send another\nperson's details here to satisfy a payout.\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","description":"Document number, as printed on the document named by `id_type`."},"id_type":{"type":"string","enum":["NATIONAL_ID","DRIVER_LICENSE","PASSPORT","RESIDENCE_PERMIT"]},"gender":{"type":"string","enum":["M","F"],"description":"Sender identity. As it appears on the identity document — payout rails match it against the document, so this is not a self-description field. `MALE`/`FEMALE` are accepted and normalized to `M`/`F`."},"nationality":{"type":"string","description":"Sender identity. Nationality as an ISO 3166-1 alpha-2 code."},"id_issue_country":{"type":"string","description":"Sender identity. Country that issued the document, ISO 3166-1 alpha-2. Often but not always the same as `nationality`."},"source_of_funds":{"type":"string","enum":["salary","business_income","savings","investment","gift","family_support","loan","sale_of_property","inheritance","other"],"description":"Sender identity. Where the money being sent comes from. Each payout rail maps this onto its own catalogue and refuses a payout it cannot map, so send the closest listed value rather than `other` when one applies."}}}}}},"responses":{"200":{"description":"KYC data updated successfully. `updated_fields` names only the fields that actually reached the record. A recognised field sent blank is a no-op rather than an error, so a patch whose recognised fields are all blank answers `200` with `updated_fields: []` and nothing is written — this endpoint does not clear a stored value.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"updated_fields":{"type":"array","items":{"type":"string"},"description":"Fields written by this patch. Empty when every recognised field in the body was blank."},"message":{"type":"string"}}}}}}}},"400":{"description":"Bad request — no valid fields, attempting to change a required field, or a value 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). Sender-identity values: `invalid_gender`, `invalid_country_code` (`nationality` / `id_issue_country` is not an alpha-2 code) and `invalid_source_of_funds`. `invalid_field_value` means a value was sent as an object or an array where a string or a number is expected. `no_valid_kyc_fields` means the body carried no updatable field at all. Nothing is written when one field is rejected — fix it and resend the whole patch."},"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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"}}}}}}
```

## What you can offer

> Whether this partner may use fiat accounts right now, which currencies an account may be\
> denominated in, and which jurisdictions each currency can be issued from.\
> \
> The one route outside the customer tree, and deliberately: it answers what you may offer AT\
> ALL, before any customer is in scope. It is not an account.\
> \
> Never errors on entitlement: when the product is not active it answers \`200\` with\
> \`enabled: false\` and a \`disabled\_reason\`, so a console can render the reason rather than a\
> failure. \`issues\_accounts: false\` with \`enabled: true\` is a real shape — the partner may put\
> customers through verification but not open accounts for them.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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":{"FiatConfigResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/FiatConfig"}}}}},"FiatConfig":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether this partner may use fiat accounts at all."},"issues_accounts":{"type":"boolean","description":"Whether this partner may OPEN accounts, as opposed to only putting customers through\nverification. `false` with `enabled: true` is a real product shape, not a degraded one.\n"},"disabled_reason":{"type":"string","description":"Why the surface is unavailable, when `enabled` is false because of something about this\npartner. Absent when the product is simply switched off platform-wide.\n"},"currencies":{"type":"array","items":{"type":"string"},"description":"ISO 4217 currencies an account may be denominated in, narrowed to what this partner's plan prices."},"issuers":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}},"description":"Currency → issuing jurisdictions (ISO 3166-1 alpha-2), default first."},"postal_code_issuers":{"type":"array","items":{"type":"string"},"description":"Jurisdictions that will not issue unless a postal code is on the identity record."}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/fiat-accounts/config":{"get":{"tags":["User Management"],"summary":"What you can offer","operationId":"getFiatAccountsConfig","description":"Whether this partner may use fiat accounts right now, which currencies an account may be\ndenominated in, and which jurisdictions each currency can be issued from.\n\nThe one route outside the customer tree, and deliberately: it answers what you may offer AT\nALL, before any customer is in scope. It is not an account.\n\nNever errors on entitlement: when the product is not active it answers `200` with\n`enabled: false` and a `disabled_reason`, so a console can render the reason rather than a\nfailure. `issues_accounts: false` with `enabled: true` is a real shape — the partner may put\ncustomers through verification but not open accounts for them.\n","responses":{"200":{"description":"Current configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatConfigResponse"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## What identity we hold, and what is still needed

> What Unigox KYC already established about this customer, and \`missing\` — the fields the\
> banking layer still needs before an account can be opened. \`ready: true\` means the\
> identification submission will be accepted with an empty body.\
> \
> A read: it creates nothing, calls no one and stays available when the product is switched\
> off, so a partner can always see WHY a customer cannot be issued an account.\
> \
> The document number is never returned — only its last four digits.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}}},"schemas":{"FiatIdentityResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"identity":{"$ref":"#/components/schemas/FiatIdentity"},"missing":{"type":"array","items":{"type":"string"},"description":"The fields the banking layer still needs. Empty means nothing is missing."},"ready":{"type":"boolean","description":"True when `missing` is empty — the identification submission will be accepted with an empty body."}}}}},"FiatIdentity":{"type":"object","description":"What Unigox KYC established. The document number is never returned — only its last four digits.","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"country_of_residence":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"postal_code":{"type":"string"},"birthdate":{"type":"string"},"document_type":{"type":"string"},"document_last4":{"type":"string"},"sources":{"type":"object","additionalProperties":{"type":"string"},"description":"Per-field provenance, so a caller can tell a verified value from a declared one."}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/identity":{"get":{"tags":["User Management"],"summary":"What identity we hold, and what is still needed","operationId":"getFiatCustomerIdentity","description":"What Unigox KYC already established about this customer, and `missing` — the fields the\nbanking layer still needs before an account can be opened. `ready: true` means the\nidentification submission will be accepted with an empty body.\n\nA read: it creates nothing, calls no one and stays available when the product is switched\noff, so a partner can always see WHY a customer cannot be issued an account.\n\nThe document number is never returned — only its last four digits.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"}],"responses":{"200":{"description":"Known identity and remaining gaps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatIdentityResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## Verification status of the account holder

> The holder's current verification state. Poll this until \`can\_open\_accounts\` is \`true\`.\
> \
> A \`GET\` on purpose: checking a verification changes nothing, so it is safe to retry and safe\
> to run on a schedule. Where the identity has already reached the banking layer this re-reads\
> their verdict; before that it answers from the holder record.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}}},"schemas":{"FiatHolderResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"holder":{"$ref":"#/components/schemas/FiatAccountHolder"}}}}},"FiatAccountHolder":{"type":"object","description":"The customer, as the account holder. There is no separate identity here: `user_uuid` is the\ncustomer created with `POST /api/v1/partner/users`, and the names and country are the ones\nUnigox KYC verified.\n","properties":{"user_uuid":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"country_of_residence":{"type":"string"},"kyc_status":{"type":"string","description":"Unigox's own verdict on the customer."},"status":{"type":"string","description":"Holder lifecycle: `draft`, `pending_review`, `approved`, `rejected`."},"can_open_accounts":{"type":"boolean","description":"Whether an account may be opened for this holder right now. Poll on this."},"created_at":{"type":"string"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/identification":{"get":{"tags":["User Management"],"summary":"Verification status of the account holder","operationId":"getFiatIdentification","description":"The holder's current verification state. Poll this until `can_open_accounts` is `true`.\n\nA `GET` on purpose: checking a verification changes nothing, so it is safe to retry and safe\nto run on a schedule. Where the identity has already reached the banking layer this re-reads\ntheir verdict; before that it answers from the holder record.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"}],"responses":{"200":{"description":"Holder status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatHolderResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`), or the customer has not been\nsubmitted for verification yet (`ACCOUNT_HOLDER_NOT_FOUND`) — polling never creates a\nholder record.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"502":{"description":"The banking layer could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## Submit the customer's identity

> Submits the customer's identity to the banking layer, registering them as an account holder\
> if this is the first call.\
> \
> \*\*Every body field is optional.\*\* What Unigox verified at KYC is always preferred over what\
> is sent here, so send only what \`GET /users/{user\_uuid}/identity\` reported as \`missing\`. The\
> name, the country of residence and the document are taken from the verification and cannot\
> be overridden — the identity a bank opens an account on has to be the one that was verified.\
> \
> The customer must be KYC-verified by Unigox first. The document number is used for the\
> submission and is not stored; only its last four digits are kept.\
> \
> Idempotent: a customer already submitted answers \`200\` with their current holder record and\
> makes no second submission.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}}},"schemas":{"FiatIdentificationRequest":{"type":"object","description":"Every field is optional. What Unigox verified at KYC is preferred over anything sent here,\nso send only what `GET /users/{user_uuid}/identity` reported as missing. The name, the country\nof residence and the document are taken from the verification and cannot be overridden.\n","properties":{"address":{"type":"string"},"city":{"type":"string"},"birthdate":{"type":"string"},"document_type":{"type":"string","enum":["PASSPORT","NATIONAL_ID","DRIVERS_LICENCE","WORK_PERMIT"]},"document_number":{"type":"string","description":"Used for the submission and not stored; only the last four digits are kept."},"email":{"type":"string"},"country_of_residence":{"type":"string"}}},"FiatHolderResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"holder":{"$ref":"#/components/schemas/FiatAccountHolder"}}}}},"FiatAccountHolder":{"type":"object","description":"The customer, as the account holder. There is no separate identity here: `user_uuid` is the\ncustomer created with `POST /api/v1/partner/users`, and the names and country are the ones\nUnigox KYC verified.\n","properties":{"user_uuid":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"country_of_residence":{"type":"string"},"kyc_status":{"type":"string","description":"Unigox's own verdict on the customer."},"status":{"type":"string","description":"Holder lifecycle: `draft`, `pending_review`, `approved`, `rejected`."},"can_open_accounts":{"type":"boolean","description":"Whether an account may be opened for this holder right now. Poll on this."},"created_at":{"type":"string"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/identification":{"post":{"tags":["User Management"],"summary":"Submit the customer's identity","operationId":"submitFiatIdentification","description":"Submits the customer's identity to the banking layer, registering them as an account holder\nif this is the first call.\n\n**Every body field is optional.** What Unigox verified at KYC is always preferred over what\nis sent here, so send only what `GET /users/{user_uuid}/identity` reported as `missing`. The\nname, the country of residence and the document are taken from the verification and cannot\nbe overridden — the identity a bank opens an account on has to be the one that was verified.\n\nThe customer must be KYC-verified by Unigox first. The document number is used for the\nsubmission and is not stored; only its last four digits are kept.\n\nIdempotent: a customer already submitted answers `200` with their current holder record and\nmakes no second submission.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatIdentificationRequest"}}}},"responses":{"200":{"description":"Submitted (or already submitted)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatHolderResponse"}}}},"400":{"description":"Identity gaps (`MISSING_FIELDS`, with `error.details.missing_fields`) or a document type\noutside the accepted set (`INVALID_DOCUMENT_TYPE`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"403":{"description":"Not entitled (`PRODUCT_NOT_ACTIVATED`, `ISSUANCE_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"409":{"description":"The banking layer matched this person to an identity another holder already owns\n(`IDENTIFICATION_ALREADY_LINKED`), or this customer is already being registered as a\nholder by a request in flight (`HOLDER_REGISTRATION_IN_PROGRESS`) — retry once it\nsettles.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"422":{"description":"The customer is not KYC-verified (`CUSTOMER_NOT_VERIFIED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"502":{"description":"The banking layer refused or failed the submission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## This customer's accounts

> Every account issued to this customer. A read: a customer with no issuance yet has no\
> accounts, which is an empty list rather than a reason to create anything.\
> \
> Only the last four digits of the identifier travel here — fetch a single account for the\
> full details a payer needs.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}}},"schemas":{"FiatAccountsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/FiatAccount"}}}}}},"FiatAccount":{"type":"object","description":"One issued account. Only the last four digits of the identifier travel in list views; the\nsingle-account view carries what a payer needs in full.\n\nNo field identifies the bank or banking platform Unigox routes through. `bank_name` and\n`bic` describe the account itself, which is different — those are for display to a payer.\n","properties":{"id":{"type":"string","description":"Opaque account id, carrying its holder kind: `retail_412`. This is what every\n`/users/{user_uuid}/fiat-accounts/{account_id}` route takes. Pass it back verbatim and\ndo not parse it — the prefix is part of the id, not decoration, and ids are not unique\nacross holder kinds without it.\n"},"holder_type":{"type":"string","enum":["retail"],"description":"The kind of holder this account belongs to. `retail` — an individual you onboarded\nthrough KYC — is the only kind addressable on this API. Published so a client can tell\nthe kinds apart if another becomes available; do not assume it is the only value\nforever.\n"},"holder_id":{"type":"string","description":"The holder — the customer's `user_uuid`, the same value that appears in the path. Sent\nso an account object is self-describing when it is passed around on its own.\n"},"currency":{"type":"string"},"issuer_country":{"type":"string","description":"The jurisdiction the account was actually issued in, read off the IBAN."},"status":{"type":"string","description":"`active`, `pending`, `closed` or `unknown`. A CLOSED account stays readable: closing\nretires the IBAN without removing the account, its history, or any money still behind it.\n"},"iban":{"type":"string","description":"Single-account view only — the list views carry `iban_last4`."},"iban_last4":{"type":"string"},"account_number":{"type":"string","description":"Single-account view only, on a non-IBAN (GB sterling) account."},"account_number_last4":{"type":"string","description":"Present instead of `iban_last4` on a non-IBAN account (a GB sterling one)."},"sort_code":{"type":"string","description":"Present on a GB sterling account."},"holder_name":{"type":"string","description":"The name the account is held in."},"bank_name":{"type":"string","description":"The bank a payer should be shown, resolved from the BIC or the IBAN's bank code."},"bic":{"type":"string"},"holder_full_name":{"type":"string","description":"List views only — who the account belongs to, so a list needs no second call."},"holder_email":{"type":"string"},"holder_status":{"type":"string"},"created_at":{"type":"string"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/fiat-accounts":{"get":{"tags":["User Management"],"summary":"This customer's accounts","operationId":"listFiatAccountsForUser","description":"Every account issued to this customer. A read: a customer with no issuance yet has no\naccounts, which is an empty list rather than a reason to create anything.\n\nOnly the last four digits of the identifier travel here — fetch a single account for the\nfull details a payer needs.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"}],"responses":{"200":{"description":"Accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatAccountsResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## Issue an account

> Opens a fiat account (IBAN) for the customer, registering them as an account holder first if\
> needed. The holder must already be approved — see\
> \`GET /users/{user\_uuid}/identification\`.\
> \
> \*\*Idempotent per (customer, currency, jurisdiction).\*\* A repeat answers \`201\` with the same\
> account and \`created: false\`; it does not open a second one. One customer may hold accounts\
> in several currencies, and in several jurisdictions of the same currency — \`EUR/NL\` and\
> \`EUR/MT\` are two accounts, each opened by naming its \`issuer\_country\`.\
> \
> Two requests racing for the same account answer \`409 PROVISIONING\_IN\_PROGRESS\`. Retry once\
> it settles rather than treating it as a failure.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}}},"schemas":{"FiatIssueAccountRequest":{"type":"object","required":["currency"],"properties":{"currency":{"type":"string","description":"ISO 4217; must be one `GET /fiat-accounts/config` offers. Upper-cased server-side."},"issuer_country":{"type":"string","description":"Issuing jurisdiction (ISO 3166-1 alpha-2). Omit for the currency's default; supplied, it\nmust be one of that currency's `issuers`.\n"},"postal_code":{"type":"string","description":"Required only when the chosen jurisdiction is in `postal_code_issuers`; ignored otherwise."}}},"FiatAccountIssuedResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"account":{"$ref":"#/components/schemas/FiatAccount"},"created":{"type":"boolean","description":"Whether THIS request opened the account. `false` means it already existed and is\nbeing handed back — the endpoint is idempotent per (customer, currency,\njurisdiction).\n"}}}}},"FiatAccount":{"type":"object","description":"One issued account. Only the last four digits of the identifier travel in list views; the\nsingle-account view carries what a payer needs in full.\n\nNo field identifies the bank or banking platform Unigox routes through. `bank_name` and\n`bic` describe the account itself, which is different — those are for display to a payer.\n","properties":{"id":{"type":"string","description":"Opaque account id, carrying its holder kind: `retail_412`. This is what every\n`/users/{user_uuid}/fiat-accounts/{account_id}` route takes. Pass it back verbatim and\ndo not parse it — the prefix is part of the id, not decoration, and ids are not unique\nacross holder kinds without it.\n"},"holder_type":{"type":"string","enum":["retail"],"description":"The kind of holder this account belongs to. `retail` — an individual you onboarded\nthrough KYC — is the only kind addressable on this API. Published so a client can tell\nthe kinds apart if another becomes available; do not assume it is the only value\nforever.\n"},"holder_id":{"type":"string","description":"The holder — the customer's `user_uuid`, the same value that appears in the path. Sent\nso an account object is self-describing when it is passed around on its own.\n"},"currency":{"type":"string"},"issuer_country":{"type":"string","description":"The jurisdiction the account was actually issued in, read off the IBAN."},"status":{"type":"string","description":"`active`, `pending`, `closed` or `unknown`. A CLOSED account stays readable: closing\nretires the IBAN without removing the account, its history, or any money still behind it.\n"},"iban":{"type":"string","description":"Single-account view only — the list views carry `iban_last4`."},"iban_last4":{"type":"string"},"account_number":{"type":"string","description":"Single-account view only, on a non-IBAN (GB sterling) account."},"account_number_last4":{"type":"string","description":"Present instead of `iban_last4` on a non-IBAN account (a GB sterling one)."},"sort_code":{"type":"string","description":"Present on a GB sterling account."},"holder_name":{"type":"string","description":"The name the account is held in."},"bank_name":{"type":"string","description":"The bank a payer should be shown, resolved from the BIC or the IBAN's bank code."},"bic":{"type":"string"},"holder_full_name":{"type":"string","description":"List views only — who the account belongs to, so a list needs no second call."},"holder_email":{"type":"string"},"holder_status":{"type":"string"},"created_at":{"type":"string"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/fiat-accounts":{"post":{"tags":["User Management"],"summary":"Issue an account","operationId":"issueFiatAccount","description":"Opens a fiat account (IBAN) for the customer, registering them as an account holder first if\nneeded. The holder must already be approved — see\n`GET /users/{user_uuid}/identification`.\n\n**Idempotent per (customer, currency, jurisdiction).** A repeat answers `201` with the same\naccount and `created: false`; it does not open a second one. One customer may hold accounts\nin several currencies, and in several jurisdictions of the same currency — `EUR/NL` and\n`EUR/MT` are two accounts, each opened by naming its `issuer_country`.\n\nTwo requests racing for the same account answer `409 PROVISIONING_IN_PROGRESS`. Retry once\nit settles rather than treating it as a failure.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatIssueAccountRequest"}}}},"responses":{"201":{"description":"Account issued, or the existing one for this (customer, currency, jurisdiction).\n`created` distinguishes the two.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatAccountIssuedResponse"}}}},"400":{"description":"`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `POSTAL_CODE_REQUIRED` or\n`INVALID_POSTAL_CODE`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"403":{"description":"Not entitled (`PRODUCT_NOT_ACTIVATED`, `ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`) or\nthe currency is outside this customer's issuance (`CURRENCY_NOT_PERMITTED`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"409":{"description":"The same account is already being opened (`PROVISIONING_IN_PROGRESS`), or this customer\nis already being registered as a holder by a request in flight\n(`HOLDER_REGISTRATION_IN_PROGRESS`). Both settle on their own — retry.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"422":{"description":"The holder is not approved or not submitted (`CLIENT_NOT_APPROVED`,\n`IDENTIFICATION_MISSING`), the customer is no longer verified\n(`CUSTOMER_NOT_VERIFIED`), or the currency is not priced (`CURRENCY_NOT_PRICED`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"500":{"description":"The account was opened at the banking layer but the local record write failed — do not\nretry (`RECORD_FAILED`); contact Unigox so it can be reconciled.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"502":{"description":"The banking layer refused to open the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## One account, with balances

> The full account details a payer needs — including the complete IBAN or account number — the\
> holder it belongs to, and the live balances.\
> \
> An account is always addressed through the customer that holds it. One that belongs to a\
> different customer answers \`404\`, the same as one that does not exist.\
> \
> \`balances\_unavailable: true\` means the balance read failed — the balances are reported as\
> unavailable rather than as zero, because a zero a partner acts on is worse than a gap.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}},"FiatAccountId":{"name":"account_id","in":"path","required":true,"description":"Opaque id of a fiat account, as returned in `FiatAccount.id` — `retail_412`. An id that\nnames no account, one that is not yours, and one that belongs to a different customer than\nthe path names all answer `404`; they are indistinguishable on purpose.\n","schema":{"type":"string"}}},"schemas":{"FiatAccountDetailResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"account":{"$ref":"#/components/schemas/FiatAccount"},"holder":{"$ref":"#/components/schemas/FiatAccountHolder"},"balances":{"type":"array","items":{"$ref":"#/components/schemas/FiatBalanceLine"}},"balances_unavailable":{"type":"boolean","description":"True when the balance read failed. The balances are reported as unavailable rather\nthan as zero — a zero a partner acts on is worse than a gap.\n"}}}}},"FiatAccount":{"type":"object","description":"One issued account. Only the last four digits of the identifier travel in list views; the\nsingle-account view carries what a payer needs in full.\n\nNo field identifies the bank or banking platform Unigox routes through. `bank_name` and\n`bic` describe the account itself, which is different — those are for display to a payer.\n","properties":{"id":{"type":"string","description":"Opaque account id, carrying its holder kind: `retail_412`. This is what every\n`/users/{user_uuid}/fiat-accounts/{account_id}` route takes. Pass it back verbatim and\ndo not parse it — the prefix is part of the id, not decoration, and ids are not unique\nacross holder kinds without it.\n"},"holder_type":{"type":"string","enum":["retail"],"description":"The kind of holder this account belongs to. `retail` — an individual you onboarded\nthrough KYC — is the only kind addressable on this API. Published so a client can tell\nthe kinds apart if another becomes available; do not assume it is the only value\nforever.\n"},"holder_id":{"type":"string","description":"The holder — the customer's `user_uuid`, the same value that appears in the path. Sent\nso an account object is self-describing when it is passed around on its own.\n"},"currency":{"type":"string"},"issuer_country":{"type":"string","description":"The jurisdiction the account was actually issued in, read off the IBAN."},"status":{"type":"string","description":"`active`, `pending`, `closed` or `unknown`. A CLOSED account stays readable: closing\nretires the IBAN without removing the account, its history, or any money still behind it.\n"},"iban":{"type":"string","description":"Single-account view only — the list views carry `iban_last4`."},"iban_last4":{"type":"string"},"account_number":{"type":"string","description":"Single-account view only, on a non-IBAN (GB sterling) account."},"account_number_last4":{"type":"string","description":"Present instead of `iban_last4` on a non-IBAN account (a GB sterling one)."},"sort_code":{"type":"string","description":"Present on a GB sterling account."},"holder_name":{"type":"string","description":"The name the account is held in."},"bank_name":{"type":"string","description":"The bank a payer should be shown, resolved from the BIC or the IBAN's bank code."},"bic":{"type":"string"},"holder_full_name":{"type":"string","description":"List views only — who the account belongs to, so a list needs no second call."},"holder_email":{"type":"string"},"holder_status":{"type":"string"},"created_at":{"type":"string"}}},"FiatAccountHolder":{"type":"object","description":"The customer, as the account holder. There is no separate identity here: `user_uuid` is the\ncustomer created with `POST /api/v1/partner/users`, and the names and country are the ones\nUnigox KYC verified.\n","properties":{"user_uuid":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"country_of_residence":{"type":"string"},"kyc_status":{"type":"string","description":"Unigox's own verdict on the customer."},"status":{"type":"string","description":"Holder lifecycle: `draft`, `pending_review`, `approved`, `rejected`."},"can_open_accounts":{"type":"boolean","description":"Whether an account may be opened for this holder right now. Poll on this."},"created_at":{"type":"string"}}},"FiatBalanceLine":{"type":"object","properties":{"currency":{"type":"string"},"available":{"type":"string"},"pending":{"type":"string"},"total":{"type":"string"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/fiat-accounts/{account_id}":{"get":{"tags":["User Management"],"summary":"One account, with balances","operationId":"getFiatAccount","description":"The full account details a payer needs — including the complete IBAN or account number — the\nholder it belongs to, and the live balances.\n\nAn account is always addressed through the customer that holds it. One that belongs to a\ndifferent customer answers `404`, the same as one that does not exist.\n\n`balances_unavailable: true` means the balance read failed — the balances are reported as\nunavailable rather than as zero, because a zero a partner acts on is worse than a gap.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"},{"$ref":"#/components/parameters/FiatAccountId"}],"responses":{"200":{"description":"Account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatAccountDetailResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`); or no such account under that\ncustomer (`FIAT_ACCOUNT_NOT_FOUND`). An account that exists but belongs to a DIFFERENT\ncustomer answers the same way — it is not addressable through this path.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"422":{"description":"The account has not finished being opened (`ACCOUNT_NOT_PROVISIONED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## Transaction history

> One page of ledger entries for the account.\
> \
> \`pagination\` is present only when the upstream page metadata is available. \*\*Its absence\
> means unknown, not "one page"\*\* — fall back to judging by the length of the page you got.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}},"FiatAccountId":{"name":"account_id","in":"path","required":true,"description":"Opaque id of a fiat account, as returned in `FiatAccount.id` — `retail_412`. An id that\nnames no account, one that is not yours, and one that belongs to a different customer than\nthe path names all answer `404`; they are indistinguishable on purpose.\n","schema":{"type":"string"}}},"schemas":{"FiatLedgerResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/FiatLedgerEntry"}},"pagination":{"$ref":"#/components/schemas/FiatPagination"}}}}},"FiatLedgerEntry":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"category":{"type":"string"},"amount":{"type":"string"},"currency":{"type":"string"},"reference":{"type":"string","description":"The entry's own upstream reference, for reconciliation."},"note":{"type":"string"},"created_at":{"type":"integer","format":"int64","description":"Unix seconds."}}},"FiatPagination":{"type":"object","description":"Upstream page metadata, present only when it is available. **Absence means unknown, not\n\"one page\"** — fall back to the length of the page you received.\n","properties":{"current_page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"total_count":{"type":"integer"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/fiat-accounts/{account_id}/ledger":{"get":{"tags":["User Management"],"summary":"Transaction history","operationId":"getFiatAccountLedger","description":"One page of ledger entries for the account.\n\n`pagination` is present only when the upstream page metadata is available. **Its absence\nmeans unknown, not \"one page\"** — fall back to judging by the length of the page you got.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"},{"$ref":"#/components/parameters/FiatAccountId"},{"name":"page","in":"query","required":false,"description":"1-based page number. Omitted or unparseable means the first page.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Ledger page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatLedgerResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`); or no such account under that\ncustomer (`FIAT_ACCOUNT_NOT_FOUND`). An account that exists but belongs to a DIFFERENT\ncustomer answers the same way — it is not addressable through this path.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"422":{"description":"The account has not finished being opened (`ACCOUNT_NOT_PROVISIONED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"502":{"description":"The banking layer could not be read (`BANKING_ERROR` / `BANKING_UNAVAILABLE`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```

## Payment records

> One page of payment records for the account — the incoming payments that credited it.\
> Same pagination caveat as the ledger.<br>

```json
{"openapi":"3.0.3","info":{"title":"Unigox API Gateway","version":"1.0.0"},"tags":[{"name":"User Management","description":"Create and manage your customers, put them through KYC, hold their payout details — and issue\nthe fiat accounts they are paid into.\n\nAll of it hangs off one customer. `POST /api/v1/partner/users` creates them and answers with\nthe `user_uuid` every route below takes in its path; KYC verifies them; and an account is\nopened for that same person. There is no second identity to register and no separate customer\nrecord for banking — the person Unigox verified is the person the account belongs to.\n\n## Fiat accounts\n\nIssue dedicated fiat accounts (IBANs) for your customers and read their balances, ledger and\nincoming payments. Every account is reached through the customer that holds it — which is why\nthese routes live here rather than under a product of their own, and why an account id on its\nown will not read an account. It is an optional product that Unigox activates per partner, it\ncovers individuals rather than companies, and money movement is not on this API. The\n[Fiat accounts guide](https://developers.unigox.com/tutorials/fiat-accounts) has the flow end\nto end, what has to be switched on before you start, and the error codes.\n"}],"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."}},"parameters":{"FiatUserUuid":{"name":"user_uuid","in":"path","required":true,"description":"Public uuid of a customer owned by the authenticated partner — the id returned by\n`POST /api/v1/partner/users`. A customer you do not own answers `404`, indistinguishable\nfrom one that does not exist.\n","schema":{"type":"string","format":"uuid"}},"FiatAccountId":{"name":"account_id","in":"path","required":true,"description":"Opaque id of a fiat account, as returned in `FiatAccount.id` — `retail_412`. An id that\nnames no account, one that is not yours, and one that belongs to a different customer than\nthe path names all answer `404`; they are indistinguishable on purpose.\n","schema":{"type":"string"}}},"schemas":{"FiatPaymentsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"payments":{"type":"array","items":{"$ref":"#/components/schemas/FiatPayment"}},"pagination":{"$ref":"#/components/schemas/FiatPagination"}}}}},"FiatPayment":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"string"},"currency":{"type":"string"},"kind":{"type":"string"},"status":{"type":"string"},"recipient":{"type":"string"},"description":{"type":"string"},"payment_rail":{"type":"string"},"iban":{"type":"string"},"bic":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"updated_at":{"type":"integer","format":"int64"}}},"FiatPagination":{"type":"object","description":"Upstream page metadata, present only when it is available. **Absence means unknown, not\n\"one page\"** — fall back to the length of the page you received.\n","properties":{"current_page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"total_count":{"type":"integer"}}},"PartnerErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Possible values:\n- `QUOTE_EXPIRED` — quote TTL has passed\n- `QUOTE_NOT_FOUND` — quote ID does not exist\n- `QUOTE_ALREADY_USED` — quote was already consumed by initiate\n- `PRICE_CHANGED_REQUOTE` — price changed beyond slippage tolerance, partner should request a new quote\n- `ORDER_NOT_FOUND` — order ID does not exist or belongs to another partner\n- `NO_OFFERS_AVAILABLE` — no vendor offers for the requested pair\n- `INVALID_REQUEST` — malformed request or missing fields\n- `INVALID_PAYMENT_DETAILS` — payment details not found or invalid\n- `RAIL_ROUTE_MISMATCH` — rail or route does not match payment details\n- `UNAUTHORIZED` — authentication failed\n- `INTERNAL_ERROR` — unexpected server error\n- `INVALID_STATUS` — order is not in the correct status for the requested action\n- `TRANSACTOR_ERROR` — on-chain transaction relay failed (e.g. simulation reverted)\n- `INSUFFICIENT_BALANCE` — partner wallet lacks tokens to fund escrow\n- `OPERATION_NOT_ALLOWED` — action is not permitted for the current order state\n- `KYC_NOT_CLEARED` — the customer is not KYC-cleared for this transaction; `error.details.kyc_status` carries their current partner-facing status\n- `SENDER_IDENTITY_REQUIRED` — the payout corridor settles consumer-to-consumer and the customer's record cannot name them as the remitter; `error.details.kyc_fields` lists what to send to `PATCH /partner/users/{user_uuid}/kyc`, and `error.details.field_limits` carries the rail's length ceiling on any listed field that has one\n\nFiat account endpoints (`/partner/fiat-accounts/config` and the `/partner/users/{user_uuid}`\n`identity`, `identification` and `fiat-accounts` routes) answer with their own codes, each\ndescribed on the response that returns it: `FIAT_ACCOUNT_NOT_FOUND`,\n`ACCOUNT_HOLDER_NOT_FOUND`, `ACCOUNT_NOT_PROVISIONED`, `CUSTOMER_NOT_FOUND`,\n`CUSTOMER_NOT_VERIFIED`, `CLIENT_NOT_APPROVED`, `HOLDER_REGISTRATION_IN_PROGRESS`,\n`IDENTIFICATION_MISSING`, `IDENTIFICATION_ALREADY_LINKED`, `INVALID_DOCUMENT_TYPE`,\n`POSTAL_CODE_REQUIRED`, `INVALID_POSTAL_CODE`, `MISSING_FIELDS`, `PRODUCT_NOT_ACTIVATED`,\n`ISSUANCE_NOT_GRANTED`, `ISSUANCE_DISABLED`, `PROVISIONING_IN_PROGRESS`,\n`UNSUPPORTED_CURRENCY`, `UNSUPPORTED_ISSUER_COUNTRY`, `CURRENCY_NOT_PERMITTED`,\n`CURRENCY_NOT_PRICED`, `RECORD_FAILED`, `BANKING_ERROR`, `BANKING_UNAVAILABLE`.\n\nThis list is not closed: codes are added as endpoints grow. Treat a code you do not recognise\nas an error of the kind its HTTP status says, rather than rejecting the response.\n"},"message":{"type":"string","description":"Human-readable error message"},"details":{"type":"object","nullable":true,"additionalProperties":true,"description":"Additional context (e.g., quoted_rate, current_rate for slippage errors)"}}}}}}},"paths":{"/api/v1/partner/users/{user_uuid}/fiat-accounts/{account_id}/payments":{"get":{"tags":["User Management"],"summary":"Payment records","operationId":"getFiatAccountPayments","description":"One page of payment records for the account — the incoming payments that credited it.\nSame pagination caveat as the ledger.\n","parameters":[{"$ref":"#/components/parameters/FiatUserUuid"},{"$ref":"#/components/parameters/FiatAccountId"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Payments page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FiatPaymentsResponse"}}}},"404":{"description":"No such customer, or not yours (`CUSTOMER_NOT_FOUND`); or no such account under that\ncustomer (`FIAT_ACCOUNT_NOT_FOUND`). An account that exists but belongs to a DIFFERENT\ncustomer answers the same way — it is not addressable through this path.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}},"502":{"description":"The banking layer could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerErrorResponse"}}}}}}}}}
```
