# Managing Credentials
Source: https://docs.chain.link/ace/guides/identity-manager/manage-credentials
Last Updated: 2026-07-17

> For the complete documentation index, see [llms.txt](/llms.txt).

Credentials are attestations that a [cross-chain identity (CCID)](/ace/concepts/cross-chain-identity) holds a specific qualification — for example, KYC verification, accredited investor status, or sanctions clearance. Each credential links a **credential type** to an **identity** and is recorded on-chain across every chain where the credential registry is deployed.

This guide covers the full credential lifecycle: issuing, viewing, updating, expiring, and revoking credentials through the Coordinator API.

## Attestation vs. typed credentials

ACE supports two kinds of credentials:

- **Attestation-only** (the default) — The credential records only that an identity holds a credential of a given type, with no additional data. When you issue one, the on-chain record contains just the **credential type hash**, the **identity** (CCID) it is issued to, and an **issuance timestamp**. Policies verify existence — for example, "does this address have a valid KYC credential?" — without accessing any personally identifiable information (PII).
- **Typed** — When the credential type is linked to a [data schema](/ace/guides/identity-manager/manage-credential-types#typed-credentials-with-data-schemas), the credential also carries structured `credential_data` (for example, a jurisdiction code). Policies can then evaluate the contents through a [Data Validator](/ace/guides/policy-manager/manage-data-validators), not just the credential's existence.

In both cases, no PII should be stored on-chain — credential data must be a minimal, non-sensitive value (such as an ISO country code) or a hash. For a deeper discussion of credential data and privacy, see [Credential Data and Privacy](/ace/concepts/cross-chain-identity#credential-data-and-privacy).

## Issue a credential

To issue a credential, you need a registered [identity](/ace/guides/identity-manager/manage-identities) and at least one [credential type](/ace/guides/identity-manager/manage-credential-types) defined in your registry.

> **CAUTION**
>
> Each identity can hold only **one credential per credential type**. Attempting to issue a duplicate returns an error.

Issue a credential with a `POST` request:

```bash
curl -X POST "https://ace.api.chain.link/v1/credentials" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "credential_type_id": "<CREDENTIAL_TYPE_ID>",
    "identity_id": "<IDENTITY_ID>",
    "external_unique_id": "kyc-2026-04-acme",
    "expires_at": 1806883200
  }'
```

| Field                | Required | Description                                                  |
| -------------------- | -------- | ------------------------------------------------------------ |
| `credential_type_id` | Yes      | UUID of the credential type to issue                         |
| `identity_id`        | Yes      | UUID of the target identity (CCID)                           |
| `external_unique_id` | No       | Your own reference identifier for this credential            |
| `expires_at`         | No       | Unix timestamp (integer); omit for a non-expiring credential |

## Issue a credential with data

When the credential type is linked to a [data schema](/ace/guides/identity-manager/manage-credential-types#typed-credentials-with-data-schemas), include a `credential_data` field. The value must match the schema — for the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code schema, that is a JSON array of two-letter country codes. ACE validates the data against the schema and encodes it on-chain.

```bash
curl -X POST "https://ace.api.chain.link/v1/credentials" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "credential_type_id": "<CREDENTIAL_TYPE_ID>",
    "identity_id": "<IDENTITY_ID>",
    "credential_data": ["US"],
    "external_unique_id": "jurisdiction-2026-04-acme",
    "expires_at": 1806883200
  }'
```

> **CAUTION: Data is required for typed credential types**
>
> If the credential type is linked to a data schema, `credential_data` is **required** and must satisfy the schema.
> Conversely, do not send `credential_data` for an attestation-only credential type. Keep the value minimal and
> non-sensitive — never store PII on-chain.

Once issued, the credential data can be enforced at transaction time by attaching a [Data Validator](/ace/guides/policy-manager/manage-data-validators) to the credential source of an identity-validation policy.

## Issue credentials during identity creation

You can issue credentials inline when registering a new identity by including a `credentials` array in the `POST /identities` request body. This is useful when you have completed verification before registration and want to create the identity and its credentials in a single call.

```bash
curl -X POST "https://ace.api.chain.link/v1/identities" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Acme Corp Treasury",
    "entity_id": "acme-corp-001",
    "registry_id": "<REGISTRY_ID>",
    "onchain_identities": [
      {
        "chain_selector": "16015286601757825753",
        "address": "0x1234567890abcdef1234567890abcdef12345678"
      }
    ],
    "credentials": [
      {
        "credential_type_id": "<CREDENTIAL_TYPE_ID>",
        "external_unique_id": "kyc-2026-04-acme",
        "expires_at": 1806883200
      },
      {
        "credential_type_id": "<CREDENTIAL_TYPE_ID_2>"
      }
    ]
  }'
```

Each entry in the `credentials` array follows the same schema as the standalone `POST /credentials` endpoint, except that `identity_id` is inferred from the identity being created. See [Managing Identities](/ace/guides/identity-manager/manage-identities) for the full identity creation reference.

## View and filter credentials

List credentials with a `GET` request. All query parameters are optional:

```bash
curl "https://ace.api.chain.link/v1/credentials?credential_type_id=<CREDENTIAL_TYPE_ID>&page=1&page_size=25" \
  -H "Authorization: Apikey <API_KEY>"
```

| Parameter            | Description                                         |
| -------------------- | --------------------------------------------------- |
| `credential_type_id` | Filter by credential type                           |
| `identity_id`        | Filter by identity                                  |
| `entity_id`          | Filter by entity                                    |
| `registry_id`        | Filter by registry                                  |
| `include_onchains`   | Include on-chain deployment details in the response |
| `page`               | Page number (default: 1)                            |
| `page_size`          | Results per page                                    |

To retrieve a single credential by its ID:

```bash
curl "https://ace.api.chain.link/v1/credentials/<CREDENTIAL_ID>" \
  -H "Authorization: Apikey <API_KEY>"
```

## Credential expiration

The `expires_at` field controls whether a credential has a limited validity period.

- **No expiration** — Omit `expires_at` when issuing. The credential remains valid indefinitely until explicitly archived.
- **With expiration** — Provide a Unix timestamp (integer). Once the timestamp passes, policy checks that require this credential type will treat the credential as invalid.

To **renew** an expiring credential, update it with a new `expires_at` value (see the next section). Alternatively, you can archive the expired credential and issue a new one.

> **TIP**
>
> Set `expires_at` to align with your compliance review cycle. For example, if KYC reviews happen annually, set
> expiration to one year from issuance and update upon re-verification.

## Update a credential

You can update a credential's `external_unique_id` and `expires_at` fields. You **cannot** change the credential type or the associated identity — to change either, archive the credential and issue a new one.

Update a credential with a `PUT` request:

```bash
curl -X PUT "https://ace.api.chain.link/v1/credentials/<CREDENTIAL_ID>" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "external_unique_id": "kyc-2026-04-acme-renewed",
    "expires_at": 1838419200
  }'
```

| Field                | Required | Description                                       |
| -------------------- | -------- | ------------------------------------------------- |
| `external_unique_id` | Yes      | Updated reference identifier                      |
| `expires_at`         | No       | New expiration timestamp; omit to leave unchanged |

You can also perform a partial update with `PATCH`. The `PATCH` endpoint accepts `external_unique_id` and `expires_at` independently, but you **cannot** combine field updates with a status change in the same request:

```bash
curl -X PATCH "https://ace.api.chain.link/v1/credentials/<CREDENTIAL_ID>" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "expires_at": 1838419200
  }'
```

## Revoke (archive) a credential

Archiving a credential removes it from the on-chain credential registry. After archival, policy contracts will no longer see this credential — any policy that requires it (such as the [Credential Registry Identity Validator](/ace/reference/policy-library/credential-registry-identity-validator-policy)) will reject transactions from the associated addresses.

Common reasons to revoke a credential:

- KYC verification expired or failed re-verification
- Sanctions status changed
- Accreditation lapsed
- Entity relationship terminated

Archive a credential with a `PATCH` request:

```bash
curl -X PATCH "https://ace.api.chain.link/v1/credentials/<CREDENTIAL_ID>" \
  -H "Authorization: Apikey <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "archived"
  }'
```

> **CAUTION**
>
> Archiving triggers on-chain removal. The credential cannot be un-archived — to restore the attestation, issue a new
> credential of the same type to the same identity.

## Related resources

- [Cross-Chain Identity](/ace/concepts/cross-chain-identity) — CCID model, credential registries, and the attestation lifecycle
- [Managing Identities](/ace/guides/identity-manager/manage-identities) — register and manage CCIDs and their on-chain address mappings
- [Managing Credential Types](/ace/guides/identity-manager/manage-credential-types) — create and organize the credential categories your registry supports
- [Credential Registry Identity Validator Policy](/ace/reference/policy-library/credential-registry-identity-validator-policy) — the policy that checks credentials at transaction time
- [Managing Data Validators](/ace/guides/policy-manager/manage-data-validators) — enforce rules on credential data at transaction time
- [Beta Scope](/ace/beta-scope) — current scope and limitations