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

# Revoking a Credential

> Invalidate a credential immediately and propagate the change to all verifiers via Status List 2021.

## Overview

Revocation flips a single bit in your organisation's Status List 2021 bitstring. Verifiers — including the Beltic verify endpoint and any offline verifier — see the revocation on their next bitstring fetch. There's no per-credential round-trip; revocation propagation is bounded by the bitstring's cache TTL.

## Prerequisites

* A Beltic API key with `credentials:revoke` permission
* The `credential_id` of the credential you want to revoke

## Step 1: Send the Revoke Request

```bash theme={null}
curl -X POST https://api.beltic.com/v1/credentials/$CREDENTIAL_ID/revoke \
  -H "X-Api-Key: $BELTIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason": "key_rotation"}'
```

The `reason` field is optional but recommended. Use it for audit context — common values are `key_rotation`, `compromised`, `policy_change`, `user_request`, `error`.

## Step 2: Inspect the Response

```json theme={null}
{
  "id": "cred_01HQ7P4M6...",
  "credential_id": "cred_01HQ7P4M6...",
  "credential_type": "business",
  "status": "revoked",
  "revoked_at": "2026-05-21T15:00:00Z",
  "revocation_reason": "key_rotation",
  "status_list_index": 4287,
  "issued_at": "2026-05-21T10:30:00Z",
  "expires_at": "2026-08-19T10:30:00Z",
  "updated_at": "2026-05-21T15:00:00Z"
}
```

The credential's `status` is now `revoked`, and the bit at `status_list_index` in your org's bitstring has been flipped. The signed JWT itself is still cryptographically valid — revocation is a separate signal that lives outside the signature.

## How Verifiers See the Change

Revocation propagates through the status list, not through the credential itself:

<Steps>
  <Step title="Beltic flips the bit">
    `POST /revoke` writes the updated bitstring to S3 at the public status-list URL (`/.well-known/status-lists/v1`).
  </Step>

  <Step title="Verifiers fetch the bitstring">
    Every verify call fetches (or uses a cached copy of) the org's status list. Cache-Control on the response is 60 seconds by default.
  </Step>

  <Step title="The bit is checked at the credential's slot">
    During step 6 of the verify pipeline, the verifier reads bit `status_list_index` from the bitstring. If it's set, the credential is treated as revoked.
  </Step>
</Steps>

**Worst-case propagation delay:** 60 seconds (the cache TTL). After that, every verifier sees the revocation.

## Revocation Is Permanent

Revoked credentials cannot be un-revoked. The bit stays flipped for the lifetime of the credential, and the slot is not reused — Status List 2021's protocol guarantees that a bit, once set, stays set.

If you need to issue a fresh credential for the same subject, call `POST /v1/credentials` again with the same subject and claims. The new credential gets its own credential ID and its own status-list slot.

## Suspension vs Revocation

Status List 2021 supports two distinct lifecycle states beyond `active` and `expired`:

| Status      | Bit state                       | Semantics                               |
| ----------- | ------------------------------- | --------------------------------------- |
| `active`    | Unset                           | Credential is valid                     |
| `suspended` | Set (and reversible internally) | Temporarily invalid; can be reactivated |
| `revoked`   | Set                             | Permanently invalid                     |
| `expired`   | n/a                             | Past its `exp` claim                    |

V1 of the Beltic API exposes only `revoked` via the public revoke endpoint. Suspension is reserved for internal administrative use (e.g. a fraud hold) and surfaces on verify as `reason: "revoked"` with `status: "suspended"` in the response so callers can distinguish.

## Auditing Revocations

Every revoke call writes an immutable audit event with the `credential.revoked` action. Query it via:

```bash theme={null}
curl "https://api.beltic.com/v1/audit/events?action=credential.revoked" \
  -H "X-Api-Key: $BELTIC_API_KEY"
```

Each audit event captures the credential ID, the actor (API key ID), the revocation reason, and a hash-chained `prev_hash` + `row_hash` pair for tamper detection. See the audit-events endpoint reference for the full shape.

## Error Codes

| HTTP | Code        | Cause                                            |
| ---- | ----------- | ------------------------------------------------ |
| 404  | `not_found` | Credential ID doesn't exist in your org          |
| 409  | `conflict`  | Credential is already revoked or already expired |
| 403  | `forbidden` | API key lacks `credentials:revoke`               |

## Next Steps

<CardGroup cols={2}>
  <Card title="Issue a Replacement" icon="plus" href="/guides/credentials/issuing-a-credential">
    Mint a new credential for the same subject.
  </Card>

  <Card title="Verify a Credential" icon="shield-check" href="/guides/credentials/verifying-a-credential">
    Confirm a credential is or isn't revoked.
  </Card>
</CardGroup>
