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

# Updating KYC information

> How-to task page: guide the user through re-verification after documents / KYC data expire (kycApplyMode=H5-RENEWAL / guide page type=8). Entry point is kycRenewalRequired=true; organized as a two-step flow, including the retry loop after a rejection and when the restriction is lifted.

## 📄 Guide

Identity documents and KYC data both have an expiry. Once they expire the user must complete verification again for the account to stay compliant and keep spending normally. DCS notifies you proactively when it detects an expiry; all you have to do is guide the user to re-capture their documents and selfie on a DCS-hosted H5 page.

Renewal reuses the same two-step H5 KYC flow; the only differences are that the application mode is `H5-RENEWAL` and the guide page type is `type=8`.

## When to use it

A user needs to renew their KYC data whenever either of these holds:

* [Query a user's KYC information](./kyc-info) returns `kycRenewalRequired=true`;
* You receive the user-level [`KYC` webhook](../webhooks/events-and-schema#kyc) with `kycRenewalRequired=true`.

The webhook's `kycRenewalType` states which factors need renewing (`POI` proof of identity / `SELFIE`), which you can use to prompt for only that item in your front end.

> **Until the renewal completes, some of the user's operations (such as spending) may be restricted.** Guide the user through it as early as possible.

## How this relates to the other KYC paths

| Your situation                                                                         | Use                                          |
| -------------------------------------------------------------------------------------- | -------------------------------------------- |
| Brand-new user, you collect the documents and submit them via API                      | [Apply for KYC (API mode)](./apply-kyc)      |
| Brand-new user, let them fill everything in on the DCS-hosted page                     | [H5 KYC guide page](./h5-kyc-guidance)       |
| **The user's data has expired and needs re-verification**                              | **This page**                                |
| The user already completed KYC under the DeCard-Managed model and you want to reuse it | [KYC information migration](./kyc-migration) |

## Interaction flow

A renewal can be rejected. Once rejected the ticket is terminal, but the user **still needs to renew** (`kycRenewalRequired` remains `true`); apply for a new ticket to let them retry until it passes and `kycRenewalRequired` becomes `false`.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-kyc-renewal-light.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=ed9b8c4655d4d5bfc10dfdc341a236cb" alt="KYC renewal interaction flow" width="476" height="973" data-path="imgs/en/diagrams/pa-kyc-renewal-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-kyc-renewal-dark.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=bf2747642f5d04d5ffa51f44c1be113b" alt="KYC renewal interaction flow" width="476" height="973" data-path="imgs/en/diagrams/pa-kyc-renewal-dark.svg" />
</Frame>

## Step 1: Apply for the renewal ticket (you)

**`POST /open-api/kyc-ticket/v1/apply-kyc-h5`**

| Field          | Type   | Required | Constraints | Description                                                  |
| -------------- | ------ | -------- | ----------- | ------------------------------------------------------------ |
| `kycTicketRef` | string | Yes      | ≤50         | Your own business idempotency key; you can query by it later |
| `customerId`   | string | Yes      | ≤50         | The user whose data needs renewing                           |
| `kycApplyMode` | string | Yes      | ≤20         | Fixed `H5-RENEWAL`                                           |

```json theme={null}
{
  "kycTicketRef": "kyc-renew-20260728-0001",
  "customerId": "1000000123",
  "kycApplyMode": "H5-RENEWAL"
}
```

<Warning>
  This step **synchronously checks that the user really does need to renew**. If they do not (`kycRenewalRequired` is not `true`), no ticket is created and `DAPI_KYC_RENEWAL_NOT_REQUIRED` is returned. Confirm first via [Query a user's KYC information](./kyc-info) or the webhook.
</Warning>

<Warning>
  Only **one** in-progress (`INIT`) renewal ticket is allowed per user at a time; you can apply again only after the previous one reaches a terminal state (`PASSED` / `REJECTED`).
</Warning>

## Step 2: Exchange for the renewal guide link (you)

**`POST /open-api/card-redirect/v1/guidance-link`**

| Field                   | Type   | Required | Constraints | Description                                                                                                               |
| ----------------------- | ------ | -------- | ----------- | ------------------------------------------------------------------------------------------------------------------------- |
| `type`                  | string | Yes      | ≤1          | Fixed `8` (update KYC information)                                                                                        |
| `customerId`            | string | Yes      | ≤50         | Same as step 1                                                                                                            |
| `kycTicketId`           | string | Yes      | ≤50         | The `kycTicketId` returned in step 1                                                                                      |
| `errorRedirectUrl`      | string | **Yes**  | ≤200        | Error page to redirect to when the renewal fails. **Required** for `type=8`; omitting it returns `DAPI_SYS_ILLEGAL_PARAM` |
| `language`              | string | Yes      | Length 2    | `zh` / `en`; non-zh countries are uniformly mapped to `en`                                                                |
| `theme`                 | string | Yes      | ≤10         | Such as `default`                                                                                                         |
| `mode`                  | string | Yes      | ≤10         | `light` / `dark`                                                                                                          |
| `userAgent`             | string | Yes      | ≤300        | User browser UA                                                                                                           |
| `successfulRedirectUrl` | string | No       | ≤200        | Redirect address on success                                                                                               |
| `submitAutoClosed`      | string | No       | ≤1          | `Y` closes the page automatically after a successful submission / `N` does not                                            |
| `primaryColor`          | string | No       | ≤7          | Main colour, such as `#FFFFFF`                                                                                            |

> `type=8` does **not** need `profileId` (that is required only for `type=7`, apply for KYC-H5).

The response `data` is a string — the H5 URL you hand to the user. The link has a limited lifetime; if it expires while the ticket is still `INIT`, call this endpoint again for a fresh link — you do **not** need to apply for a new ticket.

## Step 3: Receive the result and retry if needed

Learn the review outcome from the [`KYC_TICKET` webhook](../webhooks/events-and-schema) or by calling `GET /open-api/kyc-ticket/v1/detail`:

* **`PASSED`**: the renewal is complete. You will then receive the user-level `KYC` webhook with `kycRenewalRequired=false` and the restriction is lifted.
* **`REJECTED`**: this renewal was rejected and `kycRenewalRequired` is **still `true`**. Go back to step 1 and apply for a new ticket with a **new `kycTicketRef`**.

### Ticket status (renewal mode)

In renewal mode a ticket only ever takes these three statuses — `NEED_VERIFY` and `PENDING` do **not** occur:

| Status     | Meaning                                                                           | Terminal | Your next step                                                               |
| ---------- | --------------------------------------------------------------------------------- | :------: | ---------------------------------------------------------------------------- |
| `INIT`     | Ticket created, waiting for the user to submit on H5; review also stays at `INIT` |    No    | Send the H5 link to the user; call `guidance-link` again if the link expires |
| `PASSED`   | Review passed, renewal complete                                                   |    Yes   | Wait for the `KYC` webhook to report `kycRenewalRequired=false`              |
| `REJECTED` | Review rejected                                                                   |    Yes   | `kycRenewalRequired` is still `true`; re-apply with a new `kycTicketRef`     |

## Error codes

### apply-kyc-h5 (`kycApplyMode=H5-RENEWAL`)

In addition to the common error codes listed on the [H5 KYC guide page](./h5-kyc-guidance), renewal mode can also return:

| Error code                         | Meaning                              | Trigger                                                                   |                 Retryable                 |
| ---------------------------------- | ------------------------------------ | ------------------------------------------------------------------------- | :---------------------------------------: |
| `DAPI_KYC_RENEWAL_NOT_REQUIRED`    | customer does not need KYC renewal   | This user does not currently need to renew, or their record is incomplete | ❌ Confirm `kycRenewalRequired=true` first |
| `DAPI_TICKET_APPLY_LIMIT_EXCEEDED` | Ticket application exceeds the limit | Too many applications for the same user; the intake rate limit was hit    |            ✅ Back off and retry           |

### guidance-link (`type=8`)

| Error code                         | Meaning                     | Trigger                                                                                              |
| ---------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------- |
| `DAPI_SYS_ILLEGAL_PARAM`           | System illegal param        | `kycTicketId` or `errorRedirectUrl` is empty                                                         |
| `DAPI_KYC_TICKET_NOT_FOUND`        | kyc ticket not found        | Ticket does not exist / belongs to someone else / is not a renewal ticket                            |
| `DAPI_KYC_TICKET_IS_IN_PROCESSING` | KYC ticket is in processing | The ticket has already been submitted and is still being processed; the operation cannot be repeated |
| `DAPI_KYC_TICKET_ALREADY_PASSED`   | KYC ticket already passed   | The ticket already passed                                                                            |

## Prerequisites

* You hold the Enterprise ApiKey / SecretKey — see [First steps](../../getting-started/first-steps).
* You have confirmed `kycRenewalRequired=true` for this user — see [Query a user's KYC information](./kyc-info).
* You have configured a webhook endpoint that can receive `KYC` and `KYC_TICKET` events — see [Webhook configuration](../webhooks/configuration).

## Next steps

* Check whether a user currently needs to renew → [Query a user's KYC information](./kyc-info)
* Reuse KYC the user already completed under the DeCard-Managed model → [KYC information migration](./kyc-migration)
* Webhook events and fields → [Events and data structures](../webhooks/events-and-schema)
