- Read concepts first: Issuing Credentials
- For JWT/JWKS setup and signing examples, see Partner Authentication.
AIR API base URL
This base URL applies only to the AIR-hosted endpoints on this page —POST /auth/initialize-user and POST /dstorage/vcs — shown below as {AIR_API_BASE_URL}.
/available-vc, /issue-vc, and the credential-status endpoints are hosted on your issuer backend under its public ISSUER_ORIGIN. AIR calls these endpoints during hosted SDK issuance — you never call the AIR API base URL for them.The production base URL is for approved production partners on Moca Chain private Mainnet. See Production mainnet access before requesting mainnet $MOCA gas tokens.
Authentication
Direct AIR API requests for direct issuance use a Partner JWT sent in thex-partner-auth header. The JWT must include the partner identity, at minimum partnerId, and for issuance flows should be scoped for issuance, e.g. scope: "issue" where required by the endpoint. The JWT should be signed with the partner’s private key and verifiable through the configured JWKS endpoint; its header should include kid matching the JWKS key and typ: "JWT". For the newer initialize-user flow, the recipient/user identifier, typically email, is passed in the initialize-user request body, and the returned DID/public key are then used when storing the encrypted VC through /dstorage/vcs.
Your issuer backend protects POST /available-vc and POST /issue-vc with a shared API key in the x-api-key header. Configure this value as API_KEY in the issuer service and register the same value with AIR during issuer activation. During hosted SDK issuance, AIR—not the browser—calls these endpoints and sends the key. Never expose this key to frontend code.
Issuance surfaces
There are two issuance patterns. In both cases, the issuer controls the signing keys and the resulting encrypted credential is stored in DStorage.- Hosted SDK issuance — holder present. Your frontend calls
air.issueCredential(...). AIR resolves the authenticated holder and calls your registered issuer backend’sPOST /available-vcto retrieve an encrypted credential-subject preview. After the holder confirms, AIR callsPOST /issue-vc. The issuer backend generates the authoritative claims, signs the VC, encrypts it to the holder’s public key, persists the issuance record, and uploads the envelope to DStorage. - Direct (on-demand) issuance — no holder interaction. Your backend calls
POST /auth/initialize-userwith the recipient’s email, builds and issuer-signs the VC, encrypts it to the returned holder public key, and stores the encrypted envelope throughPOST /dstorage/vcs. The issuer service’sbatch-issue-vc-csvrunner is a reference implementation of this path; it does not go through/issue-vc.
1) Initialize or resolve an AIR account
Resolve or create the recipient’s AIR Account using their email address, and return the AIR user UUID, holder DID, and public key required for direct issuance.Request headers
Request body
Response
2) Store encrypted VC
Store an encrypted VC envelope in DStorage. Before calling this endpoint, the issuer must build and sign the VC, then encrypt the complete signed credential to the holder’s public key returned byinitialize-user.
AIR and DStorage receive the encrypted envelope and do not construct or sign the credential.
Request headers
Request body
Response 201
3) Issuer-hosted endpoints
Your issuer backend exposesPOST /available-vc and POST /issue-vc for hosted SDK issuance. AIR—not the browser—calls these registered endpoints with the holder identity resolved through the authenticated AIR session.
Both endpoints require:
API_KEY in the issuer service and register it with AIR during issuer activation. These routes are hosted under your issuer backend’s public ISSUER_ORIGIN, not under the AIR API base URL.
Do not authorize issuance or retrieve claims from holderDID alone. Use the AIR-resolved partner primary userId to look up the holder’s eligibility and authoritative claims in your own systems. Do not assume this value is interchangeable with the AIR user UUID returned by initialize-user.
POST {ISSUER_ORIGIN}/available-vc
Return credentials the holder can claim. schemaId and proofType are optional filters. AIR calls this endpoint during hosted SDK issuance to discover credentials available to the authenticated holder. The issuer backend validates eligibility using userId, generates authoritative claims, encrypts the preview to pubKey, and returns it to AIR.
schemaId is a credential schema ID—not the Dashboard issuance program ID
Response:
POST {ISSUER_ORIGIN}/issue-vc
AIR calls this endpoint after the holder confirms hosted issuance. The issuer backend regenerates or retrieves the authoritative claims, signs the complete VC, encrypts it to pubKey, persists the issuance record, uploads the encrypted envelope to DStorage, and returns HTTP 201 with an empty body.
On success, the endpoint returns
201 with an empty response body. The issuer backend uploads the encrypted credential and stores the DStorage response internally; callers should not expect a storagePath in this response. A missing or mismatched x-api-key on either issuer-hosted endpoint returns 403, not 401.
4) Credential status and revocation
The issuer service exposes public credential-status URLs used by verifiers. These routes do not require an API key.ISSUER_ORIGIN must be the stable public HTTPS origin of the issuer service, without a trailing slash. The issuer service embeds a URL under this origin into each issued BJJ credential. Changing the origin later can break status resolution for previously issued credentials.
Public status endpoints
These endpoints are hosted underISSUER_ORIGIN and do not use an API key:
Example revocation status response:
Error reference
Troubleshooting
- If
dstorage/vcssucceeds, record thestoragePath; the credential is available for the holder to present at any verifier. - If AIR never calls
/available-vcor/issue-vc, confirm that the Issuer DID, Partner ID, API key, and both public endpoint URLs have been registered and activated by AIR. - For v1 authentication errors, verify the JWT contains
partnerIdandscope: "issue"(not the recipient email), and that the header includestyp: "JWT". - Ensure your JWKS endpoint is public and
kidmaps to the signing key. - The SDK’s
credentialIdis the Dashboard issuance program ID. The issuer backend receivesschemaId. Passing one in place of the other can result in “schema not found” or routing failures.