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

# 概要

> 通話が終わったときに、結果を指定のURLへ受け取ります。

## 送信先を追加する

管理画面の「設定 → API」の「Webhook」か、[送信先を追加する](https://docs.ai-call.co/webhooks/create.md)で、受け取るURLを登録します。

```bash theme={null}
curl https://api.ai-call.co/webhooks \
  -H "Authorization: Bearer $AICALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/webhooks/ai-call", "events": ["call.ended", "call.failed"]}'
```

応答の `secret`（`whsec_…`）は署名の確認に使います。この応答でだけ返るので、安全な場所に保管してください。

* URLは外部から届く `https://` のみです。
* 送信先は1アカウント5件までです。

## イベント

| type | いつ届くか |
| - | - |
| `call.ended` | 通話が終わったとき（不在・話し中なども含む）。文字起こしが揃うよう、終話の約20秒後に届きます |
| `call.failed` | 発信キューに入った通話が、かける前に失敗したとき |
| `webhook.test` | テスト送信 |

## 届く内容

POST で、次の JSON が届きます。`data` は[通話を取得する](https://docs.ai-call.co/calls/get.md)と同じ形で、文字起こしを含みます。

```json theme={null}
{
  "id": "evt_6730b7e4c0ffee0000000001_call_ended",
  "type": "call.ended",
  "created_at": "2026-11-12T03:00:30.000Z",
  "data": {
    "id": "6730b7e4c0ffee0000000001",
    "direction": "outbound",
    "status": "ended",
    "result": "completed",
    "duration_seconds": 84,
    "to": "+819012345678",
    "agent": { "id": "0123456789abcdef01234567", "name": "営業架電" },
    "metadata": { "crm_id": "A-1024" },
    "cost_yen": 50.4,
    "transcript": [
      { "role": "ai", "text": "お忙しいところ失礼いたします。", "at": "2026-11-12T03:00:01.000Z" },
      { "role": "caller", "text": "はい。", "at": "2026-11-12T03:00:04.000Z" }
    ]
  }
}
```

ヘッダー：

| ヘッダー | 内容 |
| - | - |
| `AICall-Event-Id` | イベントのID（`id` と同じ） |
| `AICall-Event-Type` | イベントの種類 |
| `AICall-Signature` | `t=<UNIX秒>,v1=<署名>` |

## 署名を確かめる

`v1` は、シークレットを鍵にした `"<t>.<受け取った本文そのまま>"` の HMAC-SHA256（16進）です。本文は JSON として解析する前の文字列のまま使ってください。`t` が5分以上ずれているものは受け付けないでください。

```js Node.js theme={null}
import crypto from "node:crypto";

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && parts.v1?.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
```

```python Python theme={null}
import hashlib, hmac, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
    fresh = abs(time.time() - int(parts["t"])) < 300
    return fresh and hmac.compare_digest(parts.get("v1", ""), expected)
```

## 受け取ったら

* 10秒以内に `2xx` を返してください。重い処理は受け取ったあとに別で行ってください。
* `2xx` 以外（タイムアウト・リダイレクトを含む）は、1分・5分・15分・1時間・3時間・6時間・12時間後に送り直します（計8回、約1日）。それでも届かなければ失敗として記録します。
* 同じイベントが二度届くことがあります。`id` で重複を除いてください。届く順番は保証しません。
* 送信の結果は、管理画面の「最近の送信」か[送信記録](https://docs.ai-call.co/webhooks/deliveries.md)で確かめられます（30日間保存）。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.