Issue a Credential Directly to a Wallet
This page walks through pushing a credential into a Business Wallet unattended, no QR code, no redirect, no accept step. It is a two-call sequence:
- Create a credential offer with the Start Issue Credential API.
- Push that offer into the target wallet with
directIssue=true.
Preconditions
- A credential template is configured for the credential you want to issue.
- OAuth2 or an API key is enabled for your backend.
- The issuer is registered in the target wallet as a
trusted contact with
directIssueAllowed = true. Without this, the credential is accepted and then discarded. - You know the
walletExternalKeyof the target wallet.
Step 1: Create the credential offer
Call the Start Issue Credential API with the template key and the
credential attributes. Unlike the QR flow, you do not request a qr_code.
POST /api/v2/credential/issue
Content-Type: application/json
{
"correlation_id": "89cba89",
"template_id": "ebw_oid",
"claims": {
"id": "90004760",
"name": "CoolSoft B.V.",
"issuing_authority": "Credenco",
"issuing_country": "NL"
}
}
The response contains the credential offer URI:
{
"correlation_id": "89cba89",
"request_uri": "openid-credential-offer://?credential_offer_uri=https://wallet.credenco.com/api/oidc/credential-offer/abc123",
"status_uri": "https://wallet.credenco.com/api/v2/issue/89cba89"
}
You only need the credential_offer_uri query parameter from request_uri for the next
step. Parse it out of the request_uri and URL-decode it.
Step 2: Push the offer into the wallet
Post the offer to the wallet's OIDC offer endpoint with directIssue=true, passing the
credential_offer_uri you extracted:
POST /api/oidc/offer/{walletExternalKey}?directIssue=true&credential_offer_uri=https%3A%2F%2Fwallet.credenco.com%2Fapi%2Foidc%2Fcredential-offer%2Fabc123
| Parameter | In | Description |
|---|---|---|
walletExternalKey | path | External key of the target wallet. |
directIssue | query | Set to true for unattended issue. Omit it to drop the offer in the inbox instead. |
credential_offer_uri | query | The URL-encoded credential_offer_uri extracted from the request_uri in step 1. |
The endpoint responds with 201 Created. Behind it, the wallet:
- Completes the OpenID4VCI exchange on the holder's behalf, with no user interaction.
- Verifies the issuer DID against the wallet's trusted contacts.
- Keeps the credential if the issuer is trusted, or discards it if not.
The first call mints the credential offer from your issuer. The second call delivers that offer
to a specific wallet. Splitting them lets the same offer mechanism serve both the attended
(QR / redirect) flows and this unattended one, the only difference is directIssue=true.
Step 3: Check the result
Use the Get Issue Status API with your correlation_id to
confirm issuance and retrieve the revocation_uuid (needed later to revoke the credential, if
a status list is configured):
{
"status": "issue_request_created",
"correlation_id": "89cba89",
"revocation_uuid": "0e2c1f62-3392-462e-a25e-483fa0e2a3a3"
}
If the issuer is not a trusted contact of the target wallet, the OIDC offer endpoint still
returns 201 and issuance still reports success, but the wallet discards the credential, so
it never appears to the holder. Always register the trusted contact
first.
Worked example: a company credential
This sequence places the ebw_oid company
credential into a new Business Wallet:
- The backend collects the official company info (CoC number, legal name).
- It calls
POST /api/v2/credential/issuewithtemplate_id: "ebw_oid"and the company claims (id,name,issuing_authority: "Credenco",issuing_country: "NL"). - It extracts the
credential_offer_urifrom the response and posts it toPOST /api/oidc/offer/{walletExternalKey}?directIssue=true. - Because Credenco is a trusted contact of the wallet, the credential is retained and is present the first time the user opens their wallet.