Credentials API
Credential formats
Section titled “Credential formats”BaseID Cloud supports two W3C-standard credential formats. Choosing the right format depends on your privacy requirements and ecosystem.
JWT-VC — Full disclosure
Section titled “JWT-VC — Full disclosure”Format value: jwt_vc_json
A W3C Verifiable Credential signed as a JSON Web Token (JWT). The entire credential — all claims, types, issuer, and subject — is encoded in the JWT payload and visible to any party that receives it.
Structure:
Header.Payload.SignatureThe JWT payload contains:
{ "iss": "did:key:z6MkIssuer...", "sub": "did:key:z6MkHolder...", "iat": 1711459200, "vc": { "@context": ["https://www.w3.org/ns/credentials/v2"], "type": ["VerifiableCredential", "CanadianDigitalID"], "credentialSubject": { "id": "did:key:z6MkHolder...", "givenName": "Alice", "familyName": "Martin", "dateOfBirth": "1990-05-15" } }}When to use:
- Organizational credentials (membership, employment, certificates)
- Credentials where the verifier always needs all fields
- Simple integrations that just need a signed JWT
- Maximum interoperability — JWT-VC is the most widely supported format
Limitations:
- No selective disclosure — the holder cannot hide individual claims
- All claims are visible to every verifier that receives the credential
- Not ideal for privacy-sensitive data (e.g., revealing date of birth when only age verification is needed)
SD-JWT VC — Selective disclosure
Section titled “SD-JWT VC — Selective disclosure”Format value: vc+sd-jwt
A Selective Disclosure JWT Verifiable Credential. The issuer signs all claims, but each claim is individually disclosable — the holder chooses which claims to reveal to each verifier.
Structure:
IssuerJWT~Disclosure1~Disclosure2~...~The compact serialization contains the issuer-signed JWT followed by
~-separated disclosure values. Each disclosure is a Base64-encoded
JSON array [salt, claim_name, claim_value].
How selective disclosure works:
- Issuance: The issuer signs all claims. Each claim gets a unique salt
and is hashed into the JWT’s
_sdarray. - Presentation: The holder creates a presentation including only the disclosures for claims they want to reveal. Unrevealed claims remain as opaque hashes — the verifier can see they exist but not their values.
- Verification: The verifier checks the issuer’s signature on the JWT,
then verifies each disclosed claim matches its hash in
_sd.
Example — age verification without revealing date of birth:
The credential contains givenName, familyName, dateOfBirth, and
age_over_18. The holder presents only age_over_18: true — the verifier
confirms the issuer attested to this fact without learning the actual
date of birth.
Always-visible claims (plain claims):
| Claim | Description |
|---|---|
iss | Issuer DID |
sub | Subject DID (if provided) |
vct | Verifiable Credential Type |
iat | Issuance timestamp |
All other claims (everything in claims) become selectively disclosable.
When to use:
- Privacy-sensitive credentials (government ID, health records, age verification)
- GDPR/data minimization compliance — share only what’s needed
- eIDAS 2.0 / HAIP compliance (SD-JWT VC is a required format)
- Scenarios where different verifiers need different subsets of claims
Limitations:
- Slightly more complex than JWT-VC for verifiers to process
- Requires the
vct(Verifiable Credential Type) field - Not all verifier implementations support SD-JWT yet (adoption growing rapidly)
Format comparison
Section titled “Format comparison”| Feature | JWT-VC | SD-JWT VC |
|---|---|---|
| Standard | W3C VC Data Model 2.0 | IETF SD-JWT + W3C VC |
| Privacy | All claims visible | Holder chooses which claims to reveal |
| Complexity | Simple — standard JWT | Moderate — disclosures + hashing |
| HAIP/eIDAS | Not compliant | Compliant (required format) |
| Best for | Organizational creds, certificates | Government ID, health, age verification |
| Verifier support | Universal | Growing (all major wallets) |
| Data minimization | No | Yes — GDPR-friendly |
| Credential size | Smaller | Larger (includes disclosure salts) |
Choosing a format
Section titled “Choosing a format”Do verifiers always need ALL claims? ├─ Yes → JWT-VC (simpler, universal support) └─ No → SD-JWT VC (privacy-preserving)
Targeting eIDAS 2.0 or HAIP compliance? ├─ Yes → SD-JWT VC (required) └─ No → Either format works
Handling personal data (name, DOB, address)? ├─ Yes → SD-JWT VC (data minimization) └─ No → JWT-VC (simpler)Bearer vs. subject-bound credentials
Section titled “Bearer vs. subject-bound credentials”| Type | subject_did | Who can present |
|---|---|---|
| Subject-bound | Set to holder’s DID | Only the holder identified by the DID |
| Bearer | Omitted (empty) | Anyone who possesses the credential |
Bearer credentials are useful for transferable tokens (event tickets, vouchers). Subject-bound credentials are standard for identity documents.
Issue a credential
Section titled “Issue a credential”POST /v1/credentials/issueAuthorization: Bearer <token>Permission required: credentials:issue
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
format | string | Yes | jwt_vc_json or vc+sd-jwt |
issuer_did | string | Yes | Issuer DID (must belong to your tenant — create on DIDs page) |
subject_did | string | No | Holder’s DID. Omit for bearer credentials. |
types | string[] | No | Credential types (default: ["VerifiableCredential"]). Add domain types like CanadianDigitalID. |
claims | object | Yes | JSON object with the credential’s data fields |
vct | string | No | Verifiable Credential Type (SD-JWT only — defaults to first non-VerifiableCredential type) |
Example — JWT-VC (Canadian Digital ID)
Section titled “Example — JWT-VC (Canadian Digital ID)”curl -X POST https://api.baseid.cloud/v1/credentials/issue \ -H "Authorization: Bearer bsk_live_..." \ -H "Content-Type: application/json" \ -d '{ "format": "jwt_vc_json", "issuer_did": "did:key:z6Mk...", "subject_did": "did:key:z6MkHolder", "types": ["VerifiableCredential", "CanadianDigitalID"], "claims": { "givenName": "Alice", "familyName": "Martin", "dateOfBirth": "1990-05-15", "province": "Ontario" } }'Example — SD-JWT VC (age verification)
Section titled “Example — SD-JWT VC (age verification)”curl -X POST https://api.baseid.cloud/v1/credentials/issue \ -H "Authorization: Bearer bsk_live_..." \ -H "Content-Type: application/json" \ -d '{ "format": "vc+sd-jwt", "issuer_did": "did:key:z6Mk...", "subject_did": "did:key:z6MkHolder", "vct": "AgeVerification", "claims": { "age_over_18": true, "age_over_19": true, "age_over_21": true, "dateOfBirth": "1990-05-15" } }'The holder can later present only age_over_19: true without revealing
their actual date of birth.
Example — bearer credential (event ticket)
Section titled “Example — bearer credential (event ticket)”curl -X POST https://api.baseid.cloud/v1/credentials/issue \ -H "Authorization: Bearer bsk_live_..." \ -H "Content-Type: application/json" \ -d '{ "format": "jwt_vc_json", "issuer_did": "did:key:z6Mk...", "types": ["VerifiableCredential", "EventTicket"], "claims": { "event": "BaseID Conference 2026", "venue": "Ottawa Convention Centre", "date": "2026-06-15", "seat": "A-42" } }'No subject_did — anyone with this credential can present it.
Response
Section titled “Response”{ "credential_id": "550e8400-...", "format": "jwt_vc_json", "credential": "eyJhbGciOiJFZERTQSJ9.eyJpc3Mi...", "issuer_did": "did:key:z6Mk...", "subject_did": "did:key:z6MkHolder"}The credential field contains the raw compact serialization:
- JWT-VC: three Base64url-encoded parts separated by
. - SD-JWT VC: JWT followed by
~-separated disclosures
List credentials
Section titled “List credentials”GET /v1/credentials?limit=50&offset=0Authorization: Bearer <token>Permission required: credentials:list
Query parameters
Section titled “Query parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max results (1-100) |
offset | integer | 0 | Pagination offset |
Response
Section titled “Response”[ { "id": "550e8400-...", "tenant_id": "6ba7b810-...", "format": "jwt_vc_json", "credential_data": { "raw": "eyJ...", "format": "jwt_vc_json" }, "issuer_did": "did:key:z6Mk...", "subject_did": "did:key:z6MkHolder", "types": ["VerifiableCredential", "CanadianDigitalID"], "created_at": "2026-03-26T12:00:00Z", "revoked_at": null }]Get a credential
Section titled “Get a credential”GET /v1/credentials/:idAuthorization: Bearer <token>Permission required: credentials:list
Returns a single credential by ID (same shape as list items).
Revoke a credential
Section titled “Revoke a credential”POST /v1/credentials/:id/revokeAuthorization: Bearer <token>Permission required: credentials:revoke
What happens when you revoke
Section titled “What happens when you revoke”- Immediate: The credential’s status changes to
revokedright away - Permanent: Revocation cannot be undone
- Verifiable: Verifiers checking the credential will see the revoked status
- Data preserved: The credential data is kept for audit and compliance purposes
- No notification: The holder is not automatically notified (implement via webhooks if needed)
Response
Section titled “Response”{ "status": "revoked", "credential_id": "550e8400-..."}Returns 404 if the credential doesn’t exist or is already revoked.
Usage limits
Section titled “Usage limits”Credential issuance is metered per month based on your plan:
| Plan | Credentials/month |
|---|---|
| Developer (free) | 100 |
| Startup ($49) | 1,000 |
| Business ($199) | 10,000 |
| Enterprise | Unlimited |
When the monthly limit is reached, issuance returns 400 with a message
prompting an upgrade. Check remaining quota via the
Usage API.
See also
Section titled “See also”- Credential Formats concept — deep dive into JWT-VC, SD-JWT, mDL, BBS+, AnonCreds
- DIDs concept — how issuer identities work
- Console: Credentials — dashboard guide
- Verification API — verify issued credentials