メインコンテンツまでスキップ

プッシュ候補

非同期 API を通じて、ユーザーごとにパーソナライズされたプッシュ通知候補を生成します。

概要

  1. POST /v1/push-candidates でジョブを送信します。
  2. API が候補を非同期で処理し、job_id を返します。
  3. GET /v1/push-candidates/{job_id} でステータスをポーリングするか、完了時に Webhook を受信します。
  4. 署名付き URL から JSONL 結果ファイルをダウンロードします。

ジョブの作成

curl -X POST "https://api.feed.storyhub.studio/v1/push-candidates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scenario": "push_morning",
"candidates_per_user": 3
}'

candidates_per_user は 1 ユーザーあたりに生成される候補記事数です(デフォルト: 1、最大: 3)。

レスポンス:

{
"job_id": "job-uuid",
"status": "queued"
}

ジョブステータスの確認

GET /v1/push-candidates/{job_id}
ステータス意味
queuedジョブはキューに入っています
processingジョブは実行中です
completed結果の準備が完了しました — download_url が提供されます
failedジョブが失敗しました — error フィールドを確認してください

完了すると、レスポンスに download_url(署名付き URL、有効期限 1 時間)が含まれます。

ステータスレスポンスの主要フィールド

フィールド出現条件説明
target_user_countinteger | nullオーディエンス解決後ジョブの対象ユーザー数。queued や解決前の processing / failed では未設定(null またはフィールド省略)。condition モードで合致 0 人の場合は 0null と区別されます)。
failed_user_countinteger | nullstatus=completed のみ確定値対象ユーザーのうち候補生成がエラーで失敗したユーザー件数。queued / processing / failed では未設定。0 人完了時も 0null と区別されます。
candidates_generatedinteger | nullstatus=completed のみ確定値全ユーザー合算の生成候補数。queued / processing / failed では未設定(null またはフィールド省略)— ここで「候補生成に到達しなかった」ことを 0(合致ユーザーなしで完了)と区別できます。
consumed_creditsnumber常に存在(完了前は 0)確定したクレジット消費量。
filter_statsobject | nulltarget_mode=condition 完了時オーディエンスフィルタの内訳(後述)。target_mode=manual では null
download_urlstring | nullstatus=completedJSONL のダウンロード URL(署名付き、有効期限あり)。

これらのフィールドは Webhook ペイロード(push_job.completed)と同じ値で、GET と Webhook の対称性が保たれます。

完了時のレスポンス例:

{
"job_id": "01HZX9...",
"status": "completed",
"progress": 100,
"target_user_count": 1234,
"failed_user_count": 3,
"candidates_generated": 3702,
"consumed_credits": 12.34,
"download_url": "https://storage.googleapis.com/...",
"download_url_expires_at": "2026-04-27T10:00:00Z",
"filter_stats": {
"total_audience": 5000,
"excluded_due_to_null_last_active": 200,
"excluded_due_to_last_active_days": 3500,
"excluded_due_to_registered_range": 66
},
"error": null
}
対象0人で完了する場合

target_mode=condition で条件解決の結果、対象ユーザーが 0 人になった場合も、ジョブは completed で完了します(failed にはなりません)。

  • status=completedtarget_user_count=0failed_user_count=0candidates_generated=0consumed_credits=0
  • 予約クレジットは解放されます(消費は 0)
  • 空の JSONL(0 行)に対する download_url が発行されます
  • 通常通り push_job.completed の Webhook が送信されます

filter_stats を確認することで、なぜ対象が 0 人になったか(last_active_days 除外など)を把握できます。

ダウンロード URL の使い方

download_url は認証情報が URL のクエリパラメーターに含まれた署名付き URL です。追加の認証ヘッダーは不要で、そのまま HTTP GET でダウンロードできます。

curl -o candidates.jsonl "DOWNLOAD_URL_FROM_RESPONSE"

有効期限が切れた場合は、GET /v1/push-candidates/{job_id} を再度呼び出すと新しい URL が発行されます。

結果フォーマット(JSONL)

ダウンロードしたファイルの各行は JSON オブジェクトです。candidates 配列はスコア降順(先頭が最もスコアの高い記事)で並びます:

{"user_id": "user-123", "candidates": [{"id": "content-uuid", "title": "...", "url": "...", "thumbnail": {"url": "...", "width": 1024, "height": 512}, "source": {"name": "..."}, "published_at": "2025-01-15T08:00:00Z", "score": 0.95, "tracking_token": "eyJ..."}]}

プッシュクリックのトラッキング

プッシュ記事のクリックを報告する際は、JSONL 出力の tracking_token を含めてください:

POST /v1/events
{
"events": [
{
"type": "click",
"session_id": "...",
"tracking_token": "eyJ... (from push candidates JSONL)",
"occurred_at": "..."
}
]
}

プッシュクリックをトラッキングするメリット:

  • プッシュ経由でクリックされた記事は、以降のフィードリクエストから除外されます(重複排除)。
  • クリックシグナルにより、将来のレコメンデーションが改善されます。
  • アナリティクスでプッシュ通知のエンゲージメントを測定できます。
