リファレンス
Webhook
投稿がレビューに回されたとき、承認、公開されたとき、失敗したとき、ファイルの準備ができたとき、SNSアカウントに対応が必要なときに、署名付きのリクエストを自分のサーバーで受け取れます。
エンドポイントを追加
- 1
SPREVAで開発者、Webhookの順に開き、サーバーのアドレスを追加して、通知を受け取るイベントを選びます。アドレスは公開されていて、10秒以内に2xxステータスを返す必要があります。
- 2
エンドポイントのシークレットをコピーします。表示されるのは一度だけで、各リクエストの署名を確認するのに使います。
- 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=の後に署名が続きます。
{
"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で計算した値です。署名が一致しないリクエストはすべて拒否してください。
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が送られます。すでに処理したイベントを無視するのに使ってください。 - 「最近の配信」の配信を再送は、イベントをもう一度送ります。サーバーがまだ失敗する場合は再試行も行われるので、二重に公開することなくエンドポイントを修正できます。