Skip to main content
Credential issuance is the process of an issuer creating and delivering a verifiable credential to a holder. CREDEBL supports several issuance flows:
  • Connection-based offer — issue a credential directly to a holder over an established DIDComm connection.
  • Out-of-band (OOB) offer — generate a credential offer that can be accepted without a prior connection, delivered as a URL or QR code.
  • OOB via email — send OOB credential offers to one or more holders by email.
  • Bulk CSV issuance — upload a CSV file to issue credentials to many holders simultaneously.
Both AnonCreds (Indy) and W3C JSON-LD credential types are supported. Specify the type using the credentialType query parameter (INDY or JSONLD).

Base path

All endpoints are rooted at /orgs/:orgId/credentials.

Authentication

Every endpoint requires a JWT bearer token.
Authorization: Bearer <your-jwt-token>

Role-based access

OperationRequired roles
Issue credentials, OOB offersowner, admin, issuer
Read issued credentialsowner, admin, issuer, verifier, member, holder
Delete issuance recordsowner
Bulk upload templatesowner, admin, issuer, verifier

Endpoints

Issue credential (connection)

POST /orgs/:orgId/credentials/offer — Issue to a connected holder.

Issue credential (OOB)

POST /orgs/:orgId/credentials/oob/offer — Create an OOB credential offer.

Issue via email (OOB)

POST /orgs/:orgId/credentials/oob/email — Send OOB offers via email.

List credentials

GET /orgs/:orgId/credentials — Retrieve all issued credential records.

Get credential

GET /orgs/:orgId/credentials/:credentialRecordId — Get a specific credential record.

Bulk templates

GET /orgs/:orgId/credentials/bulk/template — List or download a CSV template for bulk issuance.

Upload CSV

POST /orgs/:orgId/bulk/upload — Upload a filled CSV file for bulk issuance.

Execute bulk issuance

POST /orgs/:orgId/:requestId/bulk — Trigger bulk credential issuance for an uploaded file.

Delete issuance records

DELETE /orgs/:orgId/issuance-records — Delete all issuance records for an organization.

Issue credential (connection-based)

POST /orgs/:orgId/credentials/offer Issue one or more verifiable credentials to holders over established DIDComm connections. Required roles: owner, admin, issuer

Path parameters

orgId
string
required
UUID of the issuing organization.

Query parameters

credentialType
string
required
Credential format. Enum: INDY (default) or JSONLD.
isValidateSchema
boolean
Validate credential attributes against the schema before issuing. Defaults to true.

Request body

credentialDefinitionId
string
The ledger credential definition ID. Required when credentialType is INDY. Example: "WgWxqztrNooG92RXvxSTWv:3:CL:123:default".
comment
string
Optional human-readable comment attached to the credential offer.
protocolVersion
string
DIDComm protocol version. Example: "v1" or "v2".
autoAcceptCredential
string
Auto-acceptance mode. Enum: always, contentApproved, never.
goalCode
string
A goal code for the credential offer thread.
parentThreadId
string
Parent thread ID to attach this offer to an existing thread.
willConfirm
boolean
Whether the issuer confirms receipt of the presentation.
label
string
Label for the credential offer message.
imageUrl
string
Image URL to include with the credential offer.
reuseConnection
boolean
Reuse an existing connection if available. Defaults to true.
isShortenUrl
boolean
Shorten the OOB URL in the response.
credentialData
object[]
required
Array of credential offers. Each element targets a specific connection.

Examples

curl --request POST \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials/offer?credentialType=INDY" \
  --header "Authorization: Bearer <your-jwt-token>" \
  --header "Content-Type: application/json" \
  --data '{
    "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
    "comment": "Welcome to Acme Corp",
    "autoAcceptCredential": "always",
    "credentialData": [
      {
        "connectionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "attributes": [
          { "name": "firstName", "value": "Alice" },
          { "name": "lastName", "value": "Smith" },
          { "name": "employeeId", "value": "EMP-1042" },
          { "name": "department", "value": "Engineering" },
          { "name": "startDate", "value": "2024-01-15" }
        ]
      }
    ]
  }'
