> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.adid.dev/llms.txt.
> For full documentation content, see https://docs.adid.dev/llms-full.txt.

# Revocation Management

Revocation flips the credential's bit in a [Status List 2021](https://www.w3.org/TR/vc-status-list/) bitstring stored in the **RevocationRegistry** contract. Verifiers checking the credential read the bit at `(statusListId, statusListIndex)` and reject revoked credentials.

#### 4.4.1. Single Revocation ##### When to use

You discovered a single credential should no longer be trusted (e.g. fraud detected, employee termination).

##### Before you begin

* Issuer role.
* The credential ID.
* A reason (free text — stored for audit).

##### Steps

1. Navigate to `/issuer/credentials` and find the credential. Or open `/issuer/revocation` and search by ID.
2. Click **Revoke**.
   3\. Enter a **Reason** — e.g. "employment terminated 2026-04-26".
3. Confirm. The portal calls `POST /api/v1/credentials/revoke` (`vc.go:218`).

##### API & SDK

<table>
  <tr>
    <th>cURL</th>

    <th>TypeScript SDK</th>
  </tr>

  <tr>
    <td>
      ```bash
      curl -X POST https://adid.dev/api/v1/credentials/revoke \
        -H "Authorization: Bearer $ACCESS_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "credentialId":"urn:uuid:c5b7e3...",
          "reason":"employment terminated 2026-04-26"
        }'
      ```
    </td>

    <td>
      ```ts
      await client.revokeCredential(
        'urn:uuid:c5b7e3...',
        'employment terminated 2026-04-26',
      );
      ```
    </td>
  </tr>
</table>

The handler:

1. Verifies caller owns the issuer DID.
2. Updates `credentials.status = 'revoked'` and inserts a `revocations` row.
3. Computes the `(statusListId, statusListIndex)` for this credential.
4. Calls `setStatus(statusListId, index, 1)` on the RevocationRegistry.

##### Verify

```bash
curl https://adid.dev/api/v1/credentials/urn:uuid:c5b7e3.../status
```

returns `{ "revoked": true, ... }`.

##### Troubleshooting

| Code                           | Cause                                    | Fix                              |
| ------------------------------ | ---------------------------------------- | -------------------------------- |
| `403 NOT_ISSUER_OF_CREDENTIAL` | The credential's issuer DID is not yours | Only the issuer can revoke.      |
| `409 ALREADY_REVOKED`          | Bit already set                          | No action needed.                |
| `503 CHAIN_UNREACHABLE`        | RPC down                                 | Retry; revocation is idempotent. |

#### 4.4.2. Batch Revocation ##### When to use

You discovered a class of bad credentials (a compromised signing key, a schema misconfig). Batch revocation revokes many credentials in one transaction.

##### Steps

1. Navigate to `/issuer/revocation`.
2. Filter the credentials list (by schema, by date range, by tier, etc.).
3. Multi-select rows (or **Select all in filter**).
4. Click **Bulk revoke**.
   5\. Confirm with a **reason** (applied to all rows).
5. The portal calls `POST /api/v1/credentials/batch-revoke` (`vc.go:283`).

##### API

```bash
curl -X POST https://adid.dev/api/v1/credentials/batch-revoke \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "credentialIds":["urn:uuid:a","urn:uuid:b","urn:uuid:c"],
    "reason":"schema v1.0 deprecated"
  }'
```

The handler computes the affected indices, packs them into a single `setStatuses(...)` chain call (gas-amortised), and updates the DB rows in one transaction.

##### Verify

`GET /api/v1/credentials/<id>/status` for any of the revoked IDs returns `revoked: true`.

##### Troubleshooting

| Code                        | Cause                                 | Fix                            |
| --------------------------- | ------------------------------------- | ------------------------------ |
| `400 BATCH_TOO_LARGE`       | More than 1,000 IDs in one batch      | Split into smaller batches.    |
| `403 ONE_OR_MORE_NOT_OWNED` | Some credential's issuer is not yours | Filter to your own issuer DID. |

#### 4.4.3. Status List 2021 Bitstring Mechanics ##### Overview

Status List 2021 is a compact, privacy-preserving way to publish revocation status for many credentials. Each credential references one **status list** plus an **index**. The list is a bitstring (e.g., 131,072 bits = 16 KB) where each bit = one credential. Verifiers read the bit; `1` = revoked, `0` = active.

```
Status list bitstring (per issuer)
[ 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 ... ]
  ^ idx 0   ^ idx 4 (revoked)
                 ^ idx 8,9 (revoked)
```

##### Why bitstrings?

* **Privacy**: a verifier cannot tell *which* credentials they are checking from looking at the list — they only know the bit.
* **Efficiency**: one HTTP fetch (or one chain read) covers tens of thousands of credentials.
* **Auditability**: the list itself is signed by the issuer (standard W3C VC).

##### IDA's implementation

* The bitstring lives **on chain** in the RevocationRegistry contract — see [§11.4](#revocation-registry).
* The platform maintains one `statusListId` **per issuer DID** (current implementation; tunable). - New credentials get `statusListIndex = next_unused_index_for_this_issuer`.
* Revocation = `setStatus(statusListId, index, 1)`.
* The verifier reads the bit on demand at verification time.

##### Visualising your bitstring

```
GET /api/v1/credentials/status-lists/<id>
```

returns the encoded bitstring along with metadata. Tools in the platform let you visualise it as a heatmap on `/issuer/revocation/visualise`.