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

# Webhooks

>  Webhook overview, Dodo events, security, retries, and examples.

## Webhook Overview

Scriptonia receives **Dodo** webhooks at `POST /api/dodo/webhook` to update workflow state when a payment succeeds, fails, or is refunded. Other webhooks (e.g. GitHub) are outside this doc.

***

## Dodo Webhook

### Endpoint

```
POST /api/dodo/webhook
Content-Type: application/json
```

* **Body parsing:** Disabled (`api.bodyParser: false`) so the raw body can be used for signature verification.

***

## Event Types

Handled in `pages/api/dodo/webhook.ts`:

| Event               | Alias                                    | Action                                                                                                                                                                                                                                  |
| :------------------ | :--------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `payment.succeeded` | `payment_succeeded`, `payment.completed` | Read `data` or root; `metadata.session_id`, `metadata.platform`; `data.payment_id` or `data.id`. Update `Workflow`: `paymentMethod: 'dodo'`, `dodoPaymentId`, `currentStage: 'payment_processing'`, `selectedPlatform` (from metadata). |
| `payment.failed`    | `payment_failed`                         | Log; optionally update workflow.                                                                                                                                                                                                        |
| `refund.succeeded`  | `refund_succeeded`                       | If `metadata.session_id`, set `paymentMethod: null`, `dodoPaymentId: null` on `Workflow`.                                                                                                                                               |
| (other)             | —                                        | Log as unhandled; still return 200.                                                                                                                                                                                                     |

***

## Security

### Signature verification

* **Header:** `x-dodo-signature` or `dodo-signature` (single string; if array, treated as invalid).
* **Secret:** `DODO_WEBHOOK_SECRET`. If unset, verification is skipped (insecure in production).
* **Algorithm:** HMAC-SHA256 of the **raw body** (UTF-8), hex-encoded; compared with `crypto.timingSafeEqual` to the header value.
* On invalid signature: **401** `{ received: false, error: "Invalid signature" }`.

### Raw body

* The handler reads the raw body from `req` (stream) because Next.js does not parse it when `bodyParser: false`. The same bytes must be used for HMAC and for `JSON.parse`.

***

## Retry Logic

* **Server behavior:** The handler always returns **200** (or 401 on bad signature) so Dodo does not retry on “success.”
* On processing errors (e.g. DB update fails): the handler still returns **200** and `{ received: true, error: message }` to avoid retries for malformed or unprocessable payloads. Log errors for debugging.
* **Dodo:** Configure retries and backoff in the Dodo dashboard. No custom retry logic is implemented in Scriptonia.

***

## Examples

### payment.succeeded (conceptual)

```
{
  "type": "payment.succeeded",
  "data": {
    "payment_id": "pay_xxx",
    "id": "pay_xxx",
    "metadata": {
      "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "platform": "Web Application"
    }
  }
}
```

Handler: `prisma.workflow.update({ where: { sessionId }, data: { paymentMethod: 'dodo', dodoPaymentId, currentStage: 'payment_processing', selectedPlatform } })`.

### Refund

```
{
  "type": "refund.succeeded",
  "data": {
    "metadata": { "session_id": "a1b2c3d4-..." }
  }
}
```

Handler: `prisma.workflow.update({ where: { sessionId }, data: { paymentMethod: null, dodoPaymentId: null } })`.

***