201 response
{
  "statusCode": 201,
  "message": "Credential offer sent successfully",
  "data": [
    {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "state": "offer-sent",
      "connectionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
      "schemaId": "WgWxqztrNooG92RXvxSTWv:2:EmployeeCredential:1.0",
      "threadId": "b0f49aa6-1516-4b21-9190-b13e92c0c865",
      "protocolVersion": "v1",
      "createdAt": "2024-01-15T11:00:00.000Z"
    }
  ]
}
StatusDescription
400 Bad RequestMissing credentialDefinitionId for INDY type, or missing credential/options for JSONLD.
401 UnauthorizedMissing or invalid bearer token.
403 ForbiddenUser lacks the required role.
404 Not FoundInvalid credentialType value.

Create out-of-band credential offer

POST /orgs/:orgId/credentials/oob/offer Create an out-of-band credential offer that can be accepted by a holder without a pre-existing connection. The response contains an invitation URL. Required roles: owner, admin, issuer

Path parameters

orgId
string
required
UUID of the issuing organization.

Query parameters

credentialType
string
required
Credential format. Enum: INDY (default) or JSONLD.
isValidateSchema
boolean
Validate attributes against the schema. Defaults to true.

Request body

credentialDefinitionId
string
Ledger credential definition ID. Required for INDY type.
comment
string
Optional comment attached to the credential offer.
protocolVersion
string
DIDComm protocol version.
autoAcceptCredential
string
Auto-acceptance mode. Enum: always, contentApproved, never.
isShortenUrl
boolean
Whether to return a shortened invitation URL.
reuseConnection
boolean
Attempt to reuse an existing connection.
attributes
object[]
Credential attribute name/value pairs. Required for INDY type.
credential
object
W3C Verifiable Credential object. Required for JSONLD type.
options
object
Linked Data proof options. Required for JSONLD type.

Examples

curl --request POST \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials/oob/offer?credentialType=INDY" \
  --header "Authorization: Bearer <your-jwt-token>" \
  --header "Content-Type: application/json" \
  --data '{
    "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
    "comment": "Your employee credential from Acme Corp",
    "autoAcceptCredential": "always",
    "attributes": [
      { "name": "firstName", "value": "Alice" },
      { "name": "lastName", "value": "Smith" },
      { "name": "employeeId", "value": "EMP-1042" },
      { "name": "department", "value": "Engineering" },
      { "name": "startDate", "value": "2024-01-15" }
    ]
  }'
201 response
{
  "statusCode": 201,
  "message": "Credential offer created successfully",
  "data": {
    "invitationUrl": "http://agent.example.com?oob=eyJAdHlwZSI6...",
    "credentialOffer": {
      "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "state": "offer-sent",
      "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
      "createdAt": "2024-01-15T11:00:00.000Z"
    }
  }
}

Issue credential via email

POST /orgs/:orgId/credentials/oob/email Create OOB credential offers and deliver them to holders by email. Each element in credentialOffer targets a specific email address. Required roles: owner, admin, issuer

Path parameters

orgId
string
required
UUID of the issuing organization.

Query parameters

credentialType
string
required
Credential format. Enum: INDY (default) or JSONLD.
isValidateSchema
boolean
Validate attributes against the schema. Defaults to true.

Request body

credentialDefinitionId
string
Ledger credential definition ID. Required for INDY type.
comment
string
Optional comment for all offers in this batch.
protocolVersion
string
DIDComm protocol version.
isReuseConnection
boolean
Attempt to reuse an existing connection with each recipient.
credentialOffer
object[]
required
Array of per-recipient credential offers. The maximum number of entries is controlled by the OOB_BATCH_SIZE environment variable.

Examples

