Build an issuer
You run the brand side. As a coordinator you speak VCALM — just the coordinator side of it. You don't run VCALM delivery, the on-the-wire exchange with the product's wallet; a workflow service does that. Your whole job is three calls: create an exchange, share an interaction URL that points the product's wallet at it, then poll the exchange until the credential has been issued.
What the coordinator does
- Create an exchange by POSTing the workflow's variables
to its
exchangesendpoint. - Host and share an interaction URL that points the product's wallet at that exchange.
- Poll the exchange until it completes, then read the result.
The workflow service does everything in between — protocol negotiation, optional owner binding, signing, talking to whatever wallet shows up — and hands you back just the result.
1. Create the exchange
POST to your workflow's exchanges endpoint. The body carries a
ttl and the variables the workflow expects — here,
which product the credential is for:
POST https://workflows.example/workflows/provenance-issuance/exchanges
{
"ttl": 900,
"variables": {
"subject": "did:example:bag-456",
"sku": "HB-2026-0042"
}
}
This call is authenticated (your service uses a capability or OAuth2 token).
On success the service returns 204 No Content with a
Location header — that's your exchange URL:
HTTP/1.1 204 No Content
Location: https://workflows.example/workflows/provenance-issuance/exchanges/z19xQ...
2. Host and share the interaction URL
The exchange URL is the vcapi interaction endpoint.
Hosting and sharing it is the coordinator's responsibility — put it on a tag,
QR code, or link, typically wrapped in a presentation request the wallet
understands:
{
"VerifiablePresentation": {
"interact": {
"service": [{
"type": "VerifiableCredentialApiExchangeService",
"serviceEndpoint": "https://workflows.example/workflows/provenance-issuance/exchanges/z19xQ..."
}]
}
}
}
The product's wallet POSTs to that endpoint and runs the exchange with the workflow service directly. Owner binding and credential delivery happen there — you are not in that loop.
3. Poll for the result
While the wallet works, GET the exchange URL (authenticated) until its
state is complete:
GET https://workflows.example/workflows/provenance-issuance/exchanges/z19xQ...
{
"exchange": {
"id": "z19xQ...",
"state": "complete",
"variables": {
"results": {
"ownerBinding": {
"did": "did:example:bag-456",
"verifiablePresentation": { "...": "the wallet's authenticated VP" }
}
}
}
}
}
Verified per-step results land under
exchange.variables.results, keyed by the workflow's step names.
A complete state means the authenticity credential was issued
into the product's wallet.
That's it
A provenance issuer, as a coordinator, is these three calls: create an exchange, host and share the interaction URL, poll for the result. Signing the credential and speaking every wallet's protocol is the workflow service's job — you just create exchanges and read what comes back.
On the wallet end, a standalone client-side VCALM library is still planned; until it ships, wallets run the exchange over the raw HTTP flow. The coordinator side shown here works today against any VCALM workflow service, such as one running @bedrock/vc-delivery.