> ## Documentation Index
> Fetch the complete documentation index at: https://developers.uqpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enhanced KYC Card Issuance

> Step-by-step guide to issuing cards that require Enhanced KYC verification for cardholders.

Some card products (BINs) require cardholders to complete **Enhanced KYC** — identity verification through a third-party provider — before a card can be issued. This guide walks through the full flow from checking product requirements to issuing a card.

<Callout icon="💡" theme="info">
  If your card product only requires basic fields (Simplified KYC), the existing cardholder creation flow works as before — no changes needed. Use [List Products](/card-issuance/v1.6/api-reference/list-card-products) to check what your product requires.
</Callout>

## Overview

```mermaid theme={null}
sequenceDiagram
    participant M as Merchant
    participant U as UQPAY API
    participant S as Sumsub (IDV)

    M->>U: 1. GET /v1/issuing/products
    U-->>M: required_fields per product

    M->>U: 2. POST /v1/issuing/cardholders (with KYC fields)
    alt THIRD_PARTY method
        U-->>M: cardholder_status: SUCCESS
    else SUMSUB_REDIRECT method
        U-->>M: cardholder_status: INCOMPLETE + idv_verification_url
        M->>S: 3. Redirect cardholder to IDV URL
        S-->>U: IDV callback
        U-->>M: Webhook: cardholder.kyc.status_changed
    end

    M->>U: 4. POST /v1/issuing/cards
    U-->>M: Card created
```

## Prerequisites

Before making API calls, obtain an access token:

```bash theme={null}
curl -X POST "https://api-sandbox.uqpaytech.com/api/v1/connect/token" \
  -H "Content-Type: application/json" \
  -H "x-api-key: {your_api_key}" \
  -H "x-client-id: {your_client_id}"
```

```json theme={null}
{
  "auth_token": "eyJhbGciOiJIUzI1NiIs...",
  "expired_at": 1775210493
}
```

Use the returned `auth_token` in all subsequent requests via the `x-auth-token` header.

## Step 1: Check Product Requirements

Call [List Products](/card-issuance/v1.6/api-reference/list-card-products) to identify which fields your target product requires.

```bash theme={null}
curl -X GET "https://api-sandbox.uqpaytech.com/api/v1/issuing/products?page_size=10&page_number=1" \
  -H "Content-Type: application/json" \
  -H "x-auth-token: {your_auth_token}"
```

In the response, look at the `required_fields` array. An Enhanced KYC product will include `identity`, `residential_address`, and `kyc_verification` as required fields. Here is an example of an Enhanced product (BIN `46651711`):

```json theme={null}
{
  "product_id": "0d8f10de-c888-4107-ab65-1cc9deb31b3b",
  "card_bin": "46651711",
  "card_scheme": "VISA",
  "card_form": ["VIR"],
  "card_currency": ["USD", "SGD", "HKD"],
  "mode_type": "SHARE",
  "kyc_level": "ENHANCED",
  "max_card_quota": 3001,
  "product_status": "ENABLED",
  "required_fields": [
    { "name": "first_name", "type": "string", "required": true },
    { "name": "last_name", "type": "string", "required": true },
    { "name": "email", "type": "string", "required": true },
    { "name": "country_code", "type": "string", "required": true },
    { "name": "date_of_birth", "type": "string", "required": true },
    { "name": "phone_number", "type": "string", "required": true },
    { "name": "nationality", "type": "string", "required": true },
    {
      "name": "identity",
      "type": "object",
      "required": true,
      "fields": [
        { "name": "type", "type": "string", "required": true },
        { "name": "number", "type": "string", "required": true },
        { "name": "front_file", "type": "string", "required": true },
        { "name": "back_file", "type": "string", "required": false },
        { "name": "hand_file", "type": "string", "required": false }
      ]
    },
    {
      "name": "residential_address",
      "type": "object",
      "required": true,
      "fields": [
        { "name": "country", "type": "string", "required": true },
        { "name": "state", "type": "string", "required": true },
        { "name": "city", "type": "string", "required": true },
        { "name": "district", "type": "string", "required": false },
        { "name": "line1", "type": "string", "required": true },
        { "name": "line2", "type": "string", "required": false },
        { "name": "line_en", "type": "string", "required": true },
        { "name": "postal_code", "type": "string", "required": true }
      ]
    },
    {
      "name": "kyc_verification",
      "type": "object",
      "required": true,
      "fields": [
        { "name": "method", "type": "string", "required": true },
        {
          "name": "kyc_proof",
          "type": "object",
          "required": false,
          "fields": [
            { "name": "provider", "type": "string", "required": false },
            { "name": "reference_id", "type": "string", "required": false }
          ]
        }
      ]
    }
  ]
}
```

<Callout icon="💡" theme="info">
  The `required_fields` tell you exactly what information is needed. Only fields marked `"required": true` are mandatory — optional fields can be omitted.
</Callout>

## Step 2: Create Cardholder with Enhanced KYC

