API
サービス、CLI、エージェントから通知を送り、人の応答を受け取る API です。
ベース URL: https://api.nodd.blipdrop.net
認証
Authorization: Bearer <キー> を付けます。
| 送信キー | GET /v1/actions/events 以外のエンドポイントで使います |
|---|---|
| 読み取りキー | GET /v1/actions/events だけで使います |
| 返信トークン | GET /v1/messages/{id} で、その 1 通だけ読めます |
エラーは RFC 9457 の application/problem+json で返します。一覧はエラーコードをご覧ください。
回数の上限
| キーごと | 10 秒に 10 回。超えると 429 rate_limited |
|---|---|
| 1 通の状態の取得 | 10 秒に 10 回 |
| チャンネルごと | 1 分に 60 回。超えると 5 分止まり 403 channel_paused |
| 本文の大きさ | 16 KB。POST /v1/messages は 64 KB、受信 URL は 256 KB |
| 月の上限 | 無料 1,000 通、Team 1 人あたり 5 万配信。high だけ 10% 超えて送れます |
| 同時の応答待ち | 無料 3 件、Team 500 件 |
POST /v1/messages の応答の RateLimit-Remaining は、現在の枠の残りです。
POST /v1/messages
通知を送ります。受け付けた時点で 202 を返します。端末への到達は保証しません。知らない項目は拒否します。
kind | 必須。notice、progress、alert、approval、choice |
|---|---|
title | 必須。1 から 120 文字 |
body | 1,000 文字まで。format が markdown なら 4,000 文字まで |
level | low、normal(既定)、high。iOS の Passive、Active、Time Sensitive に対応します |
fields | 6 件まで。label 24 文字、value 80 文字 |
links | 2 件まで。label 24 文字、url は https で 512 文字 |
options | choice だけ。2 から 4 個。id 32 文字、label 16 文字、style は default、primary、destructive |
confirm | 応答に Face ID を求めます。approval の既定は true、choice の既定は false |
expires_in | 応答期限までの秒数。60 から 2,592,000。プランの受け取り期限(無料 86,400 秒)を超えられません。応答が必要な種類で省略すると受け取り期限になります |
on_timeout | reject(既定)か ignore。action.expired イベントにそのまま返す値です |
format | plain(既定)か markdown。markdown は見出し、箇条書き、引用、コード、強調、リンクをアプリで整形し、本文を 4,000 文字まで書けます。HTML、画像、表は整形しません。通知の本文では記号を外します |
image | data(JPEG か PNG の Base64。40 KB まで)と alt(120 文字まで)。本文と同じように暗号化して届け、受信後にサーバーから消します。progress では使えません |
input | prompt(40 文字まで)と required。1 人で答える approval と choice に入力欄を出し、200 文字までの文を response.note で返します。指定がなければ、却下の理由以外の文は送れません |
secret | public_key(Base64 の 32 バイトの X25519 公開鍵)。approval に伏せた入力欄を出します。値は端末がこの鍵で暗号化し、GET /v1/messages/{id}/secret で受け取ります。input、dedupe_key、confirm: false、2 人以上の承認とは併用できません |
approvals_required | approval が確定するまでの人数。1 から 3。2 人以上は Team だけです。同じ人は 1 人として数え、1 人でも却下すると確定します |
escalate_after | この秒数のあいだ応答がなければ、別の担当へ知らせます。60 から 2,592,000。応答期限より短くします。Team だけです |
escalate_to | 引き継ぎの宛先。形は to と同じです。省略すると Manager と Responder です。escalate_after が必要です |
alert_key | 128 文字まで。使える文字は英数字と . _ : -。解消に使います |
dedupe_key | 128 文字まで。未解決の同じキーを 1 件にまとめ、回数を数えます。まとめた分は上限に数えません |
progress | kind: progress で必須。current、total(1 以上)、label(40 文字)、state(running、succeeded、failed) |
to | members(20 件まで)と roles(manager、responder)。全員に届く点は変わらず、宛先の人にだけ対応タブの件数が増えます |
sensitive | ロック画面に本文を出しません |
delivery | immediate(既定)か digest。digest は 1 時間ごとのまとめ通知で、low だけ指定できます |
metadata | 文字列の組。1 KB まで。応答イベントにそのまま返します。端末ごとの暗号化の対象外です |
format、image、input、secret は Nodd 1.1 以降のアプリが対応します。1.0 のアプリは整形も画像の表示もせず、必須の入力と秘密の値には却下でしか答えられません。
Idempotency-Key ヘッダー(128 文字まで)を付けると、24 時間は同じキーに最初の結果を返します。再送しても二重に届きません。
応答の項目です。
id | 通知の ID。msg_ で始まります |
|---|---|
status | queued |
reply_token | この 1 通の状態だけを読めるトークン |
sent_at | 受け付けた時刻 |
expires_at | 応答期限。応答が必要な種類か、expires_in を指定したときに付きます |
deduped | dedupe_key で既存の通知にまとめたとき true |
GET /v1/messages/{id}
状態と応答を返します。本文はサーバーに残らないので返しません。応答待ちのあいだは Retry-After: 3 が付きます。待ち受けはサーバーで保持しないので、秒数を空けて取り直します。
id, kind, sent_at, expires_at | 送信時の値 |
|---|---|
source | サーバーが記録する経路。api、cli、github_action、mcp、slack、grafana、alertmanager、generic、datadog、sentry、pagerduty |
action_state | 応答が必要な種類だけに付きます。下の表をご覧ください |
response | 確定した応答。option_id、actor、assurance(none、biometric)、responded_at、note、secret_digest、signature |
approvals, approvals_required | 確定より前に集まった承認と、必要な人数 |
delivery | confirmed、delayed、unconfirmed、failed の推定の件数。unconfirmed は届いていないという意味ではありません |
resolved_at | アラートが解消された時刻 |
action_state の値
open | 応答待ち |
|---|---|
claimed | 応答が確定した |
delivered | 確定した応答を callback の URL へ届けた |
done | 送信元が結果を報告した |
expired | 応答期限と受付猶予(10 分)を過ぎた |
cancelled | 送信元が取り下げた |
failed | 受け付けの処理に失敗したか、応答を callback へ 24 時間届けられなかった。後者では response が残ります |
GET, DELETE /v1/messages/{id}/secret
secret への回答を暗号文のまま返します。形は {"sealed": "…"} で、中身は base64(enc || ciphertext) です。承認された後に読めます。受け取ったら DELETE で消してください。消さなくても 10 分で消えます。
暗号は HPKE(DHKEM X25519 / HKDF-SHA256 / ChaCha20-Poly1305)で、info は nod-secret-v1、追加データは通知の ID です。値は response、イベント、callback には入りません。response.secret_digest は暗号文の Base64 文字列の SHA-256 で、署名の対象です。
公開鍵はサーバーを通るので、サーバーそのものが乗っ取られた場合の保護にはなりません。
PATCH /v1/messages/{id}
kind: progress の通知を更新します。title か progress が必要です。本文と同じく暗号化して端末へ届け、サーバーには残しません。running の更新は通知を鳴らさず、succeeded と failed は通知します。その後の更新は 409 invalid_state です。受け付けると 202 を返します。
POST /v1/messages/{id}/cancel
応答前の承認や選択を取り下げます。成功すると 204 です。押された後は 409 already_claimed を返します。
POST /v1/messages/{id}/result
受け取った応答を処理した結果を報告します。カードが完了に変わり、action_state は done になります。成功すると 204 です。
status | 必須。succeeded か failed |
|---|---|
summary | 200 文字まで。暗号化して端末へ届けます |
POST /v1/alerts/{alert_key}/resolve
同じ alert_key の未解消のアラートを閉じ、全員の対応タブから外します。対象がなくても 202 を返します。本文の note(200 文字まで)は省略できます。
POST /v1/heartbeats/{name}
定期ジョブの生存を報告します。name は alert_key と同じ形式です。interval と grace の秒数のうちに次の報告がなければ、チャンネルへ high で知らせます。途絶えた後に報告が届くと再開を知らせます。報告は送信数に数えません。チャンネルごとに 20 件までです。
interval | 必須。60 から 2,678,400 秒 |
|---|---|
grace | 0 から 2,678,400 秒。省略すると interval の 10% で、60 秒を下回りません |
200 で name と次の期限の due_at を返します。DELETE /v1/heartbeats/{name} は見張りを止め、204 を返します。
GET /v1/actions/events
callback を受けられないサービスのためのイベント API です。読み取りキーを使います。
cursor | 前回の next_cursor |
|---|---|
limit | 1 から 100。既定は 50 |
events と next_cursor を返します。イベントの形は応答の受け取りと署名をご覧ください。書き込み順の入れ替わりで読み飛ばさないよう、発生から 2 秒以内のイベントは次回に返します。Retry-After: 3 を守って取得します。イベントは 7 日で消えます。
GET /v1/meta
認証なしでサービスの状態を返します。mode は normal、degraded、read_only、intake_stopped のいずれかです。ほかに api_version と、ある場合は notice を返します。