> ## 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.

# Card management (freeze / unfreeze / replacement / PIN)

> Clears up the ambiguity of freeze and unfreeze sharing one endpoint by spelling out the boolean switch.

## 📄 Guide

Once a card is issued it has to be maintained for the rest of its life: the cardholder may want to freeze it for a while, terminate it after losing it, activate the physical card when it arrives, or reset a forgotten PIN. Whether the request comes from an operator in your back office or from the cardholder tapping a button in your app, the same `/open-api/card/v1/` endpoints let you address one specific card by `cardId` and act on it.

As a licensed issuer with its own BIN, DCS keeps the underlying state in sync with the card network and the issuing processor. You only have to reason about the business semantics: what state this card is in, and what may be done to it.

> **Prerequisite**: you need a successfully issued card and its `cardId`. If you are not sure how to apply for one, read [Card issuing](./card-issuing) first.

## Mental model: the card state machine

DCS expresses the life cycle of a card in the `status` field, and every management operation is really just a transition in this state machine.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-card-states-light.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=25789d9eab5836198672f1c86965404a" alt="Card state machine" width="812" height="320" data-path="imgs/en/diagrams/pa-card-states-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-card-states-dark.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=b8cfa6fa1e23e894ef6905de82dec533" alt="Card state machine" width="812" height="320" data-path="imgs/en/diagrams/pa-card-states-dark.svg" />
</Frame>

| Status                                     | Meaning                                                                                            | Who can change it | Operations allowed                 |
| :----------------------------------------- | :------------------------------------------------------------------------------------------------- | :---------------- | :--------------------------------- |
| `PENDING_ACTIVATION` (awaiting activation) | The initial state of an issued physical card that has not been activated yet (physical cards only) | Partner           | Activate                           |
| `ACTIVATED` (active)                       | The card can transact normally                                                                     | Partner           | Freeze, terminate                  |
| `FROZEN` (frozen)                          | A suspension raised by the cardholder or the partner, which the partner can lift                   | Partner           | Unfreeze, terminate                |
| `BLOCKED` (blocked)                        | A block applied by the issuer or by risk control, which the partner **cannot** lift                | DCS only          | Wait for DCS to lift it, terminate |
| `INVALID` (invalid)                        | Terminated, permanently dead, **irreversible**                                                     | —                 | None                               |

> **How FROZEN differs from BLOCKED**: `FROZEN` is a reversible switch in the partner's hands, while `BLOCKED` is a restriction imposed by the issuer or risk control for compliance or security reasons and only DCS can lift it. Neither is final; `INVALID` is the only final state.

### Card status reason (statusReason)

While a card is `FROZEN`, `BLOCKED` or `INVALID`, the `statusReason` returned by the card detail endpoint tells you why it got there, which you can use to explain the situation to the cardholder or to decide what to do next.

| statusReason             | Applies to | Description                                                                                             |
| :----------------------- | :--------- | :------------------------------------------------------------------------------------------------------ |
| `NORMAL`                 | All        | No specific reason                                                                                      |
| `USER_FREEZE`            | FROZEN     | The cardholder froze the card                                                                           |
| `USER_REQUESTED_CLOSURE` | BLOCKED    | The cardholder asked to close the card                                                                  |
| `COMPLIANCE_REVIEW`      | BLOCKED    | Blocked for compliance review                                                                           |
| `AUTHENTICATION_FAILED`  | FROZEN     | Frozen after failed verification (three consecutive wrong CVV or PIN entries; the card is suspended)    |
| `SECURITY_RESTRICTION`   | BLOCKED    | Blocked by risk control for security reasons                                                            |
| `VERIFICATION_OVERDUE`   | BLOCKED    | Verification overdue (the customer did not respond or supply the required evidence within the deadline) |
| `ACCOUNT_TERMINATED`     | BLOCKED    | The account has been terminated                                                                         |
| `OTHER`                  | BLOCKED    | Other reasons                                                                                           |

***

## Operations at a glance

Apart from the query endpoints, all of the endpoints below are `POST` and all sit under `/open-api/card/v1/`. For the authentication headers, the signature and the response envelope, see [Authentication and security](../../integration-resources/authentication).

