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 文字
body1,000 文字まで。format が markdown なら 4,000 文字まで
levellow、normal(既定)、high。iOS の Passive、Active、Time Sensitive に対応します
fields6 件まで。label 24 文字、value 80 文字
links2 件まで。label 24 文字、url は https で 512 文字
optionschoice だけ。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_timeoutreject(既定)か ignore。action.expired イベントにそのまま返す値です
formatplain(既定)か markdown。markdown は見出し、箇条書き、引用、コード、強調、リンクをアプリで整形し、本文を 4,000 文字まで書けます。HTML、画像、表は整形しません。通知の本文では記号を外します
imagedata(JPEG か PNG の Base64。40 KB まで)と alt(120 文字まで)。本文と同じように暗号化して届け、受信後にサーバーから消します。progress では使えません
inputprompt(40 文字まで)と required。1 人で答える approval と choice に入力欄を出し、200 文字までの文を response.note で返します。指定がなければ、却下の理由以外の文は送れません
secretpublic_key(Base64 の 32 バイトの X25519 公開鍵)。approval に伏せた入力欄を出します。値は端末がこの鍵で暗号化し、GET /v1/messages/{id}/secret で受け取ります。input、dedupe_key、confirm: false、2 人以上の承認とは併用できません
approvals_requiredapproval が確定するまでの人数。1 から 3。2 人以上は Team だけです。同じ人は 1 人として数え、1 人でも却下すると確定します
escalate_afterこの秒数のあいだ応答がなければ、別の担当へ知らせます。60 から 2,592,000。応答期限より短くします。Team だけです
escalate_to引き継ぎの宛先。形は to と同じです。省略すると Manager と Responder です。escalate_after が必要です
alert_key128 文字まで。使える文字は英数字と . _ : -。解消に使います
dedupe_key128 文字まで。未解決の同じキーを 1 件にまとめ、回数を数えます。まとめた分は上限に数えません
progresskind: progress で必須。current、total(1 以上)、label(40 文字)、state(running、succeeded、failed)
tomembers(20 件まで)と roles(manager、responder)。全員に届く点は変わらず、宛先の人にだけ対応タブの件数が増えます
sensitiveロック画面に本文を出しません
deliveryimmediate(既定)か digest。digest は 1 時間ごとのまとめ通知で、low だけ指定できます
metadata文字列の組。1 KB まで。応答イベントにそのまま返します。端末ごとの暗号化の対象外です

format、image、input、secret は Nodd 1.1 以降のアプリが対応します。1.0 のアプリは整形も画像の表示もせず、必須の入力と秘密の値には却下でしか答えられません。

Idempotency-Key ヘッダー(128 文字まで)を付けると、24 時間は同じキーに最初の結果を返します。再送しても二重に届きません。

応答の項目です。

id通知の ID。msg_ で始まります
statusqueued
reply_tokenこの 1 通の状態だけを読めるトークン
sent_at受け付けた時刻
expires_at応答期限。応答が必要な種類か、expires_in を指定したときに付きます
dedupeddedupe_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確定より前に集まった承認と、必要な人数
deliveryconfirmed、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
summary200 文字まで。暗号化して端末へ届けます

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 秒
grace0 から 2,678,400 秒。省略すると interval の 10% で、60 秒を下回りません

200 で name と次の期限の due_at を返します。DELETE /v1/heartbeats/{name} は見張りを止め、204 を返します。

GET /v1/actions/events

callback を受けられないサービスのためのイベント API です。読み取りキーを使います。

cursor前回の next_cursor
limit1 から 100。既定は 50

events と next_cursor を返します。イベントの形は応答の受け取りと署名をご覧ください。書き込み順の入れ替わりで読み飛ばさないよう、発生から 2 秒以内のイベントは次回に返します。Retry-After: 3 を守って取得します。イベントは 7 日で消えます。

GET /v1/meta

認証なしでサービスの状態を返します。mode は normal、degraded、read_only、intake_stopped のいずれかです。ほかに api_version と、ある場合は notice を返します。