API連携(Webhook)仕様書

温湿度モニターで測定データを受信するたびに、設定したエンドポイントへ自動でPOST送信する機能の仕様です。

1. 概要

1機器(IoT端末)が温湿度モニターへ測定データを送信
2受信直後、設定済みのエンドポイントURLへ、その回で受信した測定データをまとめて1回のHTTP POSTで転送
3受信側は2xxを返せば完了。届かない・失敗した場合は温湿度モニター側が保持し、次回受信時にまとめて再送

設定は「設定」→「API連携」画面(管理者/代理店の場合はユーザー管理画面)から行います。設定はユーザー1人につきURL・署名シークレットを1組だけ持ちます。

2. リクエスト形式

項目内容
メソッドPOST
URL設定したエンドポイントURL(https://のみ。内部ネットワーク宛のURLは設定できません)
Content-Typeapplication/json
X-Timestamp送信時刻(UNIX秒・文字列)。リプレイ攻撃対策に使えます
X-Signaturesha256=<hex> 形式のHMAC-SHA256署名(後述)
User-AgentOnshitsudokei-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_versionnumber必須ペイロード構造のバージョン。現在は 1
device_idstring必須機器の固有ID
namestring必須機器の表示名(ユーザーが設定した名前)
locationobject または null任意設置位置。未登録の場合は null
location.latnumber緯度
location.lngnumber経度
readingsarray必須測定データの配列(古い順)。1回の送信で複数件になることがあります

readings[] の各要素

フィールド型単位説明
tsstring (ISO8601)—測定時刻
temperaturenumber または null℃気温
humiditynumber または null%相対湿度
battery_voltagenumber または nullV機器の電池電圧
rssinumber または nulldBmモバイル通信の電波強度
dew_pointnumber℃露点(気温・湿度から算出)
absolute_humiditynumberg/m³絶対湿度(気温・湿度から算出)
vpdnumberkPa飽差 VPD(気温・湿度から算出)
wbgt_simplenumber℃暑さ指数の簡易近似値(気温・湿度から算出。日射・風速は考慮していない屋内式の参考値)

気温・湿度のいずれかが 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. リトライ・自動無効化

8. バージョニング

api_version はペイロード構造を変更した場合にのみ更新されます。フィールドの追加のみ(後方互換な変更)では原則バージョンは据え置きます。受信側では未知のフィールドが増えても無視できるように実装してください。