curl --request POST \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials/oob/email?credentialType=INDY" \
  --header "Authorization: Bearer <your-jwt-token>" \
  --header "Content-Type: application/json" \
  --data '{
    "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
    "comment": "Your Acme Corp employee credential is ready",
    "credentialOffer": [
      {
        "emailId": "alice@example.com",
        "attributes": [
          { "name": "firstName", "value": "Alice" },
          { "name": "lastName", "value": "Smith" },
          { "name": "employeeId", "value": "EMP-1042" },
          { "name": "department", "value": "Engineering" },
          { "name": "startDate", "value": "2024-01-15" }
        ]
      },
      {
        "emailId": "bob@example.com",
        "attributes": [
          { "name": "firstName", "value": "Bob" },
          { "name": "lastName", "value": "Jones" },
          { "name": "employeeId", "value": "EMP-1043" },
          { "name": "department", "value": "Finance" },
          { "name": "startDate", "value": "2024-02-01" }
        ]
      }
    ]
  }'
201 response
{
  "statusCode": 201,
  "message": "OOB credential offer created successfully",
  "data": [
    {
      "emailId": "alice@example.com",
      "invitationUrl": "http://agent.example.com?oob=eyJAdHlwZSI6...",
      "credentialOfferId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
    },
    {
      "emailId": "bob@example.com",
      "invitationUrl": "http://agent.example.com?oob=eyJAdHlwZSI6...",
      "credentialOfferId": "a1b2c3d4-1234-5678-90ab-cdef12345678"
    }
  ]
}

List issued credentials

GET /orgs/:orgId/credentials Retrieve all issued credential records for an organization. Supports pagination, search, and sorting. Required roles: owner, admin, issuer, verifier, member, holder

Path parameters

orgId
string
required
UUID of the organization.

Query parameters

pageNumber
number
Page to retrieve. Min 1. Defaults to 1.
pageSize
number
Records per page. Min 1, max 100. Defaults to 10.
Free-text search across credential records.
sortField
string
Field to sort by. Enum: createDateTime (default).
sortBy
string
Sort direction. ASC or DESC (default).

Examples

curl --request GET \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials?pageNumber=1&pageSize=10&sortBy=DESC" \
  --header "Authorization: Bearer <your-jwt-token>"
200 response
{
  "statusCode": 200,
  "message": "Credentials fetched successfully",
  "data": {
    "totalItems": 3,
    "hasNextPage": false,
    "data": [
      {
        "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
        "state": "done",
        "connectionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
        "schemaId": "WgWxqztrNooG92RXvxSTWv:2:EmployeeCredential:1.0",
        "threadId": "b0f49aa6-1516-4b21-9190-b13e92c0c865",
        "protocolVersion": "v1",
        "createdAt": "2024-01-15T11:00:00.000Z",
        "updatedAt": "2024-01-15T11:00:30.000Z"
      }
    ]
  }
}

Get credential by record ID

GET /orgs/:orgId/credentials/:credentialRecordId Retrieve the details of a single credential issuance record. Required roles: owner, admin, issuer, verifier, member, holder

Path parameters

orgId
string
required
UUID of the organization.
credentialRecordId
string
required
UUID of the credential record to retrieve.

Examples

curl --request GET \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials/f47ac10b-58cc-4372-a567-0e02b2c3d479" \
  --header "Authorization: Bearer <your-jwt-token>"
200 response
{
  "statusCode": 200,
  "message": "Credential fetched successfully",
  "data": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "state": "done",
    "connectionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "credentialDefinitionId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
    "schemaId": "WgWxqztrNooG92RXvxSTWv:2:EmployeeCredential:1.0",
    "credentialAttributes": [
      { "name": "firstName", "value": "Alice" },
      { "name": "lastName", "value": "Smith" },
      { "name": "employeeId", "value": "EMP-1042" }
    ],
    "autoAcceptCredential": "always",
    "threadId": "b0f49aa6-1516-4b21-9190-b13e92c0c865",
    "protocolVersion": "v1",
    "outOfBandId": null,
    "createdAt": "2024-01-15T11:00:00.000Z",
    "updatedAt": "2024-01-15T11:00:30.000Z"
  }
}
StatusDescription
400 Bad RequestcredentialRecordId is not a valid UUID.
404 Not FoundNo credential record found with that ID.

Bulk issuance

