This guide walks you through creating, testing, and managing webhook endpoints in the RiskOS™ Dashboard.

## Quick start

1. ### Prepare your endpoint

Create an HTTPS endpoint capable of receiving `POST` requests from RiskOS™. Ensure the endpoint accepts `application/json` payloads, validates authentication, and returns a `2xx` response code after successful receipt.

2. ### Access the Developer Workbench

Go to **Developer Workbench > Webhooks** in the RiskOS™ Dashboard. From this page, you can view, edit, or create webhook configurations for your account.

3. ### Create a new webhook

Click **Add a webhook** and enter the following details:

- **Name**: A descriptive name to help identify this webhook later.
   - **URL**: The HTTPS destination endpoint that receives webhook events.
   - **Use Case**: Scope webhook delivery to a specific RiskOS™ use case (for example, Consumer Onboarding or Account Takeover).
   - **Event Type**: Select one or more event types to subscribe to. Each event follows a predefined schema.
   - **Auth Type**: Choose from the supported authentication methods:
     - **Basic Authentication** — Username and password-based authentication.
     - **Bearer Token** — Uses a UUID token for authentication.
     - **OAuth2** — Requires a client ID, client secret, and token URL.

4. ### Test your webhook

Click **Continue to Test** to send a sample payload to your endpoint. The RiskOS™ Dashboard displays success or failure results, confirming whether your webhook is reachable and properly configured.

5. ### Activate your webhook

Once the test is successful, click **Save** to activate your webhook for real-time event delivery. RiskOS™ now begins sending event notifications whenever subscribed events occur.

## Webhook testing tools

To verify that events are being successfully triggered and sent by RiskOS™, you can use [Webhook Cool](https://webhook.cool/) (or a similar tool), which provides a unique URL to receive events.

> ⚠️
>
> **Security note**:
>
> When using external testing tools like Webhook Cool, be mindful that your webhook payload contains your authorization and sensitive customer information (depending on your workflow configuration). RiskOS™ doesn't endorse this third-party tool and isn't responsible for the security or handling of data received by Webhook Cool or any other external service. Use such tools only for non-production testing and with awareness of the data you expose.

## Manage webhooks

Users with the appropriate permissions can configure and manage their webhooks on the **Developer Workbench > Webhooks** section of the RiskOS™ Dashboard.

The **Webhooks** section displays all configured webhooks with key details:

- **Webhook URL**: Destination endpoint that receives event payloads.
- **Created / Last Modified**: When the webhook was created or last updated.
- **Subscribed Events**: Event types that trigger the webhook.

## Delete a webhook

Click the trash icon for the webhook, then confirm **Delete**.

## Sample receivers

Use the code samples in this section as a starting point. They acknowledge and de-duplicate via `event_id`.

### Node.js (Express)

```javascript
import express from "express";
import crypto from "crypto";

const app = express();
app.use(express.json({ type: "application/json" }));

// Replace with a real, persistent store:
const seen = new Set();

app.post("/webhooks/riskos", async (req, res) => {
  const { event_id, event_type, data } = req.body || {};
  if (!event_id || !event_type) return res.status(400).send("Bad Request");

// Idempotency: drop duplicates
  if (seen.has(event_id)) return res.status(200).send("OK");
  seen.add(event_id);

// Queue async work (do not block the response)
  queueMicrotask(() => handleEvent(event_type, data).catch(console.error));

return res.status(200).send("OK");
});

async function handleEvent(type, data) {
  switch (type) {
    case "evaluation_completed":
      // process...
      break;
    default:
      // no-op
  }
}

app.listen(3000, () => console.log("Listening on :3000"));
```

### Python (Flask)

```python
from flask import Flask, request, jsonify

app = Flask(__name__)
seen = set()  # replace with durable store

@app.post("/webhooks/riskos")
def riskos():
    payload = request.get_json(silent=True) or {}
    event_id = payload.get("event_id")
    event_type = payload.get("event_type")
    data = payload.get("data")

if not event_id or not event_type:
        return ("Bad Request", 400)

if event_id in seen:
        return ("OK", 200)
    seen.add(event_id)

# Do processing async/off-thread in production
    handle_event(event_type, data)
    return ("OK", 200)

def handle_event(event_type, data):
    if event_type == "evaluation_paused":
        pass  # handle
    # etc.

if __name__ == "__main__":
    app.run(port=3000)
```