Call [Create Cardholder](/card-issuance/v1.6/api-reference/create-cardholder) with the full set of required fields plus `kyc_verification`.

<Callout icon="⚠️" theme="warn">
  The `residential_address.country` and `nationality` fields are subject to region restrictions. See [Cardholder Region Restrictions](/card-issuance/v1.6/guide/cardholder-region-restrictions) for the full list of supported countries and sanctioned nationalities.
</Callout>

<Note>
  Field constraints for Enhanced cards:

  * The combined length of `first_name` and `last_name` must not exceed 26 letters.
  * `residential_address.postal_code` must be 4 to 10 characters long, inclusive.
</Note>

There are two verification methods — choose the one that fits your use case:

| Method            | When to use                                                            | Result                                                         |
| ----------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------- |
| `SUMSUB_REDIRECT` | You want UQPAY to handle IDV via Sumsub                                | Returns an IDV URL for the cardholder to complete verification |
| `THIRD_PARTY`     | You have already verified the cardholder through your own KYC provider | Cardholder is verified immediately                             |

### Option A: SUMSUB\_REDIRECT

Use this if you want UQPAY to handle identity verification via Sumsub. You will receive an IDV URL to redirect your cardholder to.

```bash theme={null}
curl -X POST "https://api-sandbox.uqpaytech.com/api/v1/issuing/cardholders" \
  -H "Content-Type: application/json" \
  -H "x-auth-token: {your_auth_token}" \
  -H "x-idempotency-key: cc58fa96-7a49-4be1-a70b-85075c1b4957" \
  -d '{
    "first_name": "Sarah",
    "last_name": "Chen",
    "email": "sarah.chen@example.com",
    "country_code": "SG",
    "phone_number": "90755646",
    "date_of_birth": "1992-06-15",
    "nationality": "SG",
    "identity": {
      "type": "PASSPORT",
      "number": "E98765432",
      "front_file": "<base64_encoded_image>",
      "back_file": "<base64_encoded_image>",
      "hand_file": "<base64_encoded_image>"
    },
    "residential_address": {
      "country": "SG",
      "state": "Singapore",
      "city": "Singapore",
      "district": "Buona Vista",
      "line1": "9 N Buona Vista Dr",
      "line2": "THE METROPOLIS",
      "line_en": "9 N Buona Vista Dr, THE METROPOLIS",
      "postal_code": "138666"
    },
    "kyc_verification": {
      "method": "SUMSUB_REDIRECT"
    }
  }'
```

**Response** — the cardholder enters `INCOMPLETE` status with an IDV link:

```json theme={null}
{
  "cardholder_id": "9d6017b2-0c2f-4b2e-876b-992b0db9597d",
  "cardholder_status": "INCOMPLETE",
  "idv_verification_url": "https://in.sumsub.com/websdk/p/sbx_MVSJTHTZj77PZggH",
  "idv_url_expires_at": "2026-04-04T17:32:50+08:00"
}
```