CREDEBL supports issuing credentials to large numbers of holders by uploading a filled CSV file. The bulk issuance flow has three steps:
1

Download a CSV template

Use GET /orgs/:orgId/credentials/bulk/template to list available templates, or POST /orgs/:orgId/credentials/bulk/template to download a CSV template file pre-filled with the correct column headers for a specific credential definition.
2

Upload the filled CSV

Fill in the CSV with one row per holder and upload it via POST /orgs/:orgId/bulk/upload. The server returns a requestId.
3

Trigger issuance

Call POST /orgs/:orgId/:requestId/bulk to start the issuance process for all rows in the uploaded file.

Download CSV template

POST /orgs/:orgId/credentials/bulk/template Download a CSV template with column headers derived from a credential definition’s schema. Required roles: owner, admin, issuer, verifier

Request body

templateId
string
required
The ledger credential definition ID to use as a template. Example: "WgWxqztrNooG92RXvxSTWv:3:CL:123:default".
schemaType
string
required
Schema type. Enum: INDY or W3C.

Examples

curl --request POST \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/credentials/bulk/template" \
  --header "Authorization: Bearer <your-jwt-token>" \
  --header "Content-Type: application/json" \
  --output template.csv \
  --data '{
    "templateId": "WgWxqztrNooG92RXvxSTWv:3:CL:123:default",
    "schemaType": "INDY"
  }'

Upload CSV for bulk issuance

POST /orgs/:orgId/bulk/upload Upload a filled CSV file for bulk issuance. The file is uploaded as multipart/form-data. Required roles: owner, admin, issuer, verifier

Path parameters

orgId
string
required
UUID of the organization.

Query parameters

schemaType
string
required
Schema type of the CSV data. Enum: INDY or W3C.
templateId
string
required
The credential definition ID used as the template.
isValidateSchema
boolean
Validate rows against the schema on upload. Defaults to true.

Request body

Upload a file field as multipart/form-data containing the CSV binary. Optionally include a fileName field.

Examples

curl --request POST \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/bulk/upload?schemaType=INDY&templateId=WgWxqztrNooG92RXvxSTWv:3:CL:123:default" \
  --header "Authorization: Bearer <your-jwt-token>" \
  --form "file=@employees.csv" \
  --form "fileName=employees.csv"
201 response
{
  "statusCode": 201,
  "message": "CSV imported successfully",
  "data": {
    "requestId": "c2e43f80-9f3a-4b12-835d-ecb9e4f12abc",
    "fileName": "employees.csv",
    "totalRecords": 50,
    "status": "PROCESS_STARTED"
  }
}

Execute bulk issuance

POST /orgs/:orgId/:requestId/bulk Start the bulk credential issuance process for a previously uploaded CSV file. Required roles: owner, admin, issuer, verifier

Path parameters

orgId
string
required
UUID of the organization.
requestId
string
required
The requestId returned when the CSV was uploaded.

Query parameters

isValidateSchema
boolean
Validate rows against the schema before issuing. Defaults to true.
credDefId
string
Override the credential definition ID for this issuance run.

Request body

clientId
string
Client identifier for tracking the bulk job.
fileName
string
Name of the CSV file being processed.
isSelectiveIssuance
boolean
When true, allows selective issuance for specific rows.
organizationLogoUrl
string
URL of the organization’s logo to include in credential emails.
platformName
string
Platform name to include in credential emails.

Delete issuance records

DELETE /orgs/:orgId/issuance-records Delete all issuance records for an organization. This action is irreversible. Required roles: owner

Path parameters

orgId
string
required
UUID of the organization.

Examples

curl --request DELETE \
  --url "http://localhost:5000/v1/orgs/3fa85f64-5717-4562-b3fc-2c963f66afa6/issuance-records" \
  --header "Authorization: Bearer <your-jwt-token>"
200 response
{
  "statusCode": 200,
  "message": "Issuance records deleted successfully"
}
StatusDescription
400 Bad RequestorgId is not a valid UUID.
401 UnauthorizedMissing or invalid bearer token.
403 ForbiddenUser does not have the owner role.

Build docs developers (and LLMs) love