> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yoid.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive real-time notifications for credential issuance and verification events.

## Overview

Webhooks notify your application in real time when events happen on the YoID platform — a youth accepts a credential, a verification is completed, or a request expires. This eliminates the need to poll the API for status updates.

<Warning>
  **Webhooks are the recommended approach for production integrations.** In the YOMA ecosystem, a youth may take minutes or days to respond to a verification request. Polling creates unnecessary load and doesn't scale. Use webhooks as the primary pattern, and polling only as a fallback during development.
</Warning>

## Supported Events

<Tabs>
  <Tab title="For Learning & Impact Partners">
    | Event                                | Description                                                   |
    | ------------------------------------ | ------------------------------------------------------------- |
    | `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.partiallyIssued` | Some credentials in a batch issuance were issued, but not all |
    | `openid4vc.issuance.expired`         | Credential offer expired before youth accepted                |
  </Tab>

  <Tab title="For Employers & Opportunity Providers">
    | Event                              | Description                                            |
    | ---------------------------------- | ------------------------------------------------------ |
    | `openid4vc.verification.requested` | Verification request created                           |
    | `openid4vc.verification.verified`  | Youth successfully presented credentials               |
    | `openid4vc.verification.failed`    | Verification attempt failed                            |
    | `openid4vc.verification.expired`   | Request expired before youth responded                 |
    | `openid4vc.verification.data`      | Credential data received from the youth's presentation |
  </Tab>
</Tabs>

## Registering a Webhook Endpoint

```bash theme={null}
curl -X POST "https://test.didxtech.com/me-creds/api/endpoints" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/webhooks/yoid",
    "filterTypes": ["openid4vc.issuance.completed", "openid4vc.issuance.failed"]
  }'
```

### Request Body

| Field         | Type      | Required | Description                                                                   |
| ------------- | --------- | -------- | ----------------------------------------------------------------------------- |
| `url`         | string    | Yes      | Your HTTPS endpoint URL                                                       |
| `filterTypes` | string\[] | No       | Array of event types to subscribe to. If omitted, you receive **all** events. |

Available filter types:

| Event Type                           | Description                                            |
| ------------------------------------ | ------------------------------------------------------ |
| `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.partiallyIssued` | Some credentials in a batch were issued, but not all   |
| `openid4vc.issuance.expired`         | Credential offer expired                               |
| `openid4vc.verification.requested`   | Verification request created                           |
| `openid4vc.verification.verified`    | Youth successfully presented credentials               |
| `openid4vc.verification.failed`      | Verification attempt failed                            |
| `openid4vc.verification.expired`     | Request expired                                        |
| `openid4vc.verification.data`        | Credential data received from the youth's presentation |

<Tip>
  Use `filterTypes` to reduce noise — an issuer that doesn't verify credentials doesn't need presentation events.
</Tip>

### Response (201 Created)

```json theme={null}
{
  "data": {
    "id": "du398r0fqd",
    "url": "https://your-domain.com/webhooks/yoid",
    "filterTypes": ["openid4vc.issuance.completed", "openid4vc.issuance.failed"],
    "createdAt": "2025-01-01T00:00:00.000Z",
    "updatedAt": "2025-01-01T00:00:00.000Z"
  }
}
```

## Listing Webhook Endpoints

```bash theme={null}
curl -X GET "https://test.didxtech.com/me-creds/api/endpoints" \
  -H "Authorization: Bearer <access_token>"
```

Returns an array of all registered webhook endpoints for your organisation.

## Removing a Webhook Endpoint

```bash theme={null}
curl -X DELETE "https://test.didxtech.com/me-creds/api/endpoints/du398r0fqd" \
  -H "Authorization: Bearer <access_token>"
```

Returns **204 No Content** on success.

## Webhook Payload Structure

All payloads include an `eventType` and a `payload` with a resource reference:

```json theme={null}
{
  "eventType": "openid4vc.issuance.completed",
  "payload": {
    "openId4VcIssuanceId": "cmfwfjxdq003js601bmgy9tva"
  }
}
```

Use the resource ID to fetch the full details from the relevant API endpoint.

## Technical Requirements

Your webhook endpoint must:

* Accept **POST** requests
* Use **HTTPS** exclusively
* Respond promptly with a **2xx** status code
* Handle **duplicate deliveries** — the platform may retry on failure
* Be **idempotent** — processing the same event twice should produce the same result

## Implementation Example

A production-ready webhook handler for a learning partner tracking credential acceptance:

```javascript theme={null}
const processedWebhooks = new Set();

app.post("/webhooks/yoid", async (req, res) => {
  const webhookId = req.headers["webhook-id"];
  const { eventType, payload } = req.body;

  // Deduplicate — the platform may send the same webhook more than once
  if (processedWebhooks.has(webhookId)) {
    return res.status(200).send("OK");
  }
  processedWebhooks.add(webhookId);

  // Respond immediately, process asynchronously
  res.status(200).send("OK");

  // Handle the event
  switch (eventType) {
    case "openid4vc.issuance.completed":
      // Thandi accepted her Web Development Completion credential
      console.log(`Credential accepted: ${payload.openId4VcIssuanceId}`);
      await updateInternalRecords(payload.openId4VcIssuanceId, "accepted");
      break;

    case "openid4vc.issuance.expired":
      // Credential offer expired — youth didn't accept in time
      console.log(`Credential expired: ${payload.openId4VcIssuanceId}`);
      await flagForFollowUp(payload.openId4VcIssuanceId);
      break;

    case "openid4vc.verification.verified":
      // Youth shared their credentials with a verifier
      console.log(`Presentation verified: ${payload.openId4VcPresentationId}`);
      break;
  }
});
```

## Use Cases in the YOMA Ecosystem

| Partner Type                    | Event                   | Action                                                              |
| ------------------------------- | ----------------------- | ------------------------------------------------------------------- |
| **Umuzi** (issuer)              | `issuance.completed`    | Mark programme completion as "credentialed" in their LMS            |
| **Umuzi** (issuer)              | `issuance.expired`      | Flag youth for follow-up — they may not have activated their wallet |
| **IXO** (impact)                | `issuance.completed`    | Record verified participation for funder reporting                  |
| **JobJack** (verifier)          | `verification.verified` | Proceed with candidate placement                                    |
| **Scholarship fund** (verifier) | `verification.verified` | Approve eligibility and move to next application stage              |

## Local Development

Use [ngrok](https://ngrok.com/) to expose your local server via a public HTTPS URL during development:

```bash theme={null}
ngrok http 3000
```

Register the resulting `https://` ngrok URL as your webhook endpoint. The platform retries failed deliveries automatically.

<Note>
  For production, consider a webhook ingestion service (like Svix or AWS EventBridge) that handles retries, logging, and replay — especially if your backend may be temporarily unavailable.
</Note>
