API連携(Webhook)仕様書
温湿度モニターで測定データを受信するたびに、設定したエンドポイントへ自動でPOST送信する機能の仕様です。
1. 概要
1機器(IoT端末)が温湿度モニターへ測定データを送信
2受信直後、設定済みのエンドポイントURLへ、その回で受信した測定データをまとめて1回のHTTP POSTで転送
3受信側は2xxを返せば完了。届かない・失敗した場合は温湿度モニター側が保持し、次回受信時にまとめて再送
設定は「設定」→「API連携」画面(管理者/代理店の場合はユーザー管理画面)から行います。設定はユーザー1人につきURL・署名シークレットを1組だけ持ちます。
2. リクエスト形式
| 項目 | 内容 |
|---|---|
| メソッド | POST |
| URL | 設定したエンドポイントURL(https://のみ。内部ネットワーク宛のURLは設定できません) |
Content-Type | application/json |
X-Timestamp | 送信時刻(UNIX秒・文字列)。リプレイ攻撃対策に使えます |
X-Signature | sha256=<hex> 形式のHMAC-SHA256署名(後述) |
User-Agent | Onshitsudokei-Webhook/1(識別用。ログ確認等の参考情報であり、認証には使えません) |
送信元IP/User-Agentでの許可リストは非対応です。
本サービスは送信元の固定IPを保証していないため、ファイアウォールでのIP許可リストは将来無言で届かなくなるリスクがあります。
リクエストの正当性は署名(X-Signature)で確認してください(検証の実装は任意です)。
3. 署名の検証(任意)
署名の検証は任意です。
検証を実装しなくてもデータの受信自体は動作します(本サービス側は受信側が検証したかどうかを確認しません)。
ただし検証しない場合、受信URLを知った第三者が偽のデータを送信できます。
受信URLは推測されにくい値にしたうえで、署名の検証を強く推奨します。
受信したリクエストが本サービスからの送信であることを確認するため、共有シークレット(設定画面に表示)を使ってHMAC-SHA256署名を検証します。
署名の計算方法
signature = HMAC_SHA256(secret, timestamp + "." + rawRequestBody)
rawRequestBody はリクエストボディの生のJSON文字列(パース前)、timestamp は X-Timestamp ヘッダーの値そのものです。計算結果(16進文字列)が X-Signature ヘッダーの sha256= 以降と一致すれば検証OKです。
Node.js での検証例
const crypto = require("crypto");
function verify(secret, timestamp, rawBody, signatureHeader) {
const expected = crypto.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const given = (signatureHeader || "").replace(/^sha256=/, "");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}
タイムスタンプが現在時刻から大きくずれている(例: 5分以上)場合はリプレイの可能性があるため、受信側で拒否することを推奨します。
4. 送信データ(JSON)の仕様
トップレベル
| フィールド | 型 | 説明 | |
|---|---|---|---|
api_version | number | 必須 | ペイロード構造のバージョン。現在は 1 |
device_id | string | 必須 | 機器の固有ID |
name | string | 必須 | 機器の表示名(ユーザーが設定した名前) |
location | object または null | 任意 | 設置位置。未登録の場合は null |
location.lat | number | 緯度 | |
location.lng | number | 経度 | |
readings | array | 必須 | 測定データの配列(古い順)。1回の送信で複数件になることがあります |
readings[] の各要素
| フィールド | 型 | 単位 | 説明 |
|---|---|---|---|
ts | string (ISO8601) | — | 測定時刻 |
temperature | number または null | ℃ | 気温 |
humidity | number または null | % | 相対湿度 |
battery_voltage | number または null | V | 機器の電池電圧 |
rssi | number または null | dBm | モバイル通信の電波強度 |
dew_point | number | ℃ | 露点(気温・湿度から算出) |
absolute_humidity | number | g/m³ | 絶対湿度(気温・湿度から算出) |
vpd | number | kPa | 飽差 VPD(気温・湿度から算出) |
wbgt_simple | number | ℃ | 暑さ指数の簡易近似値(気温・湿度から算出。日射・風速は考慮していない屋内式の参考値) |
気温・湿度のいずれかが null の場合、dew_point/absolute_humidity/vpd/wbgt_simple は算出できないためフィールド自体が省略されます。
5. サンプルペイロード
{
"api_version": 1,
"device_id": "AABBCCDDEEFF",
"name": "1号ハウス",
"location": { "lat": 35.681236, "lng": 139.767125 },
"readings": [
{
"ts": "2026-08-03T00:00:00.000Z",
"temperature": 24.3,
"humidity": 58.0,
"battery_voltage": 3.6,
"rssi": -70,
"dew_point": 15.6,
"absolute_humidity": 12.7,
"vpd": 1.28,
"wbgt_simple": 21.5
},
{
"ts": "2026-08-03T00:05:00.000Z",
"temperature": 24.8,
"humidity": 59.5,
"battery_voltage": 3.6,
"rssi": -70,
"dew_point": 16.2,
"absolute_humidity": 13.2,
"vpd": 1.27,
"wbgt_simple": 22.0
}
]
}
6. 期待するレスポンス
200〜299(2xx)を返せば受信完了として扱います。それ以外のステータス、またはタイムアウト(8秒)・接続エラーの場合は失敗として扱い、リトライします。レスポンスのボディは読み取りません。
7. リトライ・自動無効化
- 1回の送信で失敗した場合、2秒 → 10秒 → 60秒の間隔で最大3回リトライします
- それでも失敗したデータは「未送信」のまま保持され、次回受信時に新しいデータとまとめて再送されます(データが失われることはありません)
- 連続で20回失敗すると、事故防止のため送信が自動的に無効化されます(設定画面で状態を確認できます)。復旧後は設定画面から再度有効化してください
8. バージョニング
api_version はペイロード構造を変更した場合にのみ更新されます。フィールドの追加のみ(後方互換な変更)では原則バージョンは据え置きます。受信側では未知のフィールドが増えても無視できるように実装してください。