本文へスキップ

リファレンス

Webhook

投稿がレビューに回されたとき、承認、公開されたとき、失敗したとき、ファイルの準備ができたとき、SNSアカウントに対応が必要なときに、署名付きのリクエストを自分のサーバーで受け取れます。

エンドポイントを追加

  1. 1

    SPREVAで開発者、Webhookの順に開き、サーバーのアドレスを追加して、通知を受け取るイベントを選びます。アドレスは公開されていて、10秒以内に2xxステータスを返す必要があります。

  2. 2

    エンドポイントのシークレットをコピーします。表示されるのは一度だけで、各リクエストの署名を確認するのに使います。

  3. 3

    テストを送信を使います。本物と同じように署名されたwebhook.testイベントが1件送られ、最近の配信にサーバーが返したステータスとかかった時間が表示されます。

エンドポイントは、webhooks:writeを持つキーを使ってREST APIから追加することもできます。

各リクエストの内容

JSONボディと4つのヘッダーを持つPOSTです。

  • x-spreva-event:target.publishedなどのイベント。
  • x-spreva-event-id:ボディのidと同じ値で、再試行や再送でも変わりません。
  • x-spreva-timestamp:リクエストに署名した時刻(Unix秒)。
  • x-spreva-signature:v1=の後に署名が続きます。
JSON
{
  "id": "7f3c2d10-0000-4000-8000-000000000000",
  "type": "target.published",
  "createdAt": "2026-10-01T09:00:02.412Z",
  "workspaceId": "0b9f6c1e-0000-4000-8000-000000000001",
  "data": {
    "type": "TargetPublished",
    "workspaceId": "0b9f6c1e-0000-4000-8000-000000000001",
    "postId": "5d2a7c3e-0000-4000-8000-000000000002",
    "targetId": "9a1f4b7d-0000-4000-8000-000000000003",
    "provider": "instagram",
    "remoteId": "17900000000000000",
    "remoteUrl": "https://www.instagram.com/p/EXAMPLE/"
  }
}

dataはイベント本体で、data.typeはSPREVA内でのイベント名です。dataに含まれるIDを使って、REST APIからオブジェクト全体を取得してください。

イベント

エンドポイントは、選んだイベントを受け取ります。テストを送信は、どのイベントを選んでいても届きます。

投稿

post.created
投稿が作成された
post.review_requested
投稿がレビューに回された
post.approved
投稿が承認され、公開日時が決まった
post.changes_requested
レビュアーがメモを付けて投稿を差し戻した
post.scheduled
投稿の日時が設定された
post.published
投稿がすべてのアカウントで公開された
post.partial
投稿の結果がアカウントによって分かれた
post.failed
投稿がすべてのアカウントで失敗した

公開(アカウントごとに1件)

target.published
1つのアカウントで投稿が公開された
target.failed
1つのアカウントで公開できなかった
target.awaiting_user
アカウントのアプリで公開を仕上げる必要がある

メディア

media.ready
アップロードしたファイルが使えるようになった
media.failed
ファイルを処理または生成できなかった

SNSアカウント

connection.expired
SNSアカウントの再連携が必要になった
connection.revoked
SNSアカウントで権限が取り消された

分析

analytics.updated
公開済みの投稿に新しい数値が届いた

署名を確認

署名は、タイムスタンプ、ドット、生のボディをつなげたものを、エンドポイントのシークレットをキーとしてHMAC-SHA256で計算した値です。署名が一致しないリクエストはすべて拒否してください。

JavaScript
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody: the request body as a string, before any JSON parsing
export function isFromSpreva(rawBody, headers, secret) {
  const signed = headers["x-spreva-timestamp"] + "." + rawBody;
  const expected = Buffer.from("v1=" + createHmac("sha256", secret).update(signed).digest("hex"));
  const received = Buffer.from(headers["x-spreva-signature"] ?? "");
  return received.length === expected.length && timingSafeEqual(received, expected);
}
JSONとして解析する前に、届いたままのボディで確認してください。解析してから書き出し直すとバイト列が変わり、署名が一致しなくなります。

再試行と再送

  • 10秒以内に2xxステータスを返してください。それ以外の応答や応答がない場合は、30秒後、2分後、10分後、1時間後、6時間後の最大5回まで再試行されます。
  • リダイレクトはたどらないので、エンドポイントの最終的なアドレスを使ってください。
  • 再試行と再送では同じx-spreva-event-idが送られます。すでに処理したイベントを無視するのに使ってください。
  • 「最近の配信」の配信を再送は、イベントをもう一度送ります。サーバーがまだ失敗する場合は再試行も行われるので、二重に公開することなくエンドポイントを修正できます。