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

# Changelog

> Latest updates and changes to the PLU Card API

## August 10, 2026

### Crypto deposits now accept Optimism USDC and USDT

Partner wallets and crypto cards now also credit **Optimism**: native `usdc` and `usdt`. Deposit addresses are
unchanged — the same EVM address receives on every supported chain.

| Network  | Chain ID | `chain` value | Tokens                   |
| -------- | -------- | ------------- | ------------------------ |
| Base     | 8453     | `base`        | `usdc`                   |
| Polygon  | 137      | `polygon`     | `usdc`, `usdt`, `usdc.e` |
| Optimism | 10       | `optimism`    | `usdc`, `usdt`           |

Staging uses `optimism-sepolia` (11155420), which carries `usdc` only — there is no testnet USDT. The pairs
also appear in the `supportedNetworks` array on every deposit-address endpoint, which is the recommended way
to read this rather than hardcoding a chain.

<Warning>
  **Bridged USDC.e on Optimism is not credited.** Optimism has two contracts reporting the symbol `USDC`, and
  only the native one (`0x0b2c639c533813f4aa9d7837caf62653d097ff85`) is supported. A transfer of bridged
  USDC.e (`0x7f5c764cbc14f9669b88837ca1490cca17c31607`) produces no deposit and no webhook, and has to be
  recovered manually.

  This differs from Polygon, where both USDC contracts are credited. Check which contract your wallet or
  exchange sends before using Optimism — some label the bridged token simply "USDC". Full detail in
  [Supported networks](/webhooks#supported-networks).
</Warning>

Withdrawals are unchanged: still no `chain` or `token` parameter, still sent as **USDC on Base only**. An
Optimism USDT deposit is withdrawn as Base USDC.

## July 29, 2026

### Crypto deposits now accept Polygon USDC, USDT and USDC.e

Partner wallets and crypto cards previously only credited **USDC on Base**. They now also credit **Polygon**:
native `usdc`, `usdt`, and bridged `usdc.e`. Deposit addresses are unchanged — the same EVM address receives on
every supported chain.

| Network | Chain ID | `chain` value | Tokens                   |
| ------- | -------- | ------------- | ------------------------ |
| Base    | 8453     | `base`        | `usdc`                   |
| Polygon | 137      | `polygon`     | `usdc`, `usdt`, `usdc.e` |

Staging uses the corresponding testnets, `base-sepolia` (84532) and `polygon-amoy` (80002), which carry `usdc`
only — there is no USDT or bridged USDC on Amoy. Full detail in [Supported networks](/webhooks#supported-networks).

### New response field: `supportedNetworks`

Every endpoint that returns a deposit address now returns the chain/token pairs that address is credited on:

* [Create Card](/api-reference/cards/create-card) and [Get Card](/api-reference/cards/get-card) — on `crypto` cards, alongside `depositAddress`
* [Get Profile](/api-reference/profile/get-profile) — on `wallet`, alongside `walletAddress`

```json theme={null}
"supportedNetworks": [
  { "chain": "base", "chainId": 8453, "tokens": ["usdc"] },
  { "chain": "polygon", "chainId": 137, "tokens": ["usdc", "usdt", "usdc.e"] }
]
```

**Recommended:** read this array instead of hardcoding a chain. The list differs between staging and production
and will grow as chains are added — reading it means new networks need no change on your side.

### `chain` and `token` on deposit webhooks are no longer fixed

[`wallet.deposit.crypto`](/webhooks#crypto-deposit-webhook) and
[`card.deposit.crypto`](/webhooks#card-crypto-deposit-webhook) previously always carried `chain: "base"` and
`token: "usdc"`. Both now vary per deposit.

**Action required** if you branch on either field: stop assuming `base`/`usdc`, and treat an unrecognised pair as
a deposit you should not act on. Polygon has two USDC contracts and both are credited, distinguished only by
`token` — native USDC reports `usdc`, bridged reports `usdc.e`.

### Withdrawals remain Base USDC only

[Create Withdrawal](/api-reference/withdrawals/create-withdrawal) is unchanged: no `chain` or `token` parameter,
and `toAddress` must be a **Base** address. A Polygon USDT deposit is withdrawn as Base USDC.

## May 6, 2026

### Breaking: `reference` is now required on card withdrawals

The [Withdraw from Card](/api-reference/cards/withdraw-card) endpoint now requires a `reference` field in the request body. Calls missing it will receive `400 Bad Request`.

```json theme={null}
{
  "serviceCardId": "acme-card-xyz789jkl012mno",
  "amount": 25,
  "reference": "ref-test-001"
}
```

`reference` is an opaque, partner-supplied string (1–256 chars) — typically your internal user transaction id. We do not interpret or validate the contents beyond length.

**Action required:** add a `reference` to every `POST /partner/card/withdraw` call. Existing integrations will start receiving `400` once this change deploys.

`reference` is also accepted (optional) on `POST /partner/card/fund` and `DELETE /partner/card/terminate/:serviceCardId`.

### New webhook event: `wallet.deposit.card-withdrawal`

When funds from a card withdrawal (or a card liquidation that releases a positive balance) land in your partner wallet, we now deliver a [`wallet.deposit.card-withdrawal`](/webhooks#card-withdrawal-wallet-credit-webhook) event. The payload echoes the `reference` you sent on the originating call so you can correlate the wallet credit with the user transaction that triggered it — and immediately fan funds out to the end-user's destination.

```json theme={null}
{
  "event": "wallet.deposit.card-withdrawal",
  "timestamp": "2026-05-06T14:57:49.432Z",
  "data": {
    "partnerId": "service-partner-PdhFKbfvYr",
    "serviceCardId": "acme-card-xyz789jkl012mno",
    "serviceTransactionId": "acme-user-card-transactions-abc123def456ghi",
    "amount": 25,
    "fee": 0.5,
    "netAmount": 24.5,
    "currency": "USD",
    "reference": "ref-test-001"
  }
}
```

For card liquidations, `data.source` is set to `"liquidation"` so you can distinguish them. See [Webhooks › Card Withdrawal Wallet Credit](/webhooks#card-withdrawal-wallet-credit-webhook).

## April 21, 2026

### Breaking: Webhook event names renamed

Two partner webhook event names have been renamed to remove provider-specific branding. **Update your webhook handlers immediately** — the old event names are no longer emitted.

| Old event                | New event                |
| ------------------------ | ------------------------ |
| `rain.user-event`        | `user.kyc-event`         |
| `rain.transaction-event` | `card.transaction-event` |

**Payloads are unchanged.** The `data` body — including `status`, `type`, and all other fields — is identical. Only the top-level `event` string changed.

**Action required:**

1. Update any `switch` / `if` on the `event` field in your webhook receiver.
2. If you subscribe to specific events via the [Set Webhook Events](/api-reference/profile/set-webhook) endpoint, re-subscribe using the new names.
3. See [Webhooks](/webhooks) for the updated event reference and payload examples.

## April 20, 2026

### Crypto-funded cards now support partial withdrawals

The [Withdraw from Card](/api-reference/cards/withdraw-card) endpoint now accepts crypto-funded cards. Previously these cards returned `400 CRYPTO_CARD_WITHDRAW_BLOCKED` and required full termination to recover any balance.

Behavior is identical to float-card withdrawals: the card's available balance is debited and the amount (minus your withdrawal fee) is credited to your partner wallet. Min `$5`, max `$10,000` per transaction.

The `CRYPTO_CARD_WITHDRAW_BLOCKED` error code is retired and no longer returned by the API.

### New endpoints: USDC withdrawals from your partner wallet

You can now withdraw USDC from your partner wallet to an external Base address. Four new endpoints under [Withdrawals](/api-reference/withdrawals/create-withdrawal):

* `POST /v1/partner/withdrawal` — Submit a withdrawal request (requires `idempotency-key` header)
* `GET /v1/partner/withdrawal` — List your withdrawals with optional `status` filter
* `GET /v1/partner/withdrawal/{id}` — Retrieve a specific withdrawal
* `DELETE /v1/partner/withdrawal/{id}` — Cancel a `pending` withdrawal and refund your wallet

**How it works**

1. You submit a request — the amount is debited from your wallet immediately and the withdrawal enters `pending` status.
2. An admin reviews and approves (or rejects) the request. There is no auto-approval.
3. On approval, USDC is sent on-chain on Base. Your wallet stays debited.
4. On rejection or your own cancellation, the amount is refunded to your wallet.

**Fees and limits**

* Minimum withdrawal: **\$5**
* Flat fee: **\$0.50**, deducted from the on-chain amount. If you request `$100`, your wallet is debited `$100` and `$99.50` is sent on-chain.

**New webhook event**

The [`wallet.withdrawal.crypto`](/webhooks#wallet-events) event fires when a withdrawal reaches a terminal state (`completed`, `cancelled`, or `rejected`). For `completed`, the payload includes `txHash` and `explorerUrl`.

## March 27, 2026

### Delete User now supports pending/denied KYC users + fee waiver on re-creation

The [Delete User](/api-reference/users/delete-user) endpoint now accepts users whose KYC was denied or is still pending — previously these users could not be deleted.

Additionally, if you re-create a previously deleted user whose KYC was **never approved**, the KYC fee is waived. You are only charged again if the original user had been fully approved. See [Delete User — Fee Waiver](/api-reference/users/delete-user#fee-waiver-on-re-creation) for details.

### New endpoint: List User Cards

The [List User Cards](/api-reference/users/list-user-cards) endpoint allows partners to list all cards belonging to a specific user via `GET /v1/partner/card/users/{serviceId}/cards`.

Returns the same card summary data as [List Cards](/api-reference/cards/list-cards), but scoped to a single user. Supports `skip` and `limit` pagination. Returns `404 USER_NOT_FOUND` if the user does not exist under your partner account.

### Get User now returns KYC verification link

The [Get User](/api-reference/users/get-user) endpoint now returns an optional `verificationUrl` field when the user has initiated KYC. This is the link the user can visit to complete identity verification.

This field is only present when the user has an active KYC flow. No action required — this is an additive, backward-compatible change.

### New endpoint: Delete User

The [Delete User](/api-reference/users/delete-user) endpoint allows partners to permanently delete a card user via `DELETE /v1/partner/card/users/{serviceId}`.

All cards belonging to the user must be [terminated](/api-reference/cards/terminate-card) before deletion. If active cards remain, the API returns `409 ACTIVE_CARDS_EXIST` with the list of card IDs that need to be terminated first.

## March 26, 2026

### New required field: `countryCode` on Create User

The [Create User](/api-reference/users/create-user) endpoint now requires a `countryCode` field — an ISO 3166-1 alpha-2 code representing the user's **country of residence** (e.g. `US`, `KE`, `NG`).

This field is passed to the KYC provider and card issuer to correctly identify the user's region. Without it, users whose nationality differs from their country of residence may be incorrectly denied with `WRONG_USER_REGION`.

**Action required:** Update your integration to include `countryCode` in the request body when creating users. Requests without this field will now return a validation error.

```json theme={null}
{
  "firstName": "Jane",
  "lastName": "Doe",
  "email": "jane@example.com",
  "countryCode": "KE",
  ...
}
```
