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

# cardholder.kyc.updated

> Fired when a cardholder's KYC status changes

## Event: `cardholder.kyc.updated`

Sent when a cardholder's KYC verification status changes (e.g. approved or rejected).

KYC approval is asynchronous: `POST /partner/cardholders/{id}/kyc` returns `"status": "pending"`, and this event fires once verification completes. When the outcome is approval, a [`cardholder.approved`](/partner/webhooks/cardholder-approved) event is emitted alongside this one. Sandbox replays the same pending-then-approved sequence after a short delay (payloads include `"sandbox": true`).

## Payload

```json theme={null}
{
  "cardholderId": "ch_abc123",
  "cardProgramId": "prog_def456",
  "kycStatus": "approved"
}
```

| Field | Type | Description |
| - | - | - |
| `cardholderId` | string | Cardholder whose KYC status changed |
| `cardProgramId` | string | Card program the KYC was initiated for |
| `kycStatus` | string | New KYC status. One of `approved`, `rejected`, `pending` |

## Response

Your endpoint must return a **2xx** status code within **30 seconds** to acknowledge receipt. Any non-2xx response or timeout triggers the [retry policy](/partner/webhooks#retry-policy).

| Status code | Meaning |
| - | - |
| `200` | Event received and processed |
| `202` | Event received, will process asynchronously |
| Any non-2xx | Delivery failed — will retry |

## Example handler

```javascript theme={null}
app.post("/webhooks/contro", (req, res) => {
  const eventType = req.headers["x-contro-event"];

  if (eventType === "cardholder.kyc.updated") {
    const { cardholderId, kycStatus } = req.body;

    if (kycStatus === "approved") {
      // Cardholder is verified — you can now issue cards
    } else if (kycStatus === "rejected") {
      // Notify your user to retry or contact support
    }
  }

  res.status(200).send("OK");
});
```
