Base URL depends on which indexer instance you are querying. The DID indexer and VC indexer run as separate services with different INDEXER_CONFIG values, but they share the same codebase and health endpoint.
All responses are JSON. All timestamps are ISO 8601 strings. The API supports CORS and gzip compression.
Returns the current sync state of the indexer. Use this to check if the service is running and how far behind the chain tip it is.
Response
{
"status": "ok",
"indexer": "prisma-did-indexer",
"network": "preprod",
"confirmationDepth": 10,
"sync": [
{
"label": 199674,
"lastBlockHeight": 1234567,
"lastBlockHash": "abc123..."
}
]
}| Field | Type | Description |
|---|---|---|
status |
string | Always "ok" if the server is responding |
indexer |
string | Name of the indexer configuration |
network |
string | Cardano network (preprod or mainnet) |
confirmationDepth |
number | How many blocks deep a transaction must be before it is considered confirmed |
sync |
array | One entry per metadata label the indexer is tracking. lastBlockHeight tells you the most recent block the indexer has processed |
These endpoints are available on the DID indexer (INDEXER_CONFIG=did).
Resolves a DID to its current document and metadata. By default, the indexer uses the latest valid confirmed event for this DID, fetches the DID Document from IPFS, and returns both.
URL params
| Param | Type | Description |
|---|---|---|
did |
string | The full DID string, e.g. did:cardano:stake_test1uq... |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
includeUnconfirmed |
string | "false" |
Set to "true" to include events that have not yet reached confirmation depth. Useful for showing freshly created DIDs before they are fully confirmed |
Responses
| Status | When |
|---|---|
| 200 | DID found and active |
| 400 | Invalid DID format |
| 404 | No events found for this DID |
| 410 | DID has been revoked |
200 Response
{
"did": "did:cardano:stake_test1uq...",
"document": {
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:cardano:stake_test1uq...",
"verificationMethod": [...],
"authentication": [...],
"service": [...]
},
"metadata": {
"created": "2025-01-15T10:30:00.000Z",
"updated": "2025-02-01T14:00:00.000Z",
"version": 2,
"deactivated": false
}
}| Field | Type | Description |
|---|---|---|
did |
string | The resolved DID |
document |
object or null | The W3C DID Document fetched from IPFS. Null if the IPFS fetch failed |
metadata.created |
string or null | Timestamp of the first create event |
metadata.updated |
string | Timestamp of the most recent event |
metadata.version |
number | Current version number (starts at 1, increments on each update) |
metadata.deactivated |
boolean | Always false for active DIDs (revoked DIDs return 410 instead) |
Caching: Responses are cached for 60 seconds. An ETag header is included based on the DID and version number.
Returns the full event history for a DID with pagination. Each event represents an on-chain action (create, update, or revoke).
URL params
| Param | Type | Description |
|---|---|---|
did |
string | The full DID string |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
limit |
number | 50 |
Results per page, between 1 and 100 |
offset |
number | 0 |
Number of results to skip |
order |
string | "desc" |
Sort order by version. "desc" shows newest first, "asc" shows oldest first |
includeUnconfirmed |
string | "false" |
Set to "true" to include unconfirmed events |
Responses
| Status | When |
|---|---|
| 200 | DID found, returning events |
| 400 | Invalid DID format |
| 404 | No events found for this DID |
200 Response
{
"did": "did:cardano:stake_test1uq...",
"events": [
{
"txHash": "abc123...",
"action": "create",
"version": 1,
"prevTxHash": null,
"ipfsCid": "QmXyz...",
"blockHeight": 1234000,
"timestamp": "2025-01-15T10:30:00.000Z",
"valid": true,
"confirmed": true
}
],
"total": 3,
"limit": 50,
"offset": 0
}| Field | Type | Description |
|---|---|---|
events[].txHash |
string | Cardano transaction hash |
events[].action |
string | One of create, update, or revoke |
events[].version |
number | Version number at the time of this event |
events[].prevTxHash |
string or null | Transaction hash of the previous event in the chain. Null for create events |
events[].ipfsCid |
string or null | IPFS CID pointing to the DID Document for this version |
events[].blockHeight |
number | Block number where this transaction was included |
events[].timestamp |
string | Block timestamp |
events[].valid |
boolean | Whether the event passed structural and signature validation |
events[].confirmed |
boolean | Whether the event has reached the required confirmation depth |
total |
number | Total number of events matching the query |
limit |
number | Page size used |
offset |
number | Offset used |
W3C Universal Resolver compatible endpoint. Returns the same data as GET /did/:did but wrapped in the standard DID Resolution Result format defined by the W3C DID Resolution spec.
URL params
| Param | Type | Description |
|---|---|---|
did |
string | The full DID string |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
includeUnconfirmed |
string | "false" |
Set to "true" to include unconfirmed events |
200 Response (active DID)
{
"didResolutionMetadata": {
"contentType": "application/did+ld+json"
},
"didDocument": {
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:cardano:stake_test1uq..."
},
"didDocumentMetadata": {
"created": "2025-01-15T10:30:00.000Z",
"updated": "2025-02-01T14:00:00.000Z",
"versionId": "2",
"deactivated": false
}
}200 Response (revoked DID)
{
"didResolutionMetadata": {},
"didDocument": null,
"didDocumentMetadata": {
"deactivated": true
}
}400 Response (invalid DID)
{
"didResolutionMetadata": { "error": "invalidDid" },
"didDocument": null,
"didDocumentMetadata": {}
}404 Response (not found)
{
"didResolutionMetadata": { "error": "notFound" },
"didDocument": null,
"didDocumentMetadata": {}
}These endpoints are available on the VC indexer (INDEXER_CONFIG=vc).
Returns all on-chain anchor events for a credential, ordered by block height. This includes issue, validate, and revoke events. Useful for building a full audit trail.
URL params
| Param | Type | Description |
|---|---|---|
vcHash |
string | The credential's unique identifier (JTI hash) |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
includeUnconfirmed |
string | "false" |
Set to "true" to include unconfirmed events |
Responses
| Status | When |
|---|---|
| 200 | Events found |
| 404 | No events for this vcHash |
200 Response
{
"vcHash": "abc123...",
"events": [
{
"txHash": "def456...",
"event": "issue",
"issuerDid": "did:cardano:stake_test1uq...",
"holderDid": "did:cardano:stake_test1ur...",
"validatorDid": null,
"vcType": "PrismaIdentityCredential",
"vcFormat": "cose-sd",
"ipfsCid": "QmXyz...",
"reason": null,
"confirmed": true,
"blockHeight": 1234000,
"timestamp": "2025-01-15T10:30:00.000Z"
}
]
}| Field | Type | Description |
|---|---|---|
events[].txHash |
string | Cardano transaction hash |
events[].event |
string | One of issue, validate, or revoke |
events[].issuerDid |
string | DID of the credential issuer |
events[].holderDid |
string | DID of the credential holder |
events[].validatorDid |
string or null | DID of the validator (only present for validate events) |
events[].vcType |
string | Credential type identifier (e.g. PrismaIdentityCredential) |
events[].vcFormat |
string | Credential format. One of cose-sd or ed25519 |
events[].ipfsCid |
string or null | IPFS CID where the credential payload is pinned. Only present on issue events |
events[].reason |
string or null | Allowlisted revocation reason on revoke events (issued_in_error, holder_request, policy_violation, expired, compromised, withdrawn_by_holder) |
events[].confirmed |
boolean | Whether this event has reached confirmation depth |
events[].blockHeight |
number | Block number |
events[].timestamp |
string | Block timestamp |
Returns the current status of a credential. The indexer looks at all events for this vcHash and reduces them into a single status using a deterministic algorithm: it finds the first issue event to identify the canonical issuer, then checks if there is an authorized revoke event from that same issuer. Only the original issuer can revoke a credential.
URL params
| Param | Type | Description |
|---|---|---|
vcHash |
string | The credential's unique identifier |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
includeUnconfirmed |
string | "false" |
Set to "true" to see freshly issued credentials that have not been confirmed yet |
Responses
| Status | When |
|---|---|
| 200 | Status computed |
| 404 | No events for this vcHash |
200 Response (active)
{
"vcHash": "abc123...",
"status": "active",
"confirmed": true,
"issuer": "did:cardano:stake_test1uq...",
"holder": "did:cardano:stake_test1ur...",
"vcType": "PrismaIdentityCredential",
"issuedAt": "2025-01-15T10:30:00.000Z",
"issuedTxHash": "def456...",
"issuedTxConfirmed": true
}200 Response (revoked)
{
"vcHash": "abc123...",
"status": "revoked",
"confirmed": true,
"issuer": "did:cardano:stake_test1uq...",
"holder": "did:cardano:stake_test1ur...",
"vcType": "PrismaIdentityCredential",
"issuedAt": "2025-01-15T10:30:00.000Z",
"issuedTxHash": "def456...",
"issuedTxConfirmed": true,
"revokedAt": "2025-02-10T08:00:00.000Z",
"revokedTxHash": "ghi789...",
"reason": "compromised"
}| Field | Type | Description |
|---|---|---|
vcHash |
string | The credential identifier |
status |
string | One of active, revoked, or unknown. For GET /vc/:vcHash/status, unknown means events exist but none are issue events (if no events exist, this endpoint returns 404). In batch status responses, missing vcHashes are returned as unknown |
confirmed |
boolean | True if all relevant events (issue and revoke if applicable) have been confirmed |
issuer |
string | DID of the issuer (from the first issue event) |
holder |
string | DID of the holder |
vcType |
string | Credential type |
issuedAt |
string | When the credential was issued |
issuedTxHash |
string | Transaction hash of the issue event |
issuedTxConfirmed |
boolean | Whether the issue transaction is confirmed |
revokedAt |
string | When the credential was revoked (only if status is revoked) |
revokedTxHash |
string | Transaction hash of the revoke event (only if revoked) |
reason |
string | Allowlisted revocation reason (only if provided): issued_in_error, holder_request, policy_violation, expired, compromised, withdrawn_by_holder |
Caching: Responses are cached for 30 seconds.
Fetches the status of multiple credentials in a single request. This avoids making one HTTP call per credential when loading a list. Each vcHash is reduced independently using the same algorithm as GET /vc/:vcHash/status.
Request body
{
"vcHashes": ["abc123...", "def456...", "ghi789..."],
"includeUnconfirmed": true
}| Field | Type | Required | Description |
|---|---|---|---|
vcHashes |
string[] | Yes | Array of credential identifiers. Maximum 100 per request |
includeUnconfirmed |
boolean | No | Defaults to false. Set to true to include unconfirmed events in the status computation |
Responses
| Status | When |
|---|---|
| 200 | Statuses computed |
| 400 | Missing or invalid vcHashes, or more than 100 items |
200 Response
{
"statuses": {
"abc123...": {
"vcHash": "abc123...",
"status": "active",
"confirmed": true,
"issuer": "did:cardano:stake_test1uq...",
"holder": "did:cardano:stake_test1ur...",
"vcType": "PrismaIdentityCredential",
"issuedAt": "2025-01-15T10:30:00.000Z",
"issuedTxHash": "def456...",
"issuedTxConfirmed": true
},
"def456...": {
"vcHash": "def456...",
"status": "unknown",
"confirmed": true
}
}
}The statuses object is keyed by vcHash. Each value has the same shape as the response from GET /vc/:vcHash/status. In this batch endpoint, credentials with no events on-chain are returned as status: "unknown" (unlike the single status endpoint, which returns 404 when no events are found).
Caching: Responses are cached for 30 seconds.
Returns a paginated list of credentials issued by a specific DID. Only issue events are returned (not revoke or validate events). To check if any of these credentials have been revoked, use the batch status endpoint.
URL params
| Param | Type | Description |
|---|---|---|
did |
string | The issuer's DID |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 |
Results per page, between 1 and 100 |
offset |
number | 0 |
Number of results to skip |
order |
string | "desc" |
Sort by block height. "desc" shows newest first |
includeUnconfirmed |
string | "false" |
Set to "true" to include unconfirmed issue events |
200 Response
{
"issuer": "did:cardano:stake_test1uq...",
"credentials": [
{
"vcHash": "abc123...",
"holderDid": "did:cardano:stake_test1ur...",
"vcType": "PrismaIdentityCredential",
"vcFormat": "cose-sd",
"ipfsCid": "QmXyz...",
"txHash": "def456...",
"confirmed": true,
"blockHeight": 1234000,
"timestamp": "2025-01-15T10:30:00.000Z"
}
],
"pagination": {
"total": 15,
"limit": 20,
"offset": 0
}
}| Field | Type | Description |
|---|---|---|
credentials[].vcHash |
string | Credential identifier |
credentials[].holderDid |
string | DID of the holder this credential was issued to |
credentials[].vcType |
string | Credential type |
credentials[].vcFormat |
string | Credential format |
credentials[].ipfsCid |
string or null | IPFS CID of the credential payload |
credentials[].txHash |
string | Transaction hash of the issue event |
credentials[].confirmed |
boolean | Whether the issue event is confirmed |
credentials[].blockHeight |
number | Block number |
credentials[].timestamp |
string | Block timestamp |
pagination.total |
number | Total credentials matching the query |
pagination.limit |
number | Page size |
pagination.offset |
number | Current offset |
Returns a paginated list of credentials held by a specific DID. Same structure and behavior as the issuer endpoint but filtered by holderDid instead of issuerDid.
URL params
| Param | Type | Description |
|---|---|---|
did |
string | The holder's DID |
Query params
Same as GET /issuer/:did/credentials.
200 Response
{
"holder": "did:cardano:stake_test1ur...",
"credentials": [
{
"vcHash": "abc123...",
"issuerDid": "did:cardano:stake_test1uq...",
"vcType": "PrismaIdentityCredential",
"vcFormat": "cose-sd",
"ipfsCid": "QmXyz...",
"txHash": "def456...",
"confirmed": true,
"blockHeight": 1234000,
"timestamp": "2025-01-15T10:30:00.000Z"
}
],
"pagination": {
"total": 5,
"limit": 20,
"offset": 0
}
}The only difference from the issuer endpoint is that each credential includes issuerDid instead of holderDid, since the holder is already known from the URL.
Returns the list of supported credential types from the schema registry. Each schema defines which fields can be selectively disclosed when creating a presentation.
No params.
200 Response
{
"schemas": [
{
"vct": "ContributionCredential",
"disclosableFields": ["hours", "description", "evidenceUrl"]
}
]
}| Field | Type | Description |
|---|---|---|
schemas[].vct |
string | Verifiable Credential Type identifier. This is the value used in the vcType field when issuing a credential |
schemas[].disclosableFields |
string[] | List of claim keys that support selective disclosure. When creating a presentation, the holder can choose which of these fields to reveal |
The schema that defines what fields a credential contains lives in a single file: packages/schemas/src/credentials/contribution.ts. This is the only place you need to make changes.
To add, remove, or change fields, edit the ContributionCredentialSchema.extend({}) block. Each field uses a Zod validator, for example z.string().min(1) for a required string or z.number().positive().optional() for an optional positive number.
To change the contribution type options, update the ContributionTypeEnum array at the top of the file. These are the allowed values for the contributionType field.
To update which fields support selective disclosure, edit the contributionDisclosableFields array at the bottom. When a holder creates a presentation, they can choose to reveal or hide any field listed here.
No changes are needed for the on-chain transaction (it only stores a credential hash and an IPFS pointer, so it never sees the schema fields), the indexer (it only indexes on-chain event metadata and never inspects the credential body on IPFS), or the schema registry (packages/schemas/src/registry.ts) which already references this file and feeds the /schemas endpoint automatically.
You also need to update the issuance form. The form in apps/vc-interface/components/IssuanceForm.tsx has a hardcoded credentialFields object (around line 35) that does not read from the Zod schema. If you change the schema, you must mirror those changes in the form or it will break.
Example: adding a role field to ContributionCredential
-
In
packages/schemas/src/credentials/contribution.ts, add the field to the Zod schema:role: z.string().min(1), // required text field // or role: z.string().optional(), // optional text field
If it should support selective disclosure, add
'role'to thecontributionDisclosableFieldsarray. -
In
apps/vc-interface/components/IssuanceForm.tsx, add a matching entry to theContributionCredentialarray insidecredentialFields:{ key: 'role', label: 'Role', type: 'text', required: true, canDisclose: false, defaultDisclosed: false },
Each field needs:
key: must match the Zod field name exactlylabel: what the user sees in the formtype:'text'for strings,'number'for numbers,'select'for enumsrequired:trueif the Zod field is not.optional()options: only for'select'type, list the enum values (e.g.['code', 'design', 'other'])canDisclose:trueif the field is incontributionDisclosableFieldsdefaultDisclosed:trueif the disclosure checkbox should be pre-checked
The same pattern applies when removing or renaming fields. Delete or update the entry in both files.
Most error responses include an error message and may include endpoint-specific context fields (for example, did or vcHash):
{
"error": "Human-readable error message",
"did": "did:cardano:stake_test1..."
}The Universal Resolver endpoint (/1.0/identifiers/:did) uses the W3C error format instead, with didResolutionMetadata.error containing the error code.
Check if a DID exists and is active
GET /did/did:cardano:stake_test1uq...
200 means active, 404 means not found, 410 means revoked.
Load a credential list with statuses
GET /holder/did:cardano:stake_test1ur.../credentials?includeUnconfirmed=trueto get the listPOST /vc/status/batchwith all thevcHashvalues from step 1 to get statuses in one call
Check if a freshly issued credential is visible
GET /vc/:vcHash/status?includeUnconfirmed=true
The includeUnconfirmed=true flag ensures the credential appears before it reaches confirmation depth. The confirmed field in the response tells you whether it is confirmed yet.