tracking_token について

tracking_token はフィード取得(GET /v1/feed)と Push 候補ファイル(JSONL)に含まれます。一方、GET /v1/contents/{content_id}(単体取得)にはランキング文脈がないため、tracking_token は含まれません。

Webhooks

テナントに webhook_url が設定されている場合、ジョブ完了時に通知が送信されます:

  • completed または failed ステータス時に配信されます。
  • 検証用の X-StoryHub-Signature ヘッダー(HMAC-SHA256)が含まれます。
  • ベストエフォート配信で、最大 3 回リトライされます。

Webhook ペイロード

{
"event": "push_job.completed",
"job_id": "...",
"tenant_id": "...",
"scenario_id": "...",
"status": "completed",
"target_user_count": 1234,
"failed_user_count": 3,
"candidates_generated": 3702,
"consumed_credits": 12.34,
"download_url": "https://...",
"download_url_expires_at": "...",
"filter_stats": {
"total_audience": 5000,
"excluded_due_to_null_last_active": 200,
"excluded_due_to_last_active_days": 3500,
"excluded_due_to_registered_range": 66
},
"completed_at": "..."
}

filter_stats(target_mode=condition のみ)

target_mode=condition の場合、filter_stats でフィルタの内訳を確認できます。各カウンタは独立しており、複数の条件で除外されたユーザーはそれぞれのカウンタに重複してカウントされます。

フィールド説明
total_audienceテナントの総オーディエンス数(フィルタ前)
excluded_due_to_null_last_activelast_active_days が指定されているが last_active_at が NULL のため除外された数
excluded_due_to_last_active_dayslast_active_at が cutoff(now − last_active_days)より古いため除外された数
excluded_due_to_registered_rangeregistered_from / registered_to の範囲外のため除外された数

target_mode=manual の場合、filter_statsnull です。同じ値が GET /v1/push-candidates/{job_id} のレスポンスにも含まれます。

target_user_count / failed_user_count / candidates_generated も Webhook と GET レスポンスの両方で公開されており、両系統での集計を一致させることができます。failed_user_count は候補生成がエラーで失敗したユーザー数を表します(成功して候補 0 件の場合は失敗扱いになりません)。

制約

制限
テナントあたりの最大同時実行ジョブ数5
実行時間(10 万ユーザー)10 分未満
ダウンロード URL の有効期限1 時間
リクエストボディサイズ8 MiB
user_ids の最大件数(manual モード)100,000 件
1 件あたりの user_id の長さ128 文字以下
専用レート制限1 RPS / burst 5

user_ids 件数や本文サイズが上限を超える場合のレスポンス:

  • 件数超過 → 400 Validation (user_ids: must not exceed 100000 entries)
  • ボディサイズ超過 → 413 Payload Too Large

1 件あたりの user_id が長い場合(例えば 128 文字に近い長さ)、件数上限に達する前にボディサイズ上限 8 MiB に当たる可能性があります。100,000 件を超えるユーザーへ配信したい場合は、リクエストを複数バッチに分割するか、target_mode=condition の活用を検討してください。

condition モード(推奨)

ユーザー絞り込み条件で対象を選びます。

POST /v1/push-candidates
{
"scenario": "push_morning",
"target_mode": "condition",
"conditions": { "last_active_days": 7 }
}
条件説明
last_active_days指定日数以内に session_start 等のイベントがあったユーザーのみを対象とします。
last_active_days(NULL の挙動)last_active_at が未設定(一度もイベント送信が無い)ユーザーは、本フィルタ適用時は対象外となります。
last_active_days(未指定時)本フィールドを省略するとフィルタは無効化され、活動記録の無いユーザーも含めて全員が対象となります。
registered_from / registered_toregistered_atPUT /v1/users で送信した値、または初回イベント時刻)の範囲で絞り込みます。
休眠ユーザーへの配信

復帰促進など、まだ一度もアクセスしていないユーザーを含めたい場合は、last_active_days省略してください。条件を省略すると「絞り込みなし=全ユーザー」となります。

テスト用: manual モード

特定のユーザーを指定して候補を生成できます。開発・テスト時に便利です。

POST /v1/push-candidates
{
"scenario": "YOUR_PUSH_SCENARIO",
"target_mode": "manual",
"user_ids": ["user-12345", "user-67890"]
}

user_ids の各エントリは、/v1/eventsuser_id と同じ文字種ルール(A-Za-z0-9._:@|+=-、最大 128 文字)に従う必要があります。違反すると 400 Validation を返します。

クレジット

プッシュ候補の生成は、候補が生成されたユーザーごとにクレジットを消費します。詳細は クレジット使用量 をご覧ください。

候補生成に失敗したユーザー(JSONL 上で candidates が空配列となる行、Webhook ペイロードの failed_user_count に集計される行)はクレジット消費の対象外です。確定消費量は consumed_credits フィールドおよび Webhook ペイロードで確認できます。