Redirect your cardholder to `idv_verification_url` to complete identity verification, then wait for the webhook notification ([Step 3](#step-3-wait-for-kyc-approval-sumsub_redirect-only)).

### Option B: THIRD\_PARTY

Use this if you have already completed identity verification through your own KYC provider and have a proof reference.

```bash theme={null}
curl -X POST "https://api-sandbox.uqpaytech.com/api/v1/issuing/cardholders" \
  -H "Content-Type: application/json" \
  -H "x-auth-token: {your_auth_token}" \
  -H "x-idempotency-key: {unique_uuid}" \
  -d '{
    "first_name": "Sarah",
    "last_name": "Chen",
    "email": "sarah.chen@example.com",
    "country_code": "SG",
    "phone_number": "90755646",
    "date_of_birth": "1992-06-15",
    "nationality": "SG",
    "identity": {
      "type": "PASSPORT",
      "number": "E98765432",
      "front_file": "<base64_encoded_image>",
      "back_file": "<base64_encoded_image>",
      "hand_file": "<base64_encoded_image>"
    },
    "residential_address": {
      "country": "SG",
      "state": "Singapore",
      "city": "Singapore",
      "district": "Buona Vista",
      "line1": "9 N Buona Vista Dr",
      "line2": "THE METROPOLIS",
      "line_en": "9 N Buona Vista Dr, THE METROPOLIS",
      "postal_code": "138666"
    },
    "kyc_verification": {
      "method": "THIRD_PARTY",
      "kyc_proof": {
        "provider": "YOUR_PROVIDER",
        "reference_id": "your_provider_ref_1234567890",
        "documents": [
          { "file_id": "b3d9d2d5-4c12-4946-a09d-953e82sed2b0", "report_type": "IDV" },
          { "file_id": "7c4ff2cd-1bf6-4aaa-bf16-266771425011", "report_type": "AML" }
        ]
      }
    }
  }'
```

<Callout icon="📌" theme="info">
  `kyc_proof.reference_id` must be at least 10 characters and globally unique.
</Callout>

### Attach compliance reports

`kyc_proof.documents` carries the compliance report files behind your third-party verification. Upload each file first with [Upload A File](/account-center/v1.6/api-reference/upload-file) to obtain a `file_id`, then reference it here with its `report_type`.

You must include an identity verification report; an anti-money-laundering report is optional. There are two ways to supply the reports, depending on how your provider formats them:

| Layout         | `documents` entries                                                        |
| -------------- | -------------------------------------------------------------------------- |
| Separate files | `{ "report_type": "IDV" }` **plus** an optional `{ "report_type": "AML" }` |
| Combined file  | A single `{ "report_type": "IDV_AML" }` covering both                      |

| `report_type` | Meaning                                     | Required                           |
| ------------- | ------------------------------------------- | ---------------------------------- |
| `IDV`         | Identity verification report only           | Yes (unless supplied as `IDV_AML`) |
| `AML`         | Anti-money-laundering screening report only | No                                 |
| `IDV_AML`     | One file covering both IDV and AML          | Satisfies the IDV requirement      |

**Response** — the cardholder is verified immediately:

```json theme={null}
{
  "cardholder_id": "9d6017b2-0c2f-4b2e-876b-992b0db9597d",
  "cardholder_status": "SUCCESS"
}
```

You can proceed directly to [Step 4: Create Card](#step-4-create-card).

## Step 3: Wait for KYC Approval (SUMSUB\_REDIRECT only)

If you used `SUMSUB_REDIRECT`, subscribe to the `cardholder.kyc.status_changed` webhook to receive real-time KYC status updates.

**Webhook payload example** (KYC approved):

```json theme={null}
{
  "version": "V1.6.0",
  "event_name": "ISSUING",
  "event_type": "cardholder.kyc.status_changed",
  "event_id": "d92ab1ec-1737-4b3c-bedb-7500a3c02677",
  "source_id": "9d6017b2-0c2f-4b2e-876b-992b0db9597d",
  "data": {
    "cardholder_id": "9d6017b2-0c2f-4b2e-876b-992b0db9597d",
    "cardholder_status": "SUCCESS",
    "country_code": "SG",
    "create_time": "2026-04-03T17:32:50+08:00",
    "date_of_birth": "1992-06-15",
    "email": "sarah.chen@example.com",
    "first_name": "Sarah",
    "idv_provider": "SUMSUB",
    "idv_status": "PASSED",
    "last_name": "Chen",
    "nationality": "SG",
    "phone_number": "90755646",
    "update_time": "2026-04-03T17:34:49+08:00"
  }
}
```

When `cardholder_status` becomes `SUCCESS`, the cardholder is ready for card issuance.

<Callout icon="⚠️" theme="warn">
  Cards cannot be issued while the cardholder is in `PENDING` status. Wait for KYC approval before proceeding.
</Callout>

## Step 4: Create Card

Once `cardholder_status` is `SUCCESS`, call [Create Card](/card-issuance/v1.6/api-reference/create-card):

<Callout icon="📌" theme="info">
  The sample below uses `card_currency: "USD"` for sandbox. In production, set `card_currency` to `XUSD`.
</Callout>

```bash theme={null}
curl -X POST "https://api-sandbox.uqpaytech.com/api/v1/issuing/cards" \
  -H "Content-Type: application/json" \
  -H "x-auth-token: {your_auth_token}" \
  -H "x-idempotency-key: bf705cbd-27f0-48d1-a60b-212134a89ad7" \
  -d '{
    "cardholder_id": "9d6017b2-0c2f-4b2e-876b-992b0db9597d",
    "card_product_id": "0d8f10de-c888-4107-ab65-1cc9deb31b3b",
    "card_currency": "USD",
    "card_limit": 1000
  }'
```

**Response:**

```json theme={null}
{
  "card_id": "d26f2287-434b-41a4-af47-f06dbf6f9e71",
  "card_order_id": "c004375c-8137-4b94-b948-4282bff33625",
  "card_status": "PENDING",
  "order_status": "PROCESSING",
  "create_time": "2026-04-03T17:35:55+08:00",
  "risk_controls": {}
}
```

## Error Handling

### KYC insufficient at card creation

If you attempt to create a card but the cardholder hasn't met the product's KYC requirements, you will receive an error with `missing_fields` indicating which fields are still needed:

```json theme={null}
{
  "code": "kyc_insufficient",
  "message": "Cardholder KYC information is insufficient for this product.",
  "missing_fields": ["identity", "residential_address"]
}
```

You can either:

1. Update the cardholder first via [Update Cardholder](/card-issuance/v1.6/api-reference/update-cardholder), then retry card creation.
2. Supply the missing fields inline by passing `cardholder_required_fields` in the Create Card request.

### Cardholder in PENDING status

Creating a card while the cardholder's `cardholder_status` is `PENDING` will be rejected. Wait for the KYC review to complete before retrying.
