VC issuance contract (MBI two-phase)
Issuance is a single, two-phase endpoint on the MBI RS; behaviour branches on the presence of the X-PAYMENT header. The holder signs the VC payload up front (folding the legacy construct-sign/submit-sign into one call), so MBI can prove the request comes from the holder both before and after payment.
Request body (both phases)
Mirrors the canonical VC payload:
{
"data": "[{\"templateId\":\"<fixed>\",\"metadata\":{ …attribute values… }}]", // canonical JSON string, holder-signed
"signData": "3044...hex...", // holder Ed25519 signature over `data`
"publicKey": "b0014...hex...", // holder public key → derives the subject address
"expirationDate": "2027-01-01" // optional
}Phase 1 (no
X-PAYMENT) → MBI verifies the holder signature, then returns 402 withaccepts[](andextra.paymentId). A request not signed by a real holder is rejected before any 402.Phase 2 (with
X-PAYMENT,paymentIdechoed in the body) → MBI re-verifies the holder signature, asserts the VC-payload signer == the x402 payer (one account both pays and owns the VC), verifies the amount exactly, then verify + settle via the Facilitator, and issues the VC on settlement success.
Success (200 OK, wrapped): { vcId, paymentId, txHash, verifiableCredential }.
Key invariants
Subject = payer. The VC subject DID is derived from
publicKey; MBI asserts it equals the payment signer. There is noholderDidfield.Settlement-bound, idempotent issuance. MBI issues once per settled payment (keyed by
payment_id/tx_hash); a repeat call returns the already-issued VC without re-charging.GET /v1/vc/pay/status/{paymentId}recovers the outcome if the phase-2 response is lost.Canonical-bytes caveat (G3).
data's key order (templateIdthenmetadata) and compact JSON must be byte-identical to MBI'sconstructSignData, or holder-signature verification fails. The holder signs the same bytes over Wallet BE's/sign-blob.Free mode (MVP bypass, config-only). Setting
mbi.x402.payment-required = falseskips both phases, MBI verifies the holder signature and issues directly (no 402, noX-PAYMENT). This is how a no-payment issuance is realised on the MBI path; it is a config toggle and no environment currently enables it (the MVP fee-free grace period ended 2026-07-14). (The requirement designates ZCert as the MVP issuer; MBI's free mode is the equivalent mechanism on the paid-issuer path.)
Last updated