| Operation                     | Method and path                               | Who does it   | Applies to          |
| :---------------------------- | :-------------------------------------------- | :------------ | :------------------ |
| Query card detail             | `GET /open-api/card/v1/detail`                | Partner       | All cards           |
| Freeze / unfreeze             | `POST /open-api/card/v1/freeze`               | Partner       | All cards           |
| Terminate                     | `POST /open-api/card/v1/terminate`            | Partner       | All cards           |
| Activate a physical card      | `POST /open-api/card/v1/physical-active`      | Partner       | Physical cards only |
| Reset PIN                     | `POST /open-api/card/v1/reset-pin`            | Partner (PCI) | All cards           |
| Get card shipping information | `GET /open-api/card/v1/shipping-info`         | Partner       | Physical cards only |
| Get sensitive card data       | `POST /open-api/card/v1/retrieve-secure-card` | Partner (PCI) | All cards           |
| Card replacement (reissue)    | `POST /open-api/card-order/v1/replace`        | Partner       | All cards           |

<Note>
  most of the operations above live under `/open-api/card/v1/`. **Card replacement** belongs to the card order domain, `/open-api/card-order/v1/replace`, and is covered in [Card replacement (reissue)](#card-replacement-reissue) below.
</Note>

### Common call sequence for card operations

Freeze, unfreeze, terminate and the other action endpoints all follow the same sequence: the partner receives the cardholder's request, calls the matching endpoint, and returns the result.

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-card-ops-seq-light.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=5cbd19f6c394635336479c2e4cc6fd08" alt="Common sequence for card action calls" width="476" height="366" data-path="imgs/en/diagrams/pa-card-ops-seq-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-card-ops-seq-dark.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=43ba9fbc7522d0d40f268a8127448d20" alt="Common sequence for card action calls" width="476" height="366" data-path="imgs/en/diagrams/pa-card-ops-seq-dark.svg" />
</Frame>

> **About the response envelope**: every endpoint returns the same envelope, `{ code, message, messageDetail, data }`. `code` carries the result, `message` and `messageDetail` carry the display text (`messageDetail` can include a title, an icon and a link you can show to the end user), and `data` carries the business payload. For the success value of `code` and the full error code dictionary, see [Authentication and security](../../integration-resources/authentication).

***

## Query card detail

```
GET /open-api/card/v1/detail
```

| Parameter | In    | Type   | Required | Description |
| :-------- | :---- | :----- | :------- | :---------- |
| `cardId`  | query | string | Yes      | Card ID     |

Returns the card status, `statusReason`, card type, `panFirst6` (the first six digits of the card number), `panLast4` (the last four digits) and similar data. It does **not** return the full card number, the CVV or any other sensitive data (for that, see "Get sensitive card data" below).

```json theme={null}
{
  "code": "...",
  "message": "...",
  "data": {
    "cardId": "card_xxx",
    "enterpriseId": "ent_xxx",
    "profileId": "prof_xxx",
    "type": "VIRTUAL",
    "customerId": "cus_xxx",
    "status": "ACTIVATED",
    "statusReason": "NORMAL",
    "panFirst6": "441364",
    "panLast4": "0123",
    "createTime": "2026-01-01T10:00:00+08:00",
    "modifyTime": "2026-01-01T10:00:00+08:00"
  }
}
```

***

## Freeze and unfreeze

**Freeze and unfreeze are the same endpoint**, and the `freeze` boolean decides the direction. This is the easiest trap on this page, so do not treat them as two endpoints.

```
POST /open-api/card/v1/freeze
```

| Field          | Type    | Required  | Description                                                               |
| :------------- | :------ | :-------- | :------------------------------------------------------------------------ |
| `cardId`       | string  | Yes       | Card ID, max length 50                                                    |
| `freeze`       | boolean | Yes       | **The freeze switch**: `true` freezes the card, `false` unfreezes it      |
| `freezeReason` | string  | See below | Reason for freezing, max length 20, for example `USER_FREEZE` or `NORMAL` |

> **When `freezeReason` is required**: only when freezing (`freeze=true`). When unfreezing (`freeze=false`) the server does not read the field, so it is ignored whether you send it or leave it out.
>
> Unfreezing the same card is rate-limited per day; exceeding it returns `DAPI_CARD_UNFREEZE_DAILY_LIMIT_EXCEEDED`, so retry the next day.

Request example (freeze):

```json theme={null}
{
  "cardId": "card_xxx",
  "freeze": true,
  "freezeReason": "USER_FREEZE"
}
```

Request example (unfreeze):

```json theme={null}
{
  "cardId": "card_xxx",
  "freeze": false,
  "freezeReason": "NORMAL"
}
```

The example above is shown for completeness; an unfreeze request can carry nothing but `cardId` and `freeze=false`.

The response `data` returns the whole card object as it stands after the operation (the same structure as [Query card detail](#query-card-detail)), with `status` now `FROZEN` or `ACTIVATED`.

<Note>
  the `freeze` endpoint only moves a card between `ACTIVATED` and `FROZEN`. A `BLOCKED` card was blocked by the issuer or by risk control, the partner cannot release it through this endpoint, and DCS has to be contacted.
</Note>

***

## Termination

Termination is **irreversible**. Once a card is terminated its status becomes `INVALID` and it can never be brought back into use.

```
POST /open-api/card/v1/terminate
```

| Field              | Type   | Required | Description                                                                                        |
| :----------------- | :----- | :------- | :------------------------------------------------------------------------------------------------- |
| `cardId`           | string | Yes      | Card ID, max length 50                                                                             |
| `invalidateReason` | string | Yes      | Reason for termination, max length 20. `CARD_LOST` for a lost card, `CARD_STOLEN` for a stolen one |

```json theme={null}
{
  "cardId": "card_xxx",
  "invalidateReason": "CARD_LOST"
}
```

The response `data` returns the terminated card object, with `status` = `INVALID`.

***

## Card replacement (reissue)

When a cardholder's card is lost, damaged or otherwise has to be swapped, you can raise a **card replacement (reissue)** order against an existing card: the old card is voided and a new one is issued. A replacement creates a card order with `type=REPLACEMENT`.

> **Hard rules for card replacement**:
>
> * **The replacement is always a virtual card.** Both virtual and physical cards can be replaced, but the new card is always virtual. If the cardholder still needs a physical card, run [virtual-to-physical](./physical-card) again after the replacement completes.
> * **Card replacement is rate-limited within a 24-hour window**; exceeding it returns `DAPI_REPLACE_CARD_APPLY_LIMIT_EXCEEDED`, so back off before retrying.
> * **The card number (PAN) changes.** This differs from virtual-to-physical, where the PAN is preserved: a replacement issues a brand-new PAN. Remind the cardholder to update any stored auto-debits, subscriptions and card-on-file details with merchants.

```
POST /open-api/card-order/v1/replace
```

| Field           | Type   | Required | Description                                |
| :-------------- | :----- | :------- | :----------------------------------------- |
| `cardOrderRef`  | string | Yes      | Card order idempotency key, max length 50  |
| `replaceCardId` | string | Yes      | The `cardId` being replaced, max length 50 |

```json theme={null}
{
  "cardOrderRef": "your-idempotent-ref",
  "replaceCardId": "card_xxx"
}
```

A successful response returns a card order. The key fields are:

| Field                       | Description                                  |
| :-------------------------- | :------------------------------------------- |
| `cardOrderId`               | Card order ID                                |
| `type`                      | Order type, `REPLACEMENT` here               |
| `cardId`                    | The `cardId` of the new card                 |
| `replaceCardId`             | The `cardId` of the card that was replaced   |
| `status`                    | Order status, see the note below             |
| `errorCode` / `errorReason` | Failure code and reason when the order fails |

> **Which order statuses to trust**: in the current code, a card order succeeds with the final status `COMPLETED` and fails with `FAILED`, and whether `cardId` has been generated is a useful cross-check. Integrate against `COMPLETED`; some older apiReference pages still describe `PENDING/SUCCEED/FAILED`.

### Card replacement flow

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-replace-card-seq-light.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=4a9f186cf694f8d3ad26f4f34e154434" alt="Card replacement flow" width="638" height="722" data-path="imgs/en/diagrams/pa-replace-card-seq-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/pa-replace-card-seq-dark.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=026d18c6a7ae191cfebe4ac32d533311" alt="Card replacement flow" width="638" height="722" data-path="imgs/en/diagrams/pa-replace-card-seq-dark.svg" />
</Frame>

***

## Activate a physical card

**Only physical cards need activation; a virtual card is `ACTIVATED` as soon as it is issued.** A physical card sits in `PENDING_ACTIVATION` from the moment it is shipped, and the partner calls this endpoint once the cardholder has it in hand.

```
POST /open-api/card/v1/physical-active
```

| Field    | Type   | Required | Description            |
| :------- | :----- | :------- | :--------------------- |
| `cardId` | string | Yes      | Card ID, max length 50 |

The response `data` returns the card object with `status` moved from `PENDING_ACTIVATION` to `ACTIVATED`. For how a physical card is applied for and shipped, see [Physical card](./physical-card).

***

## Get card shipping information

Once a physical card has shipped you can look up the tracking number and show the cardholder how the delivery is progressing.

```
GET /open-api/card/v1/shipping-info
```

| Parameter | In    | Type   | Required | Description |
| :-------- | :---- | :----- | :------- | :---------- |
| `cardId`  | query | string | Yes      | Card ID     |

```json theme={null}
{
  "code": "...",
  "data": {
    "cardId": "card_xxx",
    "trackingNumber": "SF1234567890",
    "trackingCompanyName": "SF Express"
  }
}
```

***

## Reset PIN

`reset-pin` sets the PIN of a physical card. To meet PCI requirements, every sensitive field (the card's expiry date, the CVV2, the last four digits of the card number and the new PIN) must be **encrypted with AES/GCM** before it is sent, and the request must carry the `iv` used for that encryption.

> **This endpoint is only open to partners that hold PCI certification.** If you do not, use the guidance page instead (see "Resetting the PIN and revealing card credentials without PCI certification" below).

```
POST /open-api/card/v1/reset-pin
```

| Field                 | Type   | Required | Description                                                          |
| :-------------------- | :----- | :------- | :------------------------------------------------------------------- |
| `cardId`              | string | Yes      | Card ID, max length 50                                               |
| `encryptedExpireDate` | string | Yes      | The encrypted expiry date of the card, max length 200                |
| `encryptedCvv2`       | string | Yes      | The encrypted CVV2 of the card, max length 200                       |
| `encryptedPanLast4`   | string | Yes      | The encrypted last four digits of the card number, max length 200    |
| `encryptedNewPin`     | string | Yes      | The encrypted new PIN, max length 200                                |
| `iv`                  | string | Yes      | The initialization vector used to encrypt and decrypt, max length 20 |

The response `data` is a boolean; `true` means the reset succeeded.

**Encryption algorithm (AES/GCM/NoPadding)**: use the enterprise secret (`enterpriseSecret`) as the AES key, generate a random 12-byte IV (Base64 encoded) for every call, and use a 128-bit authentication tag. Reference implementation:

```java theme={null}
// Generate a random IV (12 bytes is the recommended size for GCM)
public static String generateIV() {
    byte[] iv = new byte[12];
    new SecureRandom().nextBytes(iv);
    return Base64.getEncoder().encodeToString(iv);
}

// GCM encryption
public static String encryptGCM(String plaintext, String enterpriseSecret, String base64IV) {
    SecretKey key = new SecretKeySpec(Base64.getDecoder().decode(enterpriseSecret), "AES");
    byte[] iv = Base64.getDecoder().decode(base64IV);
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));
    byte[] ct = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
    return Base64.getEncoder().encodeToString(ct);
}
```

> For the concepts behind the PIN, what a PIN and a CVV are each for and when they are needed, see [Virtual card](./virtual-card).

***

## Get sensitive card data

`retrieve-secure-card` returns the full card number (`pan`), the `cvv2` and the expiry date (`expireDate`). The values come back encrypted and are decrypted with the `iv` using the same AES/GCM algorithm as above.

> **This endpoint is only open to partners that hold PCI certification.** The decrypted plaintext should be shown to the cardholder directly in the front end and **must not be persisted anywhere in the partner back end**.

```
POST /open-api/card/v1/retrieve-secure-card
```

| Field    | Type   | Required | Description            |
| :------- | :----- | :------- | :--------------------- |
| `cardId` | string | Yes      | Card ID, max length 50 |

```json theme={null}
{
  "code": "...",
  "data": {
    "cardId": "card_xxx",
    "pan": "<encrypted card number>",
    "cvv2": "<encrypted CVV2>",
    "expireDate": "<encrypted expiry date>",
    "iv": "<IV used for decryption>"
  }
}
```

The alternative for partners without PCI certification, and the details of the two-step SecureToken retrieval, are covered in [Get sensitive card data](./secure-card).

***

## Resetting the PIN and revealing card credentials without PCI certification

A partner without PCI certification **cannot** call `reset-pin` or `retrieve-secure-card` directly and should use the guidance page instead: a DCS-hosted page takes the cardholder through setting the PIN or revealing the card credentials, so the sensitive data never touches the partner's systems.

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

The endpoint returns a DCS-hosted guidance link that the partner passes to the cardholder to open in the front end. The full parameters and usage of the guidance page are described in [Get sensitive card data](./secure-card).

***

## Next steps

Issuing and maintaining cards is now covered end to end. Next you can:

* Configure spending limits, see [Card limits (velocity limits)](./velocity-limits);
* Handle the real-time authorization raised when a cardholder pays, see [Authorization forwarding](../transactions/authorization).
