Skip to main content
This page covers two separate surfaces. Do not mix their base URLs or authentication headers.

AIR API

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, /admin/*, and the status endpoints are hosted on your issuer service under its public ISSUER_ORIGIN. You never call the AIR API base URL for them.
Moca Chain mainnet is live. Production SD-JWT issuers register in the production Developer Dashboard; see Production mainnet access.

Authentication

Direct AIR API requests for direct issuance use a Partner JWT sent in the x-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 service uses its own keys, described in Your issuer service. They are never sent to the AIR API.

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’s POST /available-vc to retrieve an encrypted credential-subject preview. After the holder confirms, AIR calls POST /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 issuance — no holder interaction. The recipient is resolved by email with POST /auth/initialize-user, the VC is issuer-signed and encrypted to the returned holder public key, and the envelope is stored through POST /dstorage/vcs. The SD-JWT issuer service wraps these steps in POST /admin/issue-vc (see Admin endpoints). You can also call the two AIR API endpoints yourself.

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 by initialize-user. AIR and DStorage receive the encrypted envelope and do not construct or sign the credential.

Request headers

Request body

Response 201

Your issuer service

These routes run on your own issuer service at its public ISSUER_ORIGIN, not on the AIR API. The examples follow the SD-JWT branch of the AIR issuer service. Iden3 issuers use a separate branch; see Iden3 credentials.

3) Holder-facing endpoints (called by AIR)

Your issuer service exposes POST /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:
Configure the same key as 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) Admin endpoints (called by your servers)

Admin routes require x-admin-api-key: <ADMIN_API_KEY>. Call them only from your own servers; never from a browser or through AIR.

POST {ISSUER_ORIGIN}/admin/issue-vc

Resolves the holder through AIR initialize-user, signs the SD-JWT VC, encrypts it to the holder, and uploads it to DStorage. No registered schema class is needed.
Credentials issued this way have no cnf holder key.

5) Public endpoints (called 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. For SD-JWT issuers it also defines the issuer DID (did:web:<host>), so changing it changes your issuer identity. The Iden3 issuer service also serves GET /credential-status/:nonce, which returns the non-revocation Merkle proof and issuer tree state. See Iden3 credentials. Example revocation status response:

Error reference

Troubleshooting

  • If dstorage/vcs succeeds, record the storagePath; the credential is available for the holder to present to any AIR verifier.
  • If AIR never calls /available-vc or /issue-vc, confirm that the Issuer DID, Partner ID, API key, and both public endpoint URLs have been registered and activated by AIR.
  • For authentication errors, verify the JWT contains partnerId and scope: "issue" (not the recipient email), and that the header includes typ: "JWT".
  • Ensure your JWKS endpoint is public and kid maps to the signing key.
  • The SDK’s credentialId is the Dashboard issuance program ID. The issuer backend receives schemaId. Passing one in place of the other can result in “schema not found” or routing failures.