Skip to main content

Deferred issuance

Issue a credential later, for example after a manual review or a background check. Your attribute provider tells EUDIPLO to defer, the wallet polls with a transaction ID, and your backend completes or fails the transaction through the management API.

Prerequisites: an attribute provider (or offer webhook source) for the credential configuration, and a client with the issuance:offer role.

1. Defer in the attribute provider​

Answer the attribute provider request with:

{ "deferred": true, "interval": 5 }

EUDIPLO stores the wallet's holder key and answers the wallet with HTTP 202 and { "transaction_id": "…", "interval": 5 }. interval (seconds, default 5) is the polling interval suggested to the wallet.

Deferred requests must carry exactly one key proof with a nonce; batch requests (several proofs) are rejected with invalid_proof.

2. Let the wallet poll​

The wallet polls POST /issuers/{tenant}/vci/deferred_credential with {"transaction_id": "…"} and the access token of the issuance (with DPoP when dPopRequired is set). While the transaction is pending, it receives HTTP 400:

{ "error": "issuance_pending", "error_description": "The credential issuance is still pending", "interval": 5 }

3. Complete or fail the transaction​

When your process has finished, provide the claims:

curl -X POST "$EUDIPLO_URL/api/issuer/deferred/$TRANSACTION_ID/complete" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "claims": { "name": "Max", "member_id": "M-001" } }'

EUDIPLO signs the credential immediately and answers 200 with { "transactionId", "status": "ready", "message" }. The claims are validated against the configuration's fields like every other claim source; claims holds the claim values directly, not keyed by configuration ID.

If the credential must not be issued:

curl -X POST "$EUDIPLO_URL/api/issuer/deferred/$TRANSACTION_ID/fail" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "error": "Identity verification failed" }'

error is optional; the wallet's next poll receives invalid_transaction_id with it as description. complete answers 404 for an unknown transaction or one that is no longer pending, fail for an unknown transaction.

Transaction ID

EUDIPLO currently does not send the transaction_id to your backend: the attribute provider request carries only the session ID, and no management endpoint lists transactions. Only the wallet receives the ID.

Transaction states​

StatusMeaningWallet's next poll
pendingWaiting for complete or failissuance_pending
readyCredential signedCredential (once)
retrievedThe wallet fetched the credentialinvalid_transaction_id
failedMarked as failedinvalid_transaction_id
expired24 hours passed since the transaction was createdinvalid_transaction_id

Expired transactions are deleted every hour. A poll with an access token that does not belong to the transaction's session also answers invalid_transaction_id.