Overview
With a credential template defined, you can now issue a specific credential by providing the template ID and the youth’s actual data. The API returns URIs that deliver the credential to the youth’s wallet.
Endpoint
POST https://test.didxtech.com/me-creds/api/credentials/issuance
Request
curl -X POST "https://test.didxtech.com/me-creds/api/credentials/issuance" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"credentialTemplateId": "tpl_6421a8905c17830c188e2e2f",
"attributes": {
"programmeName": "Umuzi Web Development Programme",
"completionDate": "2025-03-15",
"fullName": "Thandi Molefe",
"skillsCovered": "HTML, CSS, JavaScript, React, Node.js",
"assessmentScore": "87"
}
}'
Request Body
| Field | Type | Description |
|---|
credentialTemplateId | string | The id from the credential template created in Step 2 |
attributes | object | Key-value pairs matching the attributes defined in the template. Required attributes must be present. |
Response
HTTP 201 Created
{
"data": {
"id": "iss_cm7d9cq5600pwk3zq3kmpg8uc",
"status": "offered",
"credentials": [
{
"id": "cred_abc123def456",
"status": "pending",
"revocable": true
}
],
"offerUri": "https://didx.co.za/invitation?credential_offer_uri=...",
"offerQrUri": "https://didx.co.za/invitation?credential_offer_uri=...&qr=true",
"exchange": "openid4vc",
"format": "sd-jwt-vc"
}
}
Key Response Fields
| Field | Description |
|---|
id | Top-level issuance ID — use this for revocation and status tracking via webhooks |
credentials | Array of individual credentials in this issuance. Each has its own id, status, and revocable flag. |
offerUri | The URI to pass to Step 4 — this is what delivers the credential to the youth’s wallet |
offerQrUri | QR-optimised version for scanning with a wallet app. Do not pass this to the send-credential endpoint — use offerUri instead. |
status | offered — the credential is ready to be delivered to the youth’s wallet |
exchange | openid4vc — ensures cross-wallet compatibility |
format | sd-jwt-vc — selective disclosure enabled |
Two IDs, different purposes. The top-level id (iss_cm7d9cq5600pwk3zq3kmpg8uc) is the issuance ID — use this for revocation and webhook correlation. The nested credentials[0].id is the individual credential ID. For revocation, always use the top-level id, not credentials[0].id.
What Happens on the Youth’s Side
At this point, the credential exists as an offer — it hasn’t reached the youth’s wallet yet. The next step (Step 4) delivers it. But once delivered:
- If Thandi has already activated her wallet, the credential appears as a pending item she can accept or reject
- If she hasn’t activated yet, the credential waits in custody until she signs in
- She reviews the credential attributes in her wallet before accepting
- Once accepted, the credential is stored permanently in her wallet and available for presentation to verifiers
Checking Issuance Status
You can check the status of a specific issuance:
curl -X GET "https://test.didxtech.com/me-creds/api/credentials/issuance/iss_cm7d9cq5600pwk3zq3kmpg8uc" \
-H "Authorization: Bearer <access_token>"
Tracking Issuance Status
Rather than polling, use webhooks to track what happens after issuance:
| Event | Meaning |
|---|
openid4vc.issuance.offered | Credential offer sent to youth |
openid4vc.issuance.completed | Youth accepted and received the credential |
openid4vc.issuance.failed | Issuance attempt failed |
openid4vc.issuance.expired | Offer expired before youth accepted |