# Webhook Notifications

Takumi API can send webhook notifications when a workflow (such as an assessment) completes. This lets you detect workflow completion without polling and automatically start retrieving results or running follow-up processes.

## Workflow Completion Event

When a workflow finishes, an HTTP POST request is sent to the specified webhook endpoint. The event `type` is `api.workflow_run.exited`.

```json
{
  "type": "api.workflow_run.exited",
  "timestamp": "2000-01-01T00:00:00Z",
  "data": {
    "workflow_id": "whitebox-assessment",
    "workflow_run_id": "TWR..."
  }
}
```

Use `data.workflow_run_id` to identify the workflow run and retrieve its results from the `/o/{org_id}/workflows/{workflow_id}/describe` endpoint.

## Specifying Webhook Endpoints

In the workflow dispatch request body (`/o/{org_id}/workflows/{workflow_id}/dispatch`), specify one or more endpoint IDs in `notification.webhook_endpoint_ids` to receive a notification when that workflow completes.

```js
{
  "input": { /* ... */ },
  "notification": {
    "webhook_endpoint_ids": ["WH..."]
  }
}
```

## Webhook Specifications

When an event occurs, an HTTP POST request is sent to the specified webhook endpoint.

The request body has the following structure:

```js
{
  "type": "{event_type}",
  "timestamp": "2024-01-01T00:00:00Z",
  "data": 
}
```

The webhook endpoint must return an HTTP **2xx** status code **within 10 seconds** to acknowledge successful receipt. Responses with 3xx status codes are treated as failures; redirects are not followed.

If the request fails (non-2xx response, timeout, or network error), the service automatically retries delivery.

Webhook delivery is **at-least-once**, meaning the same event may be delivered more than once. Each request includes a `webhook-id` header; requests with the same `webhook-id` are redeliveries of the same event. We recommend implementing your endpoint idempotently using the `webhook-id`.

### Verifying Signatures

Always verify the signature of incoming requests to confirm they were sent by this service.
The service uses a signing scheme compliant with the [Standard Webhooks](https://www.standardwebhooks.com/) specification.

Here is an example implementation in TypeScript:

```typescript
import { Webhook } from "standardwebhooks";

const wh = new Webhook(signingSecret);

// Verify the signature using the request headers and body
wh.verify(requestBody, {
  "webhook-id": req.headers.get("webhook-id"),
  "webhook-timestamp": req.headers.get("webhook-timestamp"),
  "webhook-signature": req.headers.get("webhook-signature"),
});

const payload = JSON.parse(requestBody);
```

## Setting Up Webhook Endpoints {#setup-endpoints}

### Register a Webhook Endpoint

Go to [Settings > Webhook Endpoints](https://cloud.shisho.dev/*/settings/webhooks) and click **"Register a new webhook endpoint"** to enter the destination URL and a description.

Once registered, the **endpoint ID** (`WH...` format) and **signing secret** are displayed.

:::warning
The signing secret is only shown on this screen. Be sure to copy and store it securely before closing this page.
If you lose it, you can reissue one via "Rotate signing secret."
:::

### Send a Test Message {#send-test-message}

Once your receiving server is running, verify that webhooks are delivered correctly before running a workflow.
In [Settings > Webhook Endpoints](https://cloud.shisho.dev/*/settings/webhooks), click the `...` menu on the endpoint row and select **"Send test message"** to send a test payload.

If your server receives the request and returns HTTP 2xx, you're all set.

## Rotating the Signing Secret {#rotate-secret}

To regenerate the secret, click the `...` menu on the endpoint row and select **"Rotate signing secret"**.

For 24 hours after rotation, the service signs webhook requests with both the old and new secrets, including multiple signatures in the request per the [Standard Webhooks specification](https://www.standardwebhooks.com/). This means both servers using the old secret and servers using the new secret will accept webhook notifications from the service during this period. As long as you update your receiving server's configuration within 24 hours, you can rotate the secret without any interruption in webhook delivery.

Here is an example procedure:

1. Perform the rotation and obtain the new signing secret
2. Update the environment variables or configuration files on your receiving server with the new secret and restart the server
3. Verify with a [test message](#send-test-message)
4. (After 24 hours, webhook requests will only be signed with the new secret)
