Skip to main content

Base URLs

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 (initialize-user and dstorage/vcs) authenticate via a Partner JWT in the x-partner-auth header, signed with partnerId and scope: "issue". The JWT does not carry an email claim — the recipient is identified in the initialize-user request body. The header must include kid matching a key in your JWKS endpoint and typ: "JWT". See Partner Authentication. AIR calls an issuer-hosted available-vc or issue-vc endpoint with the shared issuer backend API key in the x-api-key header. Configure the same value in the issuer service (API_KEY) and AIR (issuerBackendApiKey).

Issuance surfaces

There are two ways to issue, both of which sign with issuer-controlled keys and store an encrypted envelope in DStorage:
  • Script-based direct issuance — your script calls POST /auth/initialize-user to resolve the user, builds/signs/encrypts the VC, then stores it with POST /dstorage/vcs.
  • Hosted Issuer Backend — you host available-vc and issue-vc; AIR and the SDK call them to discover and trigger issuance on demand.

1) Initialize / resolve user

Resolve or create the recipient’s AIR Account and return their DID and public key.

Request headers

Request body

Response

The bundled air-issuer-service CSV runner currently uses AIR’s legacy v2 bootstrap contract: POST {AIR_API_ORIGIN}/v2/auth/initialize-user, an x-partner-id header, and { "partnerJwt": "..." } in the request body. For that compatibility contract only, the runner places the recipient email in the JWT and does not set scope. New custom integrations should use the v1 contract above: x-partner-auth, scope: "issue", and { "email": "..." } in the request body.

2) Store encrypted VC

Store the issuer-signed, holder-encrypted VC envelope in DStorage.

Request headers

Request body

The issuer service encrypts the signed credential with X25519 key agreement, HKDF-SHA-256, and AES-256-GCM. Its encryption helper returns { encryptedData, iv, authTag, dataEncPublicKey }; map encryptedData to data and dataEncPublicKey to encryptedKey when calling DStorage.

Response

Returns 201 with the storagePath / storage reference. Record it as your issuance result.

3) Issuer-hosted endpoints

For the hosted Issuer Backend path, AIR calls your endpoints with an identity it resolved server-side. Both endpoints require:
Do not authorize issuance from holderDID alone. Use the AIR-resolved userId to look up eligibility and claims in your own systems.

POST /available-vc

Return credentials the holder can claim. schemaId and proofType are optional filters.
Response:

POST /issue-vc

Issue one credential, encrypt it to the holder, upload it to DStorage, and persist the issuance record.
On success, the endpoint returns 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.

4) Credential status and revocation

The issuer service exposes public status URLs for verifiers and admin-protected endpoints for issuer operations. Set ISSUER_ORIGIN to the public HTTPS origin serving these routes; the credential status URL is embedded in every issued BJJ credential.

Public status endpoints

These endpoints do not use an API key: Example revocation status response:

Admin endpoints

Admin endpoints require:

GET /admin/issuance-history

Returns paginated issuance records. Supported query parameters:

POST /admin/revoke

Revoke the credential identified by its nonce:
On success, the endpoint returns an empty response body, marks the nonce as revoked, and sets revokedAt on matching issuance records.

Script example (Node.js)

A minimal script-based direct issuance flow: resolve the user, build/sign/encrypt the VC, store it in DStorage.

Retry with backoff

The email passed to initialize-user must be the individual recipient’s AIR Account email — it is the routing key that determines which account the credential lands in. Resolve it per recipient; never reuse a partner, service, admin, or static email across recipients.

Error reference

Troubleshooting

  • If dstorage/vcs succeeds, record the storagePath; the credential is available for the holder to present at any verifier.
  • For v1 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.