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

# Receive Real-Time Fraud Alerts and Events via Webhooks

> Configure FraudEG webhooks to receive instant notifications for fraud decisions, identity events, account risk signals, and case updates in your systems.

FraudEG webhooks are HTTP POST callbacks that deliver fraud event data to your application the moment something significant happens — a transaction is flagged, an identity check completes, an account risk signal fires, or a case status changes. Rather than polling the FraudEG API repeatedly to check for updates, you register an endpoint once and FraudEG pushes events to you in real time. This is especially important for asynchronous workflows like identity verification, where the result may not be available for several seconds after the initial API call.

## Why use webhooks

Webhooks let you act on fraud signals without building polling loops or accepting latency in your response flows. Key use cases include:

* **Async KYC completion** — receive `identity.verification_completed` the moment a document review finishes, instead of polling `GET /v1/identity/verify` repeatedly
* **Account risk alerts** — react to `account.risk_detected` events to suspend sessions or notify users before damage occurs
* **Dispute automation** — update case queues automatically when `case.updated` events arrive
* **Fraud monitoring** — route `transaction.flagged` and `transaction.blocked` events into your SIEM or alerting pipeline

## Setup guide

<Steps>
  <Step title="Create a webhook endpoint in your application">
    Add a route to your application that accepts HTTP POST requests and returns a `200 OK` response. Keep the handler lightweight — acknowledge the event immediately and process it asynchronously to avoid timeouts.

    ```javascript Node.js (Express) theme={null}
    app.post('/webhooks/fraudeg', express.raw({ type: 'application/json' }), (req, res) => {
      // Acknowledge receipt immediately
      res.sendStatus(200);

      // Process asynchronously
      setImmediate(() => handleFraudEGEvent(req.body, req.headers));
    });
    ```

    Your endpoint must be reachable from the public internet. During local development, use a tunneling tool such as ngrok to expose your localhost.
  </Step>

  <Step title="Register your endpoint via POST /v1/webhooks">
    Call the webhook registration endpoint with your URL and the list of event types you want to receive. You can register multiple endpoints and subscribe each to a different set of events.

    ```bash cURL theme={null}
    curl -X POST https://api.fraudeg.com/v1/webhooks \
      -H "Authorization: Bearer $FRAUDEG_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://yourapp.com/webhooks/fraudeg",
        "events": [
          "transaction.flagged",
          "identity.verification_completed",
          "account.risk_detected",
          "case.updated"
        ],
        "description": "Production fraud alerts"
      }'
    ```

    The response includes a `webhook_id` and a `secret` — store the secret securely in your environment variables. You will use it to verify incoming payloads.

    ```json theme={null}
    {
      "webhook_id": "whk_6mx2pq9r",
      "url": "https://yourapp.com/webhooks/fraudeg",
      "events": ["transaction.flagged", "identity.verification_completed", "account.risk_detected", "case.updated"],
      "secret": "whsec_a3f8k2m...",
      "created_at": "2024-11-14T11:00:00Z"
    }
    ```
  </Step>

  <Step title="Verify webhook signatures">
    FraudEG signs every webhook payload with HMAC-SHA256 using the secret returned at registration. The signature is included in the `X-FraudEG-Signature` request header. Always verify this signature before processing the event.

    <CodeGroup>
      ```javascript Node.js theme={null}
      const crypto = require('crypto');

      function verifyWebhook(payload, signature, secret) {
        const hmac = crypto.createHmac('sha256', secret);
        const expected = hmac.update(payload).digest('hex');
        return crypto.timingSafeEqual(
          Buffer.from(signature),
          Buffer.from(expected)
        );
      }

      // In your Express route:
      app.post('/webhooks/fraudeg', express.raw({ type: 'application/json' }), (req, res) => {
        const sig = req.headers['x-fraudeg-signature'];
        if (!verifyWebhook(req.body, sig, process.env.FRAUDEG_WEBHOOK_SECRET)) {
          return res.status(401).send('Invalid signature');
        }
        const event = JSON.parse(req.body);
        // process event asynchronously
        res.sendStatus(200);
      });
      ```

      ```python Python theme={null}
      import hashlib
      import hmac
      import os
      from fastapi import FastAPI, Request, HTTPException

      app = FastAPI()

      def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
          expected = hmac.new(
              secret.encode(),
              payload,
              hashlib.sha256
          ).hexdigest()
          return hmac.compare_digest(signature, expected)

      @app.post("/webhooks/fraudeg")
      async def handle_webhook(request: Request):
          payload = await request.body()
          signature = request.headers.get("x-fraudeg-signature", "")
          secret = os.environ["FRAUDEG_WEBHOOK_SECRET"]

          if not verify_webhook(payload, signature, secret):
              raise HTTPException(status_code=401, detail="Invalid signature")

          # Acknowledge immediately; process asynchronously
          import asyncio
          asyncio.create_task(process_event(payload))
          return {"status": "ok"}
      ```
    </CodeGroup>

    Use a timing-safe comparison (`timingSafeEqual` in Node.js, `hmac.compare_digest` in Python) to prevent timing attacks that could allow an attacker to forge valid signatures.
  </Step>

  <Step title="Respond with HTTP 200 within 5 seconds">
    FraudEG considers a delivery successful when your endpoint returns any `2xx` status code within **5 seconds** of sending the request. If your response takes longer than 5 seconds, FraudEG marks the delivery as failed and schedules a retry — even if your application eventually processes the event correctly. Return `200` as the first thing your handler does, then process the payload out of band.
  </Step>

  <Step title="Process events asynchronously">
    After acknowledging receipt, route the event payload to your processing logic. Parse the `event_type` field and dispatch to the appropriate handler.

    ```javascript Node.js theme={null}
    async function handleFraudEGEvent(rawBody, headers) {
      const event = JSON.parse(rawBody);

      switch (event.event_type) {
        case 'transaction.flagged':
          await handleFlaggedTransaction(event.data);
          break;
        case 'transaction.blocked':
          await handleBlockedTransaction(event.data);
          break;
        case 'identity.verification_completed':
          await handleVerificationResult(event.data);
          break;
        case 'identity.watchlist_match':
          await handleWatchlistMatch(event.data);
          break;
        case 'account.risk_detected':
          await handleAccountRisk(event.data);
          break;
        case 'case.updated':
          await handleCaseUpdate(event.data);
          break;
        default:
          console.warn(`Unhandled event type: ${event.event_type}`);
      }
    }
    ```
  </Step>
</Steps>

## Webhook event types

FraudEG emits the following event types. Subscribe only to the events relevant to your integration.

| Event type                        | Trigger                                                                            |
| --------------------------------- | ---------------------------------------------------------------------------------- |
| `transaction.flagged`             | A scored transaction exceeded the medium-risk threshold and was flagged for review |
| `transaction.blocked`             | A scored transaction was automatically blocked due to a high-risk decision         |
| `identity.verification_completed` | An async identity verification check (document or liveness) has a final result     |
| `identity.watchlist_match`        | A user matched an entry on a sanctions, PEP, or adverse media list                 |
| `account.risk_detected`           | FraudEG detected a cross-session ATO risk pattern on a user account                |
| `case.updated`                    | A fraud case changed status (e.g., `open` → `under_review` → `resolved`)           |

## Webhook payload structure

Every webhook payload follows a consistent envelope structure. Event-specific data is nested inside the `data` field.

```json theme={null}
{
  "event_type": "transaction.flagged",
  "event_id": "evt_5nq3wr8m",
  "created_at": "2024-11-14T10:23:00Z",
  "data": {
    "transaction_id": "txn_4r8wq1zb",
    "risk_score": 82,
    "decision": "challenge",
    "signals": ["new_device", "velocity_burst"],
    "user_id": "usr_8f3k2p"
  }
}
```

| Field        | Type   | Description                                               |
| ------------ | ------ | --------------------------------------------------------- |
| `event_type` | string | The type of event (see table above)                       |
| `event_id`   | string | Unique identifier for this delivery attempt               |
| `created_at` | string | ISO 8601 UTC timestamp when the event was created         |
| `data`       | object | Event-specific payload — structure varies by `event_type` |

## Retry policy

If your endpoint returns a non-`2xx` response or does not respond within 5 seconds, FraudEG retries the delivery with exponential backoff:

| Attempt   | Delay after previous attempt |
| --------- | ---------------------------- |
| 1st retry | 1 second                     |
| 2nd retry | 2 seconds                    |
| 3rd retry | 4 seconds                    |
| 4th retry | 8 seconds                    |
| 5th retry | 16 seconds                   |

After five failed retries, FraudEG marks the delivery as permanently failed and stops retrying. You can view and manually replay failed deliveries from the **Webhooks** section of the FraudEG dashboard.

## Viewing delivery logs

Every webhook delivery attempt — successful or failed — is logged in your FraudEG dashboard under **Developers → Webhooks → Delivery Logs**. Each log entry shows the event type, delivery timestamp, HTTP response code your endpoint returned, and response body. Use delivery logs to debug endpoint issues, confirm receipt of specific events, and manually replay failed deliveries during incident recovery.

<Warning>
  Always verify the `X-FraudEG-Signature` header before processing any webhook payload. Without signature verification, your endpoint will accept forged requests from any party who discovers its URL — allowing an attacker to inject fraudulent event data into your application. Never skip signature verification, even during development or testing.
</Warning>

<Note>
  Use the `event_id` field to deduplicate events in your processing logic. Because FraudEG retries failed deliveries, your handler may receive the same event more than once. Store processed `event_id` values and check for duplicates before applying any state changes, especially for actions like unlocking accounts, approving verifications, or crediting funds.
</Note>
