Stepeee Stepeee AI全自動プラットフォーム

接続方法

1

APIキーを確認する

右上のメニュー > 設定 > アカウント > APIキー から確認できます。

2

リクエストヘッダーに付与する

発行したAPIキーを Authorization ヘッダーに Bearer 形式で付与します。

3

ベースURLにリクエストする

以下のベースURLにエンドポイントのパスを続けてリクエストします。

APIキーはアカウントごとに1本です。キーを変更すると古いキーはすぐに使えなくなります。キーは第三者に知られないように管理してください。

ベースURL

https://stepeee.com/public-api/v1

リクエスト例

curl "https://stepeee.com/public-api/v1/projects" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

レスポンス形式・エラー

すべてのレスポンスは以下の封筒形式で返されます。

成功時

{ "data": ... }

エラー時

{ "error": { "code": "...", "message": "...", "details": { ... } } }

ステータスコード

ステータス意味
401APIキーが無い・不正・失効しています
403この操作の権限がありません(Pro プラン以上が必要な操作を Pro プラン未満のアカウントのAPIキーで呼んだ場合、チームのスタッフがチームのトークン利用履歴を取得した場合など)
404リソースが存在しません(アクセス権限がない場合も含みます)
405このパスでは使えない HTTP メソッドです
409いまの状態ではこの操作ができません(自動化が動いているコンテンツの削除、同じ Idempotency-Key のリクエストを処理中など)。理由は error.code で判定してください
422パラメータが不正、または受け付けられない内容です。validation_error のときは error.details にパラメータごとの理由が入ります
429レート制限を超過しました
500予期しないエラーが発生しました
503処理を開始できませんでした(自動化の実行の開始に失敗した場合など)。時間をおいてやり直してください

共通仕様

取得・操作できる範囲

APIキーの持ち主が画面で見られるものと同じ範囲を取得・操作できます。自分のプロジェクトに加え、Teamプランではチームのオーナー・管理者はチームのすべてのプロジェクト、スタッフは権限を付与されたプロジェクトを取得・操作できます。範囲外のリソースは存在しない場合と同じく404になります。

削除したデータ

削除したプロジェクト・コンセプト・タイトル・コンテンツ・素材は、完全に消えるまでの期間も含めて返しません。タイトルやコンセプトを削除した場合、その下のコンテンツも返しません。

ページング

一覧は page(1から)と per_page(1〜100、既定20)で取得する範囲を指定します。meta に総件数(total)・現在のページ(current_page)・1ページの件数(per_page)・最後のページ(last_page)が入ります。

日時

レスポンスの日時はすべて UTC の ISO 8601 形式(例: 2026-10-21T09:30:00Z)です。パラメータの from / to は、日付(2026-10-21)・日時(2026-10-21T09:30:00)・時差つきの日時(2026-10-21T18:30:00+09:00)を受け付け、時差の無いものは UTC として扱います。from はその時刻を含み、to に日付だけを指定した場合はその日の終わり(23:59:59)までを含みます。

ID

リソースは project_unique・variation_unique のような英数字の公開IDで指定します。IDは変わりません。

ファイルのURL

画像・動画・音声のURLは {url, expires_at} の形で返します。非公開のファイルは署名付きURLで、expires_at(発行から1時間)を過ぎると使えません。続けて使う場合は期限内にダウンロードして保存するか、APIを呼び直して新しいURLを取得してください。公開設定のファイルは期限の無いURLで、expires_at は null です。

値の種類

status や platform のような値は、このページに書いた英小文字の文字列で返します。今後の機能追加で値が増えることがあるため、知らない値を受け取っても処理が止まらないように実装してください。

金額

金額は通貨の最小単位の整数です(USD はセント、JPY は円)。通貨は currency に ISO 4217 の小文字(usd、jpy など)で入ります。

書き込み(Pro プラン)

GET 以外のメソッドで、タイトルの追加・コンテンツの削除・自動化の開始・投稿の承認・Webhook の登録などの操作ができます。操作は画面で同じ操作をしたときと同じ処理で、同じ規則が適用されます。書き込みは APIキーの持ち主が Pro プラン以上のときだけ使え、Pro プラン未満では403 plan_required になります。チームのメンバーは、チームのオーナーが Team プランでなくなると403 team_plan_lost になります。ただし、自動化の停止・Webhook の一覧と削除・投稿の確認の一覧はプランに関係なく使えます(プランを変えたあとも、動いている自動化や通知を止められます)。作成したときは201、それ以外は200を返します。

Idempotency-Key

通信が切れて応答を受け取れなかったときに同じ操作を安全にやり直せるよう、一部の書き込みは Idempotency-Key ヘッダーを受け付けます(受け付けるエンドポイントはパラメータの表に載せています。自動化の開始では必須です)。値には操作ごとに作った一意な文字列(UUID など。1〜255文字の表示可能な ASCII)を使ってください。同じキーで同じ内容(メソッド・パス・本文)を再送すると、操作をやり直さずに最初の応答をそのまま返し、Idempotent-Replayed: true ヘッダーを付けます。キーは APIキーの持ち主ごとに24時間有効です。同じキーで別の内容を送ると422 idempotency_key_reused、最初のリクエストがまだ処理中なら409 idempotency_request_in_progress になります。5xx の応答は保存しないので、同じキーでやり直せます。必須のエンドポイントでヘッダーが無いと422 idempotency_key_required、形式が正しくないと422 idempotency_key_invalid になります。

レート制限

APIキーごとに1分あたり120リクエストまでです(書き込みには、これに加えて下の書き込みのレート制限があります)。レスポンスヘッダーの X-RateLimit-Limit(上限)と X-RateLimit-Remaining(残り)で確認できます。超えると429が返り、Retry-After に再試行できるまでの秒数が入ります。

書き込みのレート制限

書き込み(GET 以外のメソッド)は、1分あたり120リクエストの枠に加えて、APIキーごとに1分あたり30リクエストまでです。超えると429 rate_limited が返り、Retry-After に再試行できるまでの秒数が入ります。書き込みのレスポンスヘッダーの X-RateLimit-Limit と X-RateLimit-Remaining は、2つの枠のうち残りが少ないほうの値です。

エラーコード

エラー時は error.code にエラーの種類、error.message に英語の説明が入ります。どのエンドポイントでも返りうるコードは次のとおりです。エンドポイントに固有のコード(title_limit_reached など)は、各エンドポイントのエラーの表に載せています。プログラムでは error.code で判定してください。

コード意味
unauthorizedAPIキーが無い・不正・失効している(401)
forbidden権限が無い(403)
plan_requiredPro プラン以上が必要な操作(403)
team_plan_lostチームのオーナーが Team プランでなくなったため、チームのメンバーは書き込みできない(403)
not_foundリソースが無い、または取得できる範囲外(404)
method_not_allowedこのパスでは使えない HTTP メソッド(405)
conflictいまの状態ではこの操作ができない(409)
idempotency_request_in_progress同じ Idempotency-Key のリクエストがまだ処理中(409)
validation_errorパラメータが不正(422)
idempotency_key_requiredIdempotency-Key ヘッダーが必須のエンドポイントで、ヘッダーが無い(422)
idempotency_key_invalidIdempotency-Key が1〜255文字の表示可能な ASCII ではない(422)
idempotency_key_reused同じ Idempotency-Key を別の内容のリクエストに使った(422)
rate_limitedレート制限を超えた(429)
internal_error予期しないエラー(500)

422 の例

{
  "error": {
    "code": "validation_error",
    "message": "The per page field must not be greater than 100.",
    "details": {
      "per_page": ["The per page field must not be greater than 100."]
    }
  }
}

アカウント

APIキーの持ち主のアカウント情報です。プラン・トークン残高・使用量・ストレージ・支払い・紹介プログラムの状況を取得できます。

GET › /me

アカウント情報

APIキーの持ち主のプロフィール・プラン・プランごとの上限・所属チームを取得します。

レスポンス項目
項目型説明
user_unique string ユーザーのID
nickname string | null ニックネーム
email string ログインに使うメールアドレス
plan string プラン。free / vault / plus / pro / team
limits object 今のプランの上限。null は無制限
limits.projects integer | null 作れるプロジェクト数
limits.moviemode_variations_per_title integer | null 動画タイトル1件あたりのコンテンツ数
limits.blogmode_variations_per_title integer | null ブログタイトル1件あたりのコンテンツ数
limits.carouselmode_variations_per_title integer | null カルーセルタイトル1件あたりのコンテンツ数
limits.postmode_variations_per_concept integer | null 投稿コンセプト1件あたりのコンテンツ数
limits.team boolean チーム機能を使えるか
limits.script_duration_max integer 動画の台本の最大の長さ(秒)
limits.reading_time_max integer ブログ記事の最大の読了時間(分)
limits.reading_time_max_fulltext integer ブログ記事を全文読み上げる場合の最大の読了時間(分)
limits.slide_count_max integer カルーセルの最大スライド枚数
limits.cta_enabled boolean CTA(行動を促す最後のスライドなど)を使えるか
limits.thread_enabled boolean 投稿でスレッドと画像つき投稿を使えるか
limits.schedule_title_variation_max integer 予約作成で1回に指定できるタイトルとコンテンツの数
limits.schedule_variation_create_max integer 予約作成で1回に作れるコンテンツ数
language string | null 画面の表示言語
timezone string 設定しているタイムゾーン(IANA 形式。例: Asia/Tokyo)
team object | null 所属しているチーム。Teamプランでない、またはチームに所属していなければ null
team.team_unique string チームのID
team.role string チームでの役割。owner(オーナー)/ admin(管理者)/ staff(スタッフ)
created_at string アカウントの作成日時
リクエスト例
curl "https://stepeee.com/public-api/v1/me" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "user_unique": "aB3dE5gH7j",
    "nickname": "Alice",
    "email": "alice@example.com",
    "plan": "pro",
    "limits": {
      "projects": 3,
      "moviemode_variations_per_title": null,
      "blogmode_variations_per_title": null,
      "carouselmode_variations_per_title": null,
      "postmode_variations_per_concept": null,
      "team": false,
      "script_duration_max": 1800,
      "reading_time_max": 15,
      "reading_time_max_fulltext": 4,
      "slide_count_max": 20,
      "cta_enabled": true,
      "thread_enabled": true,
      "schedule_title_variation_max": 50,
      "schedule_variation_create_max": 5
    },
    "language": "ja",
    "timezone": "Asia/Tokyo",
    "team": null,
    "created_at": "2026-09-01T10:20:30Z"
  }
}
GET › /me/subscription

サブスクリプション

契約中のプランの状態・請求期間・解約予定・予約中のプラン変更を取得します。チームのメンバーは、チームのオーナーの契約内容を返します。

レスポンス項目
項目型説明
plan string プラン。free / vault / plus / pro / team
status string 契約の状態。active(有効)/ past_due(支払いの遅延中)/ trialing(試用中)/ none(有料プランの契約なし)
managed_by_team boolean チームのオーナーの契約で利用しているか。true のとき、期間と解約の項目はオーナーの契約の値です
current_period_start string | null 今の請求期間の開始日時
current_period_end string | null 今の請求期間の終了日時(次回の請求日時)
cancel_at_period_end boolean 今の請求期間の終わりで解約する予定か
cancel_at string | null 解約される日時
canceled_at string | null 解約の手続きをした日時
scheduled_change object | null 予約中のプラン変更(無ければ null)
scheduled_change.plan string 変更後のプラン
scheduled_change.effective_at string | null 変更される日時
リクエスト例
curl "https://stepeee.com/public-api/v1/me/subscription" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/subscription",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/subscription", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/subscription")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/subscription"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/subscription");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "plan": "pro",
    "status": "active",
    "managed_by_team": false,
    "current_period_start": "2026-10-01T00:00:00Z",
    "current_period_end": "2026-11-01T00:00:00Z",
    "cancel_at_period_end": false,
    "cancel_at": null,
    "canceled_at": null,
    "scheduled_change": {
      "plan": "plus",
      "effective_at": "2026-11-01T00:00:00Z"
    }
  }
}
GET › /me/tokens

トークン残高

使えるトークンの残高を取得します。チームでは、チームで共有している残高と、自分に割り当てられた利用枠を返します。

レスポンス項目
項目型説明
balance integer 残高
reserved integer 実行中の処理のために確保されている量
available integer 今使える量(残高から確保中の量を引いた値)
wallet string personal(自分の残高)/ team(チームで共有している残高)
team_quota object | null チームのオーナーが設定した自分の利用枠。個人の残高を使っている場合とチームのオーナーは null
team_quota.unlimited boolean 利用枠が無制限か
team_quota.view_only boolean 閲覧のみで、トークンを使えないか
team_quota.budget integer | null 期間ごとの上限(null は無制限、0 は閲覧のみ)
team_quota.used integer 今の期間に使った量
team_quota.available integer | null 今の期間に残っている量(無制限なら null)
team_quota.period string | null 上限の期間。day / week / month(上限が無い場合は null)
team_quota.next_reset_at string | null 使用量がリセットされる日時
auto_purchase.enabled boolean 残高が少なくなったときの自動購入が有効か
auto_purchase.plan string | null 自動購入するトークンの種類(例: token_100)。無効なら null
auto_purchase.threshold integer 残高がこの値を下回ると自動購入します
リクエスト例
curl "https://stepeee.com/public-api/v1/me/tokens" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/tokens",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/tokens", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/tokens")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/tokens"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/tokens");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "balance": 90000,
    "reserved": 1200,
    "available": 88800,
    "wallet": "team",
    "team_quota": {
      "unlimited": false,
      "view_only": false,
      "budget": 10000,
      "used": 2500,
      "available": 7500,
      "period": "week",
      "next_reset_at": "2026-10-26T00:00:00Z"
    },
    "auto_purchase": {
      "enabled": true,
      "plan": "token_100",
      "threshold": 5000
    }
  }
}
GET › /me/token-usage

トークン使用量

トークンの使用量と追加量を日ごと・月ごとに取得します。使用量は1日分ずつ集計され、前日分が UTC 2:45 ごろに反映されます(当日の使用量は含まれません)。購入やボーナスによる追加はすぐに反映されます。

パラメータ
名前 場所 型 必須 既定値 説明
from クエリ string (YYYY-MM-DD) 任意 — 期間の開始日(UTC)。省略時は to の29日前
to クエリ string (YYYY-MM-DD) 任意 — 期間の終了日(UTC、その日を含む)。省略時は今日。期間は366日まで
group_by クエリ string 任意 day 集計の単位。day(日ごと)/ month(月ごと)
レスポンス項目
項目型説明
data[].period string 期間。日ごとは YYYY-MM-DD、月ごとは YYYY-MM。使用も追加も無い期間は含みません
data[].consumed integer 使用量
data[].added integer 追加量(返金の取り消しなどの減少を差し引いた値)
data[].consumed_by_type object 使用の種類ごとの内訳(text / image / video / audio など)
data[].added_by_type object 追加の種類ごとの内訳。purchase(購入)/ bonus(ボーナス)/ refund(返金)/ referral_revoke(紹介特典の取り消し。マイナス)
meta.from string 集計した期間の開始日
meta.to string 集計した期間の終了日
meta.group_by string 集計の単位
meta.total_consumed integer 期間の使用量の合計
meta.total_added integer 期間の追加量の合計
エラー
ステータスコード発生する条件
403 forbidden チームのトークンを使っているスタッフ(チームのトークン利用履歴はオーナーと管理者だけが取得できます)
422 validation_error 期間が366日を超える、to が from より前、日付として読めない、group_by が day / month 以外
リクエスト例
curl "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "period": "2026-10-18",
      "consumed": 450,
      "added": 0,
      "consumed_by_type": { "image": 300, "text": 150 },
      "added_by_type": {}
    },
    {
      "period": "2026-10-20",
      "consumed": 1000,
      "added": 4800,
      "consumed_by_type": { "video": 1000 },
      "added_by_type": { "purchase": 5000, "referral_revoke": -200 }
    }
  ],
  "meta": {
    "from": "2026-10-01",
    "to": "2026-10-20",
    "group_by": "day",
    "total_consumed": 1450,
    "total_added": 4800
  }
}
GET › /me/storage

ストレージ

ストレージの使用量と容量、ファイルの種類ごとの内訳を取得します。チームでは、チームで共有しているストレージを返します。

レスポンス項目
項目型説明
used_bytes integer 使用量(バイト)。by_type の合計と同じ値
capacity_bytes integer | null 容量(バイト)。null は無制限、0 はストレージなし(Freeプラン)
by_type[].file_type string | null ファイルの種類。material(素材)/ image(画像)/ video(映像)/ bgm / voice(音声)/ movie(完成動画)
by_type[].bytes integer その種類の使用量(バイト)
by_type[].files integer その種類のファイル数
リクエスト例
curl "https://stepeee.com/public-api/v1/me/storage" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/storage",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/storage", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/storage")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/storage"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/storage");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "used_bytes": 734003200,
    "capacity_bytes": null,
    "by_type": [
      { "file_type": "image", "bytes": 52428800, "files": 120 },
      { "file_type": "movie", "bytes": 629145600, "files": 8 },
      { "file_type": "voice", "bytes": 52428800, "files": 15 }
    ]
  }
}
GET › /me/payments

支払い履歴

プランの料金やトークン購入などの支払いを新しい順に取得します。会計システムへの取り込みに使えます。

パラメータ
名前 場所 型 必須 既定値 説明
status クエリ string 任意 — 支払いの状態で絞り込みます(カンマ区切り)。succeeded / refunded / partially_refunded。省略時はすべて
type クエリ string 任意 — 支払いの種類で絞り込みます(カンマ区切り)。値は data[].type と同じ
from クエリ string 任意 — 作成日時がこの日時以降のものだけを返します
to クエリ string 任意 — 作成日時がこの日時以前のものだけを返します
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].payment_unique string 支払いのID
data[].type string 種類。token_first_time(初回のトークン購入)/ token_regular(トークン購入)/ subscription_vault・subscription_plus・subscription_pro・subscription_team(各プランの料金)/ smm_application・smm_contract・smm_usage(X運用代行の料金)
data[].description string 支払いの名前(英語)
data[].status string 状態。succeeded(支払い済み)/ refunded(全額返金)/ partially_refunded(一部返金)
data[].currency string 通貨(ISO 4217 の小文字)
data[].amount_subtotal integer 税抜きの金額(最小単位)
data[].tax_amount integer 税額(最小単位)
data[].amount_total integer 税込みの金額(最小単位)
data[].line_items[] object 明細。type(base_plan: プラン料金 / storage_addon: ストレージ追加 / extra_member: 追加メンバー)・quantity(数量)・amount(金額)・description(説明。無ければ null)
data[].receipt_url string | null 領収書のURL(Stripe)。発行から日数が経つと開けなくなることがあります
data[].invoice_pdf_url string | null 請求書PDFのURL(Stripe)。発行から日数が経つと開けなくなることがあります
data[].created_at string 支払い日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "payment_unique": "Xy12AbCd34Ef",
      "type": "subscription_team",
      "description": "Team Monthly",
      "status": "succeeded",
      "currency": "usd",
      "amount_subtotal": 5000,
      "tax_amount": 500,
      "amount_total": 5500,
      "line_items": [
        { "type": "base_plan", "quantity": 1, "amount": 4000, "description": "Team plan" },
        { "type": "extra_member", "quantity": 2, "amount": 1000, "description": null }
      ],
      "receipt_url": "https://pay.stripe.com/receipts/...",
      "invoice_pdf_url": "https://pay.stripe.com/invoice/.../pdf",
      "created_at": "2026-10-01T08:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 10, "last_page": 1 }
}
GET › /me/referral

紹介プログラム

紹介コードと、紹介の実績・報酬の状況を取得します。

レスポンス項目
項目型説明
code string | null 紹介コード(まだ無い場合は null)
referral_url string | null 紹介用のURL(紹介コードが無い場合は null)
is_active boolean 紹介コードが有効か
reward_type string | null 報酬の受け取り方。cash(現金)/ token(トークン)。紹介コードが無い場合は null
clicks integer 紹介URLが開かれた回数
signups integer 紹介から登録した人数
conversions integer 紹介から有料プランを契約した人数
earned object これまでに確定した報酬 {amount(最小単位), currency}
earned_tokens integer これまでに受け取ったトークン
pending object 確定待ちの報酬 {amount, currency}
available object 受け取りを申請できる報酬 {amount, currency}
リクエスト例
curl "https://stepeee.com/public-api/v1/me/referral" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/referral",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/referral", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/referral")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/referral"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/referral");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "code": "REFk5m2j8x9ab",
    "referral_url": "https://stepeee.com?ref=REFk5m2j8x9ab",
    "is_active": true,
    "reward_type": "cash",
    "clicks": 12,
    "signups": 4,
    "conversions": 2,
    "earned": { "amount": 1300, "currency": "usd" },
    "earned_tokens": 0,
    "pending": { "amount": 300, "currency": "usd" },
    "available": { "amount": 800, "currency": "usd" }
  }
}

プロジェクト

プロジェクトと、その中のコンセプト・タイトルの構成を取得します。

GET › /projects

プロジェクト一覧

取得できるプロジェクトを新しい順に取得します。

パラメータ
名前 場所 型 必須 既定値 説明
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].project_unique string プロジェクトのID
data[].project_name string プロジェクト名
data[].description string | null プロジェクトの説明
data[].access_level string 自分の権限。owner(自分のプロジェクト)/ admin(チームのオーナー・管理者として全権限)/ edit(チームで編集権限を付与されている)
data[].team object | null チームのプロジェクトならチーム、自分だけのプロジェクトなら null
data[].team.team_unique string チームのID
data[].is_readonly boolean プランのダウングレードで上限を超え、閲覧専用になっているか(アップグレードすると解除されます)
data[].readonly_since string | null 閲覧専用になった日時
data[].created_at string 作成日時
data[].updated_at string 更新日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/projects" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "project_unique": "a1b2c3d4e5",
      "project_name": "Sample Project",
      "description": "Sample project description",
      "access_level": "owner",
      "team": null,
      "is_readonly": false,
      "readonly_since": null,
      "created_at": "2026-01-10T09:00:00Z",
      "updated_at": "2026-10-01T12:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}

プロジェクト詳細

プロジェクト1件の詳細と、モードごとのコンセプト数・タイトル数・進捗ごとのコンテンツ数を取得します。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
レスポンス項目
項目型説明
project_unique string プロジェクトのID
project_name string プロジェクト名
description string | null プロジェクトの説明
access_level string 自分の権限。owner(自分のプロジェクト)/ admin(チームのオーナー・管理者として全権限)/ edit(チームで編集権限を付与されている)
team object | null チームのプロジェクトならチーム、自分だけのプロジェクトなら null
team.team_unique string チームのID
is_readonly boolean プランのダウングレードで上限を超え、閲覧専用になっているか(アップグレードすると解除されます)
readonly_since string | null 閲覧専用になった日時
created_at string 作成日時
updated_at string 更新日時
scope string 対象地域。global(指定なし)/ region(特定の国向け)
scope_region string | null 対象の国(ISO 3166-1 alpha-2。例: JP)。global なら null
counts.{mode}.concepts integer モード(moviemode / blogmode / carouselmode / postmode)ごとのコンセプト数
counts.{mode}.titles integer | null タイトル数(postmode はタイトルが無いため null)
counts.{mode}.contents object コンテンツ数 {total(合計), not_started(未着手), in_progress(制作中), complete(完成)}
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "project_unique": "a1b2c3d4e5",
    "project_name": "Sample Project",
    "description": "Sample project description",
    "access_level": "owner",
    "team": null,
    "is_readonly": false,
    "readonly_since": null,
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-10-01T12:00:00Z",
    "scope": "region",
    "scope_region": "JP",
    "counts": {
      "moviemode": {
        "concepts": 2,
        "titles": 5,
        "contents": { "total": 8, "not_started": 1, "in_progress": 3, "complete": 4 }
      },
      "blogmode": {
        "concepts": 1,
        "titles": 3,
        "contents": { "total": 3, "not_started": 0, "in_progress": 1, "complete": 2 }
      },
      "carouselmode": {
        "concepts": 0,
        "titles": 0,
        "contents": { "total": 0, "not_started": 0, "in_progress": 0, "complete": 0 }
      },
      "postmode": {
        "concepts": 1,
        "titles": null,
        "contents": { "total": 1, "not_started": 0, "in_progress": 1, "complete": 0 }
      }
    }
  }
}
GET › /projects/{project_unique}/concepts

コンセプト一覧

プロジェクト内のコンセプトを、すべてのモードを横断して新しい順に取得します。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
mode クエリ string 任意 — モードで絞り込みます。moviemode(動画)・blogmode(ブログ)・carouselmode(カルーセル)・postmode(投稿)をカンマ区切りで複数指定できます。省略時はすべて
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].concept_unique string コンセプトのID
data[].mode string moviemode(動画)/ blogmode(ブログ)/ carouselmode(カルーセル)/ postmode(投稿)
data[].concept_name string コンセプト名
data[].title_count integer | null タイトル数(postmode は null)
data[].content_count integer コンテンツ数
data[].created_at string 作成日時
data[].updated_at string 更新日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "concept_unique": "pC7d2KqLx01m",
      "mode": "postmode",
      "concept_name": "SaaS growth tips",
      "title_count": null,
      "content_count": 1,
      "created_at": "2026-10-02T09:00:00Z",
      "updated_at": "2026-10-02T09:00:00Z"
    },
    {
      "concept_unique": "mC4f9TnB2q",
      "mode": "moviemode",
      "concept_name": "Cat facts",
      "title_count": 3,
      "content_count": 5,
      "created_at": "2026-09-20T03:00:00Z",
      "updated_at": "2026-09-28T03:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/concepts/{concept_unique}

コンセプト詳細

コンセプト1件の詳細を取得します。動画・ブログ・カルーセルはタイトルの一覧、投稿(postmode)は投稿者の人物像と投稿ルールを含みます。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
concept_unique パス string 必須 — コンセプトのID
レスポンス項目
項目型説明
concept_unique / mode / concept_name / title_count / content_count / created_at / updated_at — コンセプト一覧と同じ
description string | null コンセプトの説明
scope string 対象地域。global(指定なし)/ region(特定の国向け)
scope_region string | null 対象の国(ISO 3166-1 alpha-2。例: JP)。global なら null
default_template_unique string | null 新しいコンテンツに使うセットアップテンプレート(テンプレート一覧の template_unique)。未設定、または postmode なら null
titles array | null タイトルの一覧(新しい順)。postmode は null
titles[].title_unique string タイトルのID
titles[].title_name string タイトル
titles[].article_type string | null 種類。moviemode は standard(通常)/ news(ニュース)、blogmode は standard / news / promotion(商品紹介)。carouselmode は null
titles[].content_count integer そのタイトルのコンテンツ数
persona object | null 投稿者の人物像(postmode のみ。未作成なら null)
persona.persona_unique string 人物像のID
persona.gender string 性別。male / female / undisclosed(非公開)
persona.generation string 世代。10s / 20s / 30s / 40s / 50s / 60s_plus
persona.region string | null 文化圏の国コード
persona.keywords object 人物像のキーワード。occupation(職業)・industry(業界)・residence(住まい)・workstyle(働き方)・household(世帯)・personality(性格)は文字列、interest(関心)・expertise(専門)は文字列の配列。設定したものだけが入ります
persona.description string 人物像の文章
persona.casual_description string | null 日常の投稿に使う人物像の文章(無ければ null)
persona.taboos array 投稿で避けること
persona.timezone_mode string タイムゾーンの決め方。auto(地域から決める。地域が無ければ投稿の言語から決める)/ specify(指定したタイムゾーン)
persona.timezone string | null 投稿のスケジュールに使うタイムゾーン(IANA 形式)。投稿ルールが未作成で決められない場合は null
rule object | null 投稿ルール(postmode のみ。未作成なら null)
rule.rule_unique string 投稿ルールのID
rule.language string 投稿の言語
rule.formality string 話し方。very_casual(タメ口)/ casual(カジュアル)/ normal(普通)/ polite(丁寧)/ honorific(敬語)
rule.emoji string 絵文字。never(使わない)/ sometimes(たまに使う)/ often(よく使う)/ always(常に使う)
rule.line_break string 改行の多さ。none(なし)/ moderate(適度)/ frequent(多め)
rule.post_type_share object 投稿タイプの配分(%)。assertion(主張)/ knowhow(ノウハウ)/ experience(体験)/ casual(日常)
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
404 not_found コンセプトが無い(Concept not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "concept_unique": "pC7d2KqLx01m",
    "mode": "postmode",
    "concept_name": "SaaS growth tips",
    "title_count": null,
    "content_count": 1,
    "created_at": "2026-10-02T09:00:00Z",
    "updated_at": "2026-10-02T09:00:00Z",
    "description": "Practical growth tips for SaaS founders",
    "scope": "global",
    "scope_region": null,
    "default_template_unique": null,
    "titles": null,
    "persona": {
      "persona_unique": "aV3kQ9mN2pRt",
      "gender": "female",
      "generation": "30s",
      "region": "JP",
      "keywords": { "occupation": "SaaS marketer", "interest": ["growth", "analytics"] },
      "description": "A B2B SaaS marketer with ten years of experience...",
      "casual_description": null,
      "taboos": ["politics"],
      "timezone_mode": "auto",
      "timezone": "Asia/Tokyo",
      "updated_at": "2026-10-02T09:10:00Z"
    },
    "rule": {
      "rule_unique": "rU5tW7yZ9aBc",
      "language": "ja",
      "formality": "polite",
      "emoji": "sometimes",
      "line_break": "moderate",
      "post_type_share": { "assertion": 40, "knowhow": 30, "experience": 20, "casual": 10 },
      "updated_at": "2026-10-02T09:20:00Z"
    }
  }
}

コンテンツ

動画・ブログ・カルーセル・投稿のコンテンツを横断で取得します。詳細の package には各SNSやサイトへ投稿される内容(本文・画像・動画・キャプション)が入るため、Stepeee で作ったコンテンツを自分のシステムへ取り込めます。

GET › /projects/{project_unique}/contents

コンテンツ一覧

プロジェクト内のコンテンツ(動画・ブログ・カルーセル・投稿)を横断で取得します。進捗・掲載言語・公開の有無などで絞り込めます。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
mode クエリ string 任意 — モードで絞り込みます。moviemode(動画)・blogmode(ブログ)・carouselmode(カルーセル)・postmode(投稿)をカンマ区切りで複数指定できます。省略時はすべて
status クエリ string 任意 — 進捗で絞り込みます。not_started(未着手)/ in_progress(制作中)/ complete(完成)
concept_unique クエリ string 任意 — このコンセプトのコンテンツだけを返します
title_unique クエリ string 任意 — このタイトルのコンテンツだけを返します(postmode はタイトルが無いため含まれません)
language クエリ string 任意 — 掲載言語で絞り込みます(例: ja、en)
published クエリ string 任意 — true は投稿済みのコンテンツだけ、false はまだ投稿していないコンテンツだけを返します
from クエリ string 任意 — 作成日時がこの日時以降のものだけを返します
to クエリ string 任意 — 作成日時がこの日時以前のものだけを返します
sort クエリ string 任意 -created_at 並び順。created_at / -created_at / updated_at / -updated_at(- は新しい順)
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].mode string moviemode(動画)/ blogmode(ブログ)/ carouselmode(カルーセル)/ postmode(投稿)
data[].variation_unique string コンテンツのID
data[].variation_no integer タイトル(postmode はコンセプト)の中での番号
data[].title string タイトル(postmode はコンセプト名)
data[].concept object 属するコンセプト {concept_unique, concept_name}
data[].title_unique string | null 属するタイトルのID(postmode は null)
data[].language string | null 掲載言語(視聴者・読者が見る言語)。未設定なら null
data[].status string 進捗。not_started(未着手)/ in_progress(制作中)/ complete(完成にしたもの)
data[].progress.step_process integer 完了した Step(0〜3)
data[].progress.is_complete boolean 完成にしたか
data[].is_readonly boolean プランのダウングレードで閲覧専用になっているか
data[].confirmed_at string | null 内容を確認済みにした日時(postmode と未確認は null)
data[].published_platforms array 投稿済み(success / partial_success)の投稿先
data[].created_at string 作成日時
data[].updated_at string 更新日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "mode": "blogmode",
      "variation_unique": "bmA1b2C3d4E5",
      "variation_no": 1,
      "title": "How to start a blog",
      "concept": { "concept_unique": "bC2x8RtY4u", "concept_name": "Blogging for beginners" },
      "title_unique": "bT9kL3mN5pQr",
      "language": "en",
      "status": "complete",
      "progress": { "step_process": 3, "is_complete": true },
      "is_readonly": false,
      "confirmed_at": "2026-10-03T08:00:00Z",
      "published_platforms": [],
      "created_at": "2026-10-01T03:00:00Z",
      "updated_at": "2026-10-03T08:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/contents/{variation_unique}

コンテンツ詳細

コンテンツ1件の詳細を取得します。package には、各投稿先へ実際に投稿される内容(Stepeee から投稿するときと同じもの)が入ります。投稿(postmode)の投稿一覧はスケジュールで取得します。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
variation_unique パス string 必須 — コンテンツのID
レスポンス項目
項目型説明
mode / variation_unique / … / updated_at — コンテンツ一覧と同じ
publish[] object 投稿先ごとの投稿結果
publish[].platform string 投稿先。youtube / tiktok / instagram / x / wordpress / webhook
publish[].status string 投稿結果。success(投稿済み)/ failed(失敗)/ scheduled(投稿先で予約済み)/ processing(処理中)/ partial_success(投稿は成功し、サムネイル設定などの付随処理が失敗)/ reviewing(投稿は成功し、投稿先の審査待ちでURL未確定)
publish[].post_url string | null 投稿のURL(未確定なら null)
publish[].posted_at string | null 投稿日時(未投稿なら null)
content object モードごとの生成データ。blogmode: body_html(記事本文)/ carouselmode: scenario(スライドの構成。resolved_header・resolved_footer・resolved_texts が掲載言語の文言)/ moviemode: movie_unique・download_url・thumbnail_url(Step3で選択した動画。URLは発行から1時間有効)/ postmode: posts(post_text・post_type)
package object | null 投稿される内容。postmode は null
package.video (moviemode) object | null 完成動画 {file: {url, expires_at}, thumbnail: {url, expires_at} | null, duration_ms, width, height, size_bytes}。まだ無ければ null
package.youtube.title (moviemode) string | null YouTube のタイトル
package.youtube.description (moviemode) string | null YouTube の説明文(固定文を含む)
package.youtube.thumbnail (moviemode) object | null YouTube のサムネイル {url, expires_at, width, height}。縦型の動画(ショート)はサムネイルを設定しないため null
package.tiktok.caption (moviemode) string | null TikTok のキャプション
package.instagram.caption (moviemode / carouselmode) string | null Instagram のキャプション(固定文を含む)
package.instagram.cover (moviemode) object | null Instagram のカバー画像 {url, expires_at, width, height}
package.x.posts (moviemode / blogmode / carouselmode) array X の投稿文。2件以上はスレッドとして順に投稿されます
package.title (blogmode) string | null 記事タイトル
package.meta_description (blogmode) string | null メタディスクリプション
package.body_html (blogmode) string | null 記事本文の HTML。画像は img タグの src に入り、商品紹介のアフィリエイトコードや口コミも置き換え済みです。そのままサイトに掲載できます
package.images (blogmode) array 本文の画像(出てくる順){url, expires_at, width, height}
package.cover_image (blogmode) object | null カバー画像 {url, expires_at, width, height}
package.audio (blogmode) object | null 記事の音声 {url, expires_at, duration_ms}
package.slides[] (carouselmode) object スライド画像(番号順){no, image: {url, expires_at, width, height}}
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
404 not_found コンテンツが無い(Content not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "mode": "blogmode",
    "variation_unique": "bmA1b2C3d4E5",
    "variation_no": 1,
    "title": "How to start a blog",
    "concept": { "concept_unique": "bC2x8RtY4u", "concept_name": "Blogging for beginners" },
    "title_unique": "bT9kL3mN5pQr",
    "language": "en",
    "status": "complete",
    "progress": { "step_process": 3, "is_complete": true },
    "is_readonly": false,
    "confirmed_at": "2026-10-03T08:00:00Z",
    "published_platforms": ["wordpress"],
    "created_at": "2026-10-01T03:00:00Z",
    "updated_at": "2026-10-03T08:00:00Z",
    "publish": [
      {
        "platform": "wordpress",
        "status": "success",
        "post_url": "https://blog.example.com/how-to-start-a-blog/",
        "posted_at": "2026-10-03T09:00:00Z"
      }
    ],
    "content": { "body_html": "<h2>Why start a blog</h2><p>...</p>" },
    "package": {
      "title": "How to Start a Blog in 2026",
      "meta_description": "A step-by-step guide to starting your first blog.",
      "body_html": "<h2>Why start a blog</h2><p>...</p><figure><img src=\"https://...\" alt=\"\" /></figure>",
      "images": [
        { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z", "width": 1536, "height": 1024 }
      ],
      "cover_image": { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z", "width": 1200, "height": 630 },
      "audio": null,
      "x": { "posts": ["New post: How to start a blog in 2026"] }
    }
  }
}
GET › /projects/{project_unique}/contents/{variation_unique}/schedule

投稿スケジュール

投稿(postmode)のコンテンツの、予定・生成済み・投稿済みの投稿を予定日時の順に取得します。自動化の状況も含みます。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
variation_unique パス string 必須 — コンテンツのID
from クエリ string 任意 — 期間の開始(予定日時)。省略時は今から7日前(to だけ指定した場合は to の37日前)
to クエリ string 任意 — 期間の終わり(予定日時)。省略時は今から30日後(from だけ指定した場合は from の37日後)。期間は92日まで
レスポンス項目
項目型説明
automation.enabled boolean 自動化が有効か
automation.is_executing boolean 自動で投稿を作る処理が動いているか(自動化を止めても、作成途中の投稿が残っていれば true)
automation.week_limit integer | null 自動で予定を作る週数の上限(null は無制限)
automation.week_count integer これまでに予定を作った週数
automation.next_refill_at string | null 次に予定を作る日時(自動化が無効なら null)
automation.timezone string | null 投稿のスケジュールに使うタイムゾーン
items[].schedule_unique string 予定のID
items[].post_unique string | null 投稿のID(まだ本文を作っていなければ null)
items[].scheduled_at string 投稿する予定日時
items[].scheduled_at_local string 予定日時(timezone の現地時刻。YYYY-MM-DDTHH:MM:SS)
items[].timezone string 予定を作ったときのタイムゾーン
items[].status string 状態。pending(本文の作成待ち)/ generating(作成中)/ generated(作成済み・投稿待ち)/ awaiting_image(画像の作成待ち)/ posting(投稿中)/ posted(投稿済み)/ failed(失敗)/ discarded(取りやめ)
items[].confirm_state string 投稿前の確認。none(確認なし)/ awaiting(承認されるまで投稿しない)/ notice(通知のみで投稿する)/ confirmed(承認済み)
items[].created_via string 作られ方。auto(自動化)/ manual(手動)
items[].post_type string 投稿タイプ。assertion(主張)/ knowhow(ノウハウ)/ experience(体験)/ casual(日常)
items[].text string | null 投稿の本文(まだ作っていなければ null)
items[].thread[] object スレッドの続きの投稿(順番どおり){text, post_url, posted_at, image}
items[].image object | null 添付する画像 {url, expires_at}(無ければ null)
items[].post_url string | null 投稿のURL(未確定なら null)
items[].posted_at string | null 投稿日時(未投稿なら null)
items[].fail_reason string | null 失敗の理由。token_expired(X の連携切れ)/ api_error(X のエラー)/ not_found(投稿の対象が無い)/ insufficient_token(トークン不足)/ no_x_account(X アカウント未設定)/ node_ws_timeout(本文の作成がタイムアウト)/ unconfirmed(承認されなかった)
meta.from / meta.to string 取得した期間
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
404 not_found 投稿(postmode)以外のコンテンツ、またはコンテンツが無い(Schedule not found.)
422 validation_error 期間が92日を超える、to が from より前、日時として読めない
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "automation": {
      "enabled": true,
      "is_executing": true,
      "week_limit": 4,
      "week_count": 2,
      "next_refill_at": "2026-10-26T15:00:00Z",
      "timezone": "Asia/Tokyo"
    },
    "items": [
      {
        "schedule_unique": "Sc1aB2cD3eF4",
        "post_unique": "Po1aB2cD3eF4",
        "scheduled_at": "2026-10-20T01:00:00Z",
        "scheduled_at_local": "2026-10-20T10:00:00",
        "timezone": "Asia/Tokyo",
        "status": "posted",
        "confirm_state": "none",
        "created_via": "auto",
        "post_type": "assertion",
        "text": "Most teams overthink onboarding...",
        "thread": [
          {
            "text": "First, cut the steps in half.",
            "post_url": "https://x.com/i/status/1848000000000000002",
            "posted_at": "2026-10-20T01:00:05Z",
            "image": null
          }
        ],
        "image": { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z" },
        "post_url": "https://x.com/i/status/1848000000000000001",
        "posted_at": "2026-10-20T01:00:00Z",
        "fail_reason": null
      },
      {
        "schedule_unique": "Sc9zY8xW7vU6",
        "post_unique": null,
        "scheduled_at": "2026-10-25T09:30:00Z",
        "scheduled_at_local": "2026-10-25T18:30:00",
        "timezone": "Asia/Tokyo",
        "status": "pending",
        "confirm_state": "none",
        "created_via": "auto",
        "post_type": "knowhow",
        "text": null,
        "thread": [],
        "image": null,
        "post_url": null,
        "posted_at": null,
        "fail_reason": null
      }
    ]
  },
  "meta": { "from": "2026-10-20T00:00:00Z", "to": "2026-11-20T23:59:59Z" }
}

投稿結果・連携先

SNS・WordPress・Webhook への投稿結果と、プロジェクトに連携している投稿先の状態を取得します。連携切れの検知に使えます。

GET › /projects/{project_unique}/publications

投稿結果一覧

プロジェクトの投稿結果を、すべてのモードと投稿先を横断して新しい順に取得します。投稿(postmode)は、投稿済みと失敗した投稿(スレッドの最初の投稿)を含みます。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
mode クエリ string 任意 — モードで絞り込みます。moviemode(動画)・blogmode(ブログ)・carouselmode(カルーセル)・postmode(投稿)をカンマ区切りで複数指定できます。省略時はすべて
platform クエリ string 任意 — 投稿先で絞り込みます(カンマ区切り)。youtube / tiktok / instagram / x / wordpress / webhook
status クエリ string 任意 — 投稿結果で絞り込みます(カンマ区切り)。success / failed / scheduled / processing / partial_success / reviewing
from クエリ string 任意 — 投稿日時(未投稿なら記録日時)がこの日時以降のものだけを返します
to クエリ string 任意 — 投稿日時(未投稿なら記録日時)がこの日時以前のものだけを返します
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].publication_unique string 投稿結果のID
data[].mode string moviemode(動画)/ blogmode(ブログ)/ carouselmode(カルーセル)/ postmode(投稿)
data[].content.variation_unique string コンテンツのID
data[].content.title string | null タイトル(postmode はコンセプト名)
data[].platform string 投稿先。youtube / tiktok / instagram / x / wordpress / webhook
data[].account object | null 投稿したアカウント {account_unique, name}。連携を解除したアカウントは name が null。postmode は null
data[].status string 投稿結果。success(投稿済み)/ failed(失敗)/ scheduled(投稿先で予約済み)/ processing(処理中)/ partial_success(投稿は成功し、サムネイル設定などの付随処理が失敗)/ reviewing(投稿は成功し、投稿先の審査待ちでURL未確定)
data[].post_url string | null 投稿のURL(未確定なら null)
data[].error_code string | null 失敗の理由のコード(投稿先やモードごとに異なります)
data[].is_automation boolean 自動化で投稿したか
data[].posted_at string | null 投稿日時(未投稿なら null)
data[].created_at string 作成日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "publication_unique": "Xk3p9QmZ2aLw",
      "mode": "postmode",
      "content": { "variation_unique": "pmV7d2KqLx01", "title": "SaaS growth tips" },
      "platform": "x",
      "account": null,
      "status": "success",
      "post_url": "https://x.com/i/status/1848123456789012345",
      "error_code": null,
      "is_automation": true,
      "posted_at": "2026-10-04T10:00:00Z",
      "created_at": "2026-10-03T22:10:00Z"
    },
    {
      "publication_unique": "Pq2wE4rT6yUi",
      "mode": "blogmode",
      "content": { "variation_unique": "bmA1b2C3d4E5", "title": "How to start a blog" },
      "platform": "wordpress",
      "account": { "account_unique": "Wp3xY5zA7bCd", "name": "My WP Site" },
      "status": "failed",
      "post_url": null,
      "error_code": "auth_failed",
      "is_automation": false,
      "posted_at": null,
      "created_at": "2026-10-02T10:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/accounts

連携先一覧

プロジェクトに連携している投稿先(SNS アカウント・WordPress・Webhook)と、その状態を取得します。status が expired や connection_error になったら再連携が必要です。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
レスポンス項目
項目型説明
data[].account_unique string 連携先のID
data[].platform string 投稿先。youtube / tiktok / instagram / x / wordpress / webhook
data[].name string 表示名。SNS はアカウント名、WordPress はサイト名、Webhook は送信先URLのドメイン(https://example.com/… の形。パスは含みません)
data[].image_url string | null アカウントのアイコン画像のURL(SNS のみ)
data[].status string 状態。active(利用可能)/ expired(連携の期限切れ。再連携が必要)/ connection_error(WordPress に接続できない)
data[].token_expires_at string | null 連携の有効期限(SNS のみ)
data[].connected_at string | null 連携した日時
data[].last_used_at string | null 最後に投稿に使った日時(SNS のみ)
data[].site_url string | null WordPress のサイトURL(WordPress のみ)
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "account_unique": "Wh9kQ2mN4pRt",
      "platform": "webhook",
      "name": "https://hooks.example.com/…",
      "image_url": null,
      "status": "active",
      "token_expires_at": null,
      "connected_at": "2026-07-01T00:00:00Z",
      "last_used_at": null,
      "site_url": null
    },
    {
      "account_unique": "Wp3xY5zA7bCd",
      "platform": "wordpress",
      "name": "Example Blog",
      "image_url": null,
      "status": "connection_error",
      "token_expires_at": null,
      "connected_at": "2026-08-01T00:00:00Z",
      "last_used_at": null,
      "site_url": "https://blog.example.com"
    },
    {
      "account_unique": "Yt4aB6cD8eFg",
      "platform": "youtube",
      "name": "Channel B",
      "image_url": "https://yt3.ggpht.com/abc.png",
      "status": "expired",
      "token_expires_at": "2026-10-01T00:00:00Z",
      "connected_at": "2026-09-01T00:00:00Z",
      "last_used_at": "2026-09-30T00:00:00Z",
      "site_url": null
    }
  ]
}

自動化

動画・ブログ・カルーセルの自動化の実行状況を取得します。投稿の自動化(ポストモード)の状況は、コンテンツのスケジュールで取得します。

GET › /automations

自動化の実行一覧

動画・ブログ・カルーセルの自動化の実行(予約・実行中・確認待ち・終了)を新しい順に取得します。

パラメータ
名前 場所 型 必須 既定値 説明
status クエリ string 任意 — 状態で絞り込みます(カンマ区切り)。値は data[].status と同じ
mode クエリ string 任意 — モードで絞り込みます(カンマ区切り)。moviemode / blogmode / carouselmode
project_unique クエリ string 任意 — このプロジェクトの実行だけを返します
from クエリ string 任意 — 作成日時がこの日時以降のものだけを返します
to クエリ string 任意 — 作成日時がこの日時以前のものだけを返します
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].auto_unique string 自動化の実行のID
data[].mode string moviemode / blogmode / carouselmode
data[].project object プロジェクト {project_unique, project_name}
data[].content.variation_unique string コンテンツのID
data[].content.title string | null タイトル(postmode はコンセプト名)
data[].run_no integer そのコンテンツで何回目の実行か
data[].status string 状態。pending(実行待ち。reserved_at が未来なら予約)/ executing(実行中)/ waiting_confirmation(内容の確認待ち。確認すると続きを実行)/ completed(完了)/ failed(失敗)/ stopped(停止)/ token_shortage(トークン不足で終了)
data[].execution_mode string sequential(1件ずつ実行)/ parallel(同時に実行)
data[].phases object 段階ごとの状態 {setup, step1, step2, step3}。not_started(未着手)/ running(実行中、または止まった段階)/ done(完了。スキップ、および completed した run では自動化の範囲外にした手順も含む)/ error(失敗)
data[].template.setup_template_name string | null 開始時に使ったセットアップテンプレートの名前
data[].template.automation_template_name string | null 開始時に使った自動化テンプレートの名前
data[].reserved_at string | null 予約した実行日時
data[].executed_at string | null 実行を始めた日時
data[].completed_at string | null 終了した日時(completed / failed / stopped / token_shortage のとき)
data[].created_at string 実行を登録した日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "auto_unique": "aB3dE5fG7h",
      "mode": "blogmode",
      "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My Blog" },
      "content": { "variation_unique": "Xy12Zw34Ab56", "title": "Spring travel tips" },
      "run_no": 2,
      "status": "executing",
      "execution_mode": "sequential",
      "phases": { "setup": "done", "step1": "done", "step2": "running", "step3": "not_started" },
      "template": { "setup_template_name": "Default setup", "automation_template_name": null },
      "reserved_at": null,
      "executed_at": "2026-10-19T23:09:27Z",
      "completed_at": null,
      "created_at": "2026-10-19T23:09:20Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /automations/{auto_unique}

自動化の実行詳細

自動化の実行1件の詳細と、手順ごとの進み具合を取得します。実行中の進捗を確かめるときに使えます。

パラメータ
名前 場所 型 必須 既定値 説明
auto_unique パス string 必須 — 自動化の実行のID
レスポンス項目
項目型説明
auto_unique / mode / … / created_at — 自動化の実行一覧と同じ
steps[].key string 手順の名前(例: step1_1_text)
steps[].phase string 手順の段階。setup / step1 / step2 / step3
steps[].status string 手順の状態。not_run(未実行・対象外・実行中)/ success(成功)/ error(失敗)/ skipped(スキップ)
steps[].started_at string | null 実行中の手順が始まった日時(終わると null)
steps[].finished_at string | null 手順が終わった日時
steps[].duration_sec number | null かかった秒数(success / error のとき)
steps[].error_code string | null 失敗の理由。internal_error / automation_record_not_found / automation_stopped_by_admin / insufficient_token(トークン不足)/ token_group_blocked(チームの利用枠の上限)/ automation_auth_error(投稿先の認証エラー)/ automation_not_found / automation_conflict / automation_rate_limited(投稿先の回数制限)/ automation_server_error(投稿先のエラー)/ automation_network_error(通信エラー)/ automation_step_failed。理由が記録されていなければ null
accounts[] object 開始時の投稿先 {platform, account_unique, name}。Webhook の name は null
stop_requested boolean 停止を指示したか
confirmation.requested_at string | null 確認待ちになった日時
confirmation.confirmed_at string | null 内容を確認した日時(確認待ちや未確認は null)
エラー
ステータスコード発生する条件
404 not_found 自動化が無い、または取得できる範囲外(Automation not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "auto_unique": "aB3dE5fG7h",
    "mode": "blogmode",
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My Blog" },
    "content": { "variation_unique": "Xy12Zw34Ab56", "title": "Spring travel tips" },
    "run_no": 2,
    "status": "failed",
    "execution_mode": "sequential",
    "phases": { "setup": "done", "step1": "done", "step2": "done", "step3": "error" },
    "template": { "setup_template_name": "Default setup", "automation_template_name": "Skip voice" },
    "reserved_at": null,
    "executed_at": "2026-10-19T23:09:27Z",
    "completed_at": "2026-10-19T23:17:50Z",
    "created_at": "2026-10-19T23:09:20Z",
    "steps": [
      { "key": "setup", "phase": "setup", "status": "success", "started_at": null, "finished_at": "2026-10-19T23:09:29Z", "duration_sec": 2.3, "error_code": null },
      { "key": "step1_1_text", "phase": "step1", "status": "success", "started_at": null, "finished_at": "2026-10-19T23:11:40Z", "duration_sec": 126.3, "error_code": null },
      { "key": "step2_2", "phase": "step2", "status": "skipped", "started_at": null, "finished_at": "2026-10-19T23:17:39Z", "duration_sec": null, "error_code": null },
      { "key": "step3_4_webhook", "phase": "step3", "status": "error", "started_at": null, "finished_at": "2026-10-19T23:17:46Z", "duration_sec": 1.2, "error_code": "automation_server_error" }
    ],
    "accounts": [
      { "platform": "webhook", "account_unique": "dxuD2gk3NYuA", "name": null }
    ],
    "stop_requested": false,
    "confirmation": { "requested_at": null, "confirmed_at": null }
  }
}

素材・テンプレート

MY素材(画像・映像・BGM)と、セットアップ・自動化のテンプレートを取得します。

GET › /materials

素材一覧

MY素材(画像・映像・BGM)を新しい順に取得します。チームでは、チームで共有している素材を返します。プロジェクトの中だけで使う画像や生成途中のファイルは含みません。

パラメータ
名前 場所 型 必須 既定値 説明
kind クエリ string 任意 — 素材の種類で絞り込みます。image(画像)/ video(映像)/ bgm
type クエリ string 任意 — 素材の用途で絞り込みます。値は data[].type と同じ。kind と一緒に指定する場合は、その種類の用途だけを指定できます
category_unique クエリ string 任意 — このカテゴリの素材だけを返します
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].material_unique string 素材のID
data[].kind string 種類。image(画像)/ video(映像)/ bgm
data[].type string 用途。image_element(エレメント)/ image_vertical(縦)/ image_horizontal(横)/ reference_person(参照画像: 人物)/ reference_background(参照画像: 背景)/ reference_layout(参照画像: レイアウト)/ reference_cta(参照画像: CTA)/ reference_pet(参照画像: ペット)/ reference_product(参照画像: 商品・サービス)/ image_rulebook(ルールブック)/ image_promotion(プロモーション)/ video_vertical(縦の映像)/ video_horizontal(横の映像)/ bgm
data[].category object | null カテゴリ {category_unique, name}(未分類なら null)
data[].width / data[].height integer | null 幅と高さ(ピクセル)。BGM と未計測は null
data[].duration_ms integer | null 長さ(ミリ秒)。画像は null
data[].size_bytes integer ファイルサイズ(バイト)。共有素材を参照している場合は 0 のことがあります
data[].file object ファイル本体 {url, expires_at}
data[].thumbnail object | null サムネイル {url, expires_at}。BGM・エレメント・サムネイルの作成中は null
data[].created_at string 作成日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "material_unique": "aB3dE5fG7hJ9kL1mN3pQ",
      "kind": "image",
      "type": "image_vertical",
      "category": { "category_unique": "Xy12Ab34Cd", "name": "Product shots" },
      "width": 768,
      "height": 1344,
      "duration_ms": null,
      "size_bytes": 1234567,
      "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "thumbnail": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "created_at": "2026-10-01T10:00:00Z"
    },
    {
      "material_unique": "Zq9Wv8Ut7Sr6Qp5On4Ml",
      "kind": "bgm",
      "type": "bgm",
      "category": null,
      "width": null,
      "height": null,
      "duration_ms": 30000,
      "size_bytes": 482133,
      "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "thumbnail": null,
      "created_at": "2026-09-30T08:12:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /materials/{material_unique}

素材詳細

素材1件を取得します。

パラメータ
名前 場所 型 必須 既定値 説明
material_unique パス string 必須 — 素材のID
レスポンス項目
項目型説明
material_unique string 素材のID
kind string 種類。image(画像)/ video(映像)/ bgm
type string 用途。image_element(エレメント)/ image_vertical(縦)/ image_horizontal(横)/ reference_person(参照画像: 人物)/ reference_background(参照画像: 背景)/ reference_layout(参照画像: レイアウト)/ reference_cta(参照画像: CTA)/ reference_pet(参照画像: ペット)/ reference_product(参照画像: 商品・サービス)/ image_rulebook(ルールブック)/ image_promotion(プロモーション)/ video_vertical(縦の映像)/ video_horizontal(横の映像)/ bgm
category object | null カテゴリ {category_unique, name}(未分類なら null)
width / height integer | null 幅と高さ(ピクセル)。BGM と未計測は null
duration_ms integer | null 長さ(ミリ秒)。画像は null
size_bytes integer ファイルサイズ(バイト)。共有素材を参照している場合は 0 のことがあります
file object ファイル本体 {url, expires_at}
thumbnail object | null サムネイル {url, expires_at}。BGM・エレメント・サムネイルの作成中は null
created_at string 作成日時
エラー
ステータスコード発生する条件
404 not_found 素材が無い、または取得できる範囲外(Material not found.)
リクエスト例
curl "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "material_unique": "aB3dE5fG7hJ9kL1mN3pQ",
    "kind": "image",
    "type": "image_vertical",
    "category": { "category_unique": "Xy12Ab34Cd", "name": "Product shots" },
    "width": 768,
    "height": 1344,
    "duration_ms": null,
    "size_bytes": 1234567,
    "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
    "thumbnail": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
    "created_at": "2026-10-01T10:00:00Z"
  }
}
GET › /material-categories

素材カテゴリ一覧

素材のカテゴリと、カテゴリごとの素材数を取得します。

パラメータ
名前 場所 型 必須 既定値 説明
kind クエリ string 任意 — 素材の種類で絞り込みます。image(画像)/ video(映像)/ bgm
type クエリ string 任意 — 素材の用途で絞り込みます。値は data[].type と同じ。kind と一緒に指定する場合は、その種類の用途だけを指定できます
レスポンス項目
項目型説明
data[].category_unique string カテゴリのID
data[].name string カテゴリ名
data[].kind string 種類。image(画像)/ video(映像)/ bgm
data[].type string 用途。image_element(エレメント)/ image_vertical(縦)/ image_horizontal(横)/ reference_person(参照画像: 人物)/ reference_background(参照画像: 背景)/ reference_layout(参照画像: レイアウト)/ reference_cta(参照画像: CTA)/ reference_pet(参照画像: ペット)/ reference_product(参照画像: 商品・サービス)/ image_rulebook(ルールブック)/ image_promotion(プロモーション)/ video_vertical(縦の映像)/ video_horizontal(横の映像)/ bgm
data[].is_system boolean Stepeee が自動で作ったカテゴリか
data[].material_count integer カテゴリの素材数
エラー
ステータスコード発生する条件
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/material-categories?kind=image" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/material-categories?kind=image",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/material-categories?kind=image", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/material-categories?kind=image")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/material-categories?kind=image"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/material-categories?kind=image");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "category_unique": "Bg12Ab34Cd",
      "name": "Lo-fi",
      "kind": "bgm",
      "type": "bgm",
      "is_system": false,
      "material_count": 3
    },
    {
      "category_unique": "Xy12Ab34Cd",
      "name": "Product shots",
      "kind": "image",
      "type": "image_vertical",
      "is_system": false,
      "material_count": 12
    }
  ]
}
GET › /templates

テンプレート一覧

セットアップテンプレートと自動化テンプレートを、更新が新しい順に取得します。チームでは、チームで共有しているテンプレートを返します。

パラメータ
名前 場所 型 必須 既定値 説明
mode クエリ string 任意 — モードで絞り込みます。moviemode / blogmode / carouselmode / postmode
kind クエリ string 任意 — テンプレートの種類で絞り込みます。setup / automation
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].template_unique string テンプレートのID
data[].kind string 種類。setup(制作の設定をまとめたセットアップテンプレート)/ automation(自動化で実行する手順を決める自動化テンプレート)
data[].mode string moviemode(動画)/ blogmode(ブログ)/ carouselmode(カルーセル)/ postmode(投稿)
data[].name string テンプレート名
data[].created_at string 作成日時
data[].updated_at string 更新日時
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "template_unique": "Ab12Cd34Ef",
      "kind": "automation",
      "mode": "carouselmode",
      "name": "Morning carousel",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-10-05T00:00:00Z"
    },
    {
      "template_unique": "Gh56Ij78Kl",
      "kind": "setup",
      "mode": "moviemode",
      "name": "60-second explainer",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-10-01T00:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}

タイトル・コンテンツ

動画・ブログ・カルーセルのコンセプトにタイトルを追加し、コンテンツを削除します。Pro プラン以上で使えます。

POST › /projects/{project_unique}/concepts/{concept_unique}/titles

タイトルを追加する

動画・ブログ・カルーセルのコンセプトにタイトルをまとめて追加し、タイトルごとに最初のコンテンツを1件作ります(画面でタイトルを手動で登録したときと同じ処理)。同じコンセプトに同じ名前のタイトルがあるもの、同じリクエストの中で2回目以降に出てくる名前は作らずに skipped に入れます。コンセプトのタイトルは100件までで、追加すると100件を超える場合は1件も作りません(同じ名前で作らないものは数えません)。プランのコンテンツ数の上限で作れないときは、タイトルだけを作り variation_unique を null にします。ブログのプロモーション・アフィリエイトの設定はできず、標準の記事として作ります。チームでは、作ったタイトルとコンテンツの所有者はチームのオーナーです。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
concept_unique パス string 必須 — コンセプトのID(動画・ブログ・カルーセルのコンセプトで、プロジェクトの中にあるもの)
titles 本文 string[] 必須 — 追加するタイトル。1〜50件。それぞれ前後の空白を除いて1〜500文字(空白だけ・「0」だけ・途中に改行を含むものは不可)
language 本文 string 必須 — 作るコンテンツの掲載言語(ja、en、fr などの言語コード)
setup_template_unique 本文 string | null 任意 — 適用するセットアップテンプレートのID(GET /templates の template_unique。kind が setup で、コンセプトと同じモードのもの)。省略するとコンセプトの既定のテンプレート(未設定なら標準のセットアップ)
Idempotency-Key ヘッダー string 任意 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
created[] object 作ったタイトル(送った順)
created[].title_unique string タイトルのID
created[].title_name string タイトル名(前後の空白を除いたもの)
created[].variation_unique string | null 作った最初のコンテンツのID。プランのコンテンツ数の上限で作れなかったときは null
skipped[] object 作らなかったタイトル(送った順)
skipped[].title_name string タイトル名(前後の空白を除いたもの)
skipped[].reason string 作らなかった理由。duplicate(同じコンセプトに同じ名前のタイトルがある、または同じリクエストの中で2回目以降に出てきた)
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
403 readonly プロジェクトがプランのダウングレードで閲覧専用
404 not_found プロジェクトが無い・取得できる範囲外、またはコンセプトがそのプロジェクトに無い
409 title_limit_reached 追加するとコンセプトのタイトルが100件を超える(1件も作りません)。details に limit(上限)と total_after_add(追加後の件数)
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 validation_error パラメータが不正
422 mode_not_supported 投稿(ポストモード)またはフォトのコンセプト
422 template_not_found setup_template_unique のテンプレートが無い(別のモードのものを含む)
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}'
import requests

body = """{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
    "language": "en",
    "setup_template_unique": "Gh56Ij78Kl"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
          "language": "en",
          "setup_template_unique": "Gh56Ij78Kl"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "created": [
      { "title_unique": "q8Wm2LzR0pXa", "title_name": "Easy breakfast for beginners", "variation_unique": "Hn4kT7sY1cVb" },
      { "title_unique": "Zr5uP9eK3wQd", "title_name": "Meal prep in 5 minutes", "variation_unique": "Jm8oB2fN6xLe" }
    ],
    "skipped": [
      { "title_name": "Easy breakfast for beginners", "reason": "duplicate" }
    ]
  }
}
DELETE › /projects/{project_unique}/contents/{variation_unique}

コンテンツを削除する

動画・ブログ・カルーセルのコンテンツを削除します(画面でコンテンツを削除したときと同じ処理)。削除したコンテンツはすぐに一覧・詳細から消え、delete_at(3日後)を過ぎると、生成した画像・音声・動画とともに完全に削除されます。同じタイトルの後ろのコンテンツの番号は1つずつ詰めます。自動化の実行中・予約中のコンテンツは削除できないので、自動化を止めてから削除してください。タイトルに残る最後の1件と、投稿(ポストモード)のコンテンツは削除できません。

パラメータ
名前 場所 型 必須 既定値 説明
project_unique パス string 必須 — プロジェクトのID
variation_unique パス string 必須 — コンテンツのID
レスポンス項目
項目型説明
variation_unique string 削除したコンテンツのID
mode string moviemode(動画)/ blogmode(ブログ)/ carouselmode(カルーセル)
delete_at string 完全に削除される日時
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
403 readonly コンテンツまたはプロジェクトがプランのダウングレードで閲覧専用
404 not_found プロジェクトが無い・取得できる範囲外、コンテンツがそのプロジェクトに無い、または削除済み
409 automation_running 自動化の実行中・予約中(終わっていない自動化がある)
409 last_variation タイトルに残る最後の1件
422 mode_not_supported 投稿(ポストモード)のコンテンツ
リクエスト例
curl -X DELETE "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "variation_unique": "Hn4kT7sY1cVb",
    "mode": "blogmode",
    "delete_at": "2026-10-24T12:00:00Z"
  }
}

自動化の操作

動画・ブログ・カルーセルの自動化を開始・予約変更・停止し、確認待ちの自動化を承認します。操作できるのは GET /automations で取得できる自動化と同じ範囲です。停止はプランに関係なく使え、それ以外は Pro プラン以上で使えます。

POST › /automations

自動化を開始する

コンテンツ(動画・ブログ・カルーセル)の自動化を、自動化テンプレートの設定で開始します。reserved_at を指定すると予約、省略すると今すぐ実行します。対象はすべて同じプロジェクト・同じモードのコンテンツにしてください。1件でも開始できないコンテンツがあれば何も登録せず、どのコンテンツが何の理由で開始できないかを返します。作成済みの手順は飛ばして最初の未作成の手順から実行し、自動化テンプレートでスキップにした手順は実行しません。セットアップが未完了のコンテンツは、開始時にセットアップを確定します。自動化の実行では Token を消費します。開始時には残高を確かめず、実行中に足りなくなると token_shortage で終わります。内容の確認が必要な設定では途中で waiting_confirmation になって止まるので、POST /automations/{auto_unique}/confirm で承認してください。投稿(ポストモード)の自動投稿は、コンテンツごとに画面でオン・オフする別の仕組みで、このエンドポイントでは開始できません。

パラメータ
名前 場所 型 必須 既定値 説明
variation_uniques 本文 string[] 必須 — 自動化するコンテンツの variation_unique。1〜50件、重複不可
automation_template_unique 本文 string 必須 — 自動化テンプレートのID(GET /templates?kind=automation の template_unique。コンテンツと同じモードのもの)
reserved_at 本文 string 任意 — 実行する日時(未来の日時)。時差つきの ISO 8601 で指定し、時差が無いものは UTC として扱います。省略すると今すぐ実行します
Idempotency-Key ヘッダー string 必須 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。二重に開始しないよう必須です。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
data[].auto_unique string 自動化の実行のID
data[].mode string moviemode / blogmode / carouselmode
data[].project object プロジェクト {project_unique, project_name}
data[].content.variation_unique string コンテンツのID
data[].content.title string | null タイトル(postmode はコンセプト名)
data[].run_no integer そのコンテンツで何回目の実行か
data[].status string 状態。pending(実行待ち。reserved_at が未来なら予約)/ executing(実行中)/ waiting_confirmation(内容の確認待ち。確認すると続きを実行)/ completed(完了)/ failed(失敗)/ stopped(停止)/ token_shortage(トークン不足で終了)
data[].execution_mode string sequential(1件ずつ実行)/ parallel(同時に実行)
data[].phases object 段階ごとの状態 {setup, step1, step2, step3}。not_started(未着手)/ running(実行中、または止まった段階)/ done(完了。スキップ、および completed した run では自動化の範囲外にした手順も含む)/ error(失敗)
data[].template.setup_template_name string | null 開始時に使ったセットアップテンプレートの名前
data[].template.automation_template_name string | null 開始時に使った自動化テンプレートの名前
data[].reserved_at string | null 予約した実行日時
data[].executed_at string | null 実行を始めた日時
data[].completed_at string | null 終了した日時(completed / failed / stopped / token_shortage のとき)
data[].created_at string 実行を登録した日時
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
404 content_not_found 取得できる範囲のコンテンツに無い variation_unique がある(受け付けた後に削除予約されたものを含む。何も登録しません)。details.variation_uniques に該当するもの
404 automation_template_not_found 自動化テンプレートが無い
409 contents_not_automatable 開始できないコンテンツがある(何も登録しません)。details.contents に {variation_unique, reason} の配列。reason は automation_active(終わっていない自動化がある)/ content_complete(完成済み)/ content_readonly(プランのダウングレードで閲覧専用)/ layout_template_required(カルーセルで、プロジェクトにレイアウトテンプレートが1件も無い)
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 validation_error パラメータが不正(0件・51件以上、重複、reserved_at が過去など)
422 mode_not_supported 投稿(ポストモード)のコンテンツが含まれる。details.variation_uniques に該当するもの
422 mixed_modes モードの違うコンテンツが混ざっている
422 mixed_projects プロジェクトの違うコンテンツが混ざっている
422 automation_template_mode_mismatch 自動化テンプレートのモードがコンテンツのモードと違う
422 idempotency_key_required Idempotency-Key ヘッダーが無い
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
503 automation_dispatch_failed 今すぐ実行の開始に失敗した。登録した自動化は failed になります。同じ Idempotency-Key で再送すると、新しく登録し直して開始します
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/automations" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}'
import requests

body = """{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
    "automation_template_unique": "Tm7pL2xQ9z",
    "reserved_at": "2030-01-02T12:04:05+09:00"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
          "automation_template_unique": "Tm7pL2xQ9z",
          "reserved_at": "2030-01-02T12:04:05+09:00"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/automations");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "auto_unique": "Qw3eRt6yUi",
      "mode": "blogmode",
      "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
      "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
      "run_no": 1,
      "status": "pending",
      "execution_mode": "sequential",
      "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
      "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
      "reserved_at": "2030-01-02T03:04:05Z",
      "executed_at": null,
      "completed_at": null,
      "created_at": "2026-10-21T10:00:00Z"
    },
    {
      "auto_unique": "As4dFg7hJk",
      "mode": "blogmode",
      "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
      "content": { "variation_unique": "Lm2nOp5qRs8t", "title": "My blog title" },
      "run_no": 1,
      "status": "pending",
      "execution_mode": "sequential",
      "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
      "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
      "reserved_at": "2030-01-02T03:04:05Z",
      "executed_at": null,
      "completed_at": null,
      "created_at": "2026-10-21T10:00:00Z"
    }
  ]
}
PATCH › /automations/{auto_unique}

予約日時を変更する

実行待ち(status が pending)の自動化の実行日時を変更します。実行が始まったもの・終了したものは変更できません。

パラメータ
名前 場所 型 必須 既定値 説明
auto_unique パス string 必須 — 自動化の実行のID
reserved_at 本文 string 必須 — 新しい実行日時(未来の日時)。時差つきの ISO 8601 で指定し、時差が無いものは UTC として扱います
レスポンス項目
項目型説明
auto_unique string 自動化の実行のID
mode string moviemode / blogmode / carouselmode
project object プロジェクト {project_unique, project_name}
content.variation_unique string コンテンツのID
content.title string | null タイトル(postmode はコンセプト名)
run_no integer そのコンテンツで何回目の実行か
status string 状態。pending(実行待ち。reserved_at が未来なら予約)/ executing(実行中)/ waiting_confirmation(内容の確認待ち。確認すると続きを実行)/ completed(完了)/ failed(失敗)/ stopped(停止)/ token_shortage(トークン不足で終了)
execution_mode string sequential(1件ずつ実行)/ parallel(同時に実行)
phases object 段階ごとの状態 {setup, step1, step2, step3}。not_started(未着手)/ running(実行中、または止まった段階)/ done(完了。スキップ、および completed した run では自動化の範囲外にした手順も含む)/ error(失敗)
template.setup_template_name string | null 開始時に使ったセットアップテンプレートの名前
template.automation_template_name string | null 開始時に使った自動化テンプレートの名前
reserved_at string | null 予約した実行日時
executed_at string | null 実行を始めた日時
completed_at string | null 終了した日時(completed / failed / stopped / token_shortage のとき)
created_at string 実行を登録した日時
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
404 not_found 自動化が無い、または取得できる範囲外(Automation not found.)
409 automation_not_pending 実行待ち(pending)ではない(実行が始まった、または終了した)
422 validation_error reserved_at が無い・日時として読めない・過去
リクエスト例
curl -X PATCH "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}'
import requests

body = """{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}"""

response = requests.request(
    "PATCH",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "reserved_at": "2031-05-06T07:08:09+09:00"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi")!)
request.httpMethod = "PATCH"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("PATCH", HttpRequest.BodyPublishers.ofString("""
        {
          "reserved_at": "2031-05-06T07:08:09+09:00"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "blogmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
    "run_no": 1,
    "status": "pending",
    "execution_mode": "sequential",
    "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
    "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
    "reserved_at": "2031-05-05T22:08:09Z",
    "executed_at": null,
    "completed_at": null,
    "created_at": "2026-10-21T10:00:00Z"
  }
}
POST › /automations/{auto_unique}/stop

自動化を停止する

画面の停止と同じ操作です。プランに関係なく使えます(プランを変えたあとも止められます)。実行待ち(予約中を含む)と確認待ちは、その場で stopped になります。実行中は停止を依頼し、応答の時点では executing のままで、実行中の手順の区切りで stopped になります(GET /automations/{auto_unique} で確認してください)。終了済みのものは何もせず、そのままの状態を返します。

パラメータ
名前 場所 型 必須 既定値 説明
auto_unique パス string 必須 — 自動化の実行のID
レスポンス項目
項目型説明
auto_unique string 自動化の実行のID
mode string moviemode / blogmode / carouselmode
project object プロジェクト {project_unique, project_name}
content.variation_unique string コンテンツのID
content.title string | null タイトル(postmode はコンセプト名)
run_no integer そのコンテンツで何回目の実行か
status string 状態。pending(実行待ち。reserved_at が未来なら予約)/ executing(実行中)/ waiting_confirmation(内容の確認待ち。確認すると続きを実行)/ completed(完了)/ failed(失敗)/ stopped(停止)/ token_shortage(トークン不足で終了)
execution_mode string sequential(1件ずつ実行)/ parallel(同時に実行)
phases object 段階ごとの状態 {setup, step1, step2, step3}。not_started(未着手)/ running(実行中、または止まった段階)/ done(完了。スキップ、および completed した run では自動化の範囲外にした手順も含む)/ error(失敗)
template.setup_template_name string | null 開始時に使ったセットアップテンプレートの名前
template.automation_template_name string | null 開始時に使った自動化テンプレートの名前
reserved_at string | null 予約した実行日時
executed_at string | null 実行を始めた日時
completed_at string | null 終了した日時(completed / failed / stopped / token_shortage のとき)
created_at string 実行を登録した日時
エラー
ステータスコード発生する条件
404 not_found 自動化が無い、または取得できる範囲外(Automation not found.)
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "blogmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
    "run_no": 1,
    "status": "stopped",
    "execution_mode": "sequential",
    "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
    "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
    "reserved_at": "2030-01-02T03:04:05Z",
    "executed_at": null,
    "completed_at": "2026-10-21T10:05:00Z",
    "created_at": "2026-10-21T10:00:00Z"
  }
}
POST › /automations/{auto_unique}/confirm

確認待ちを承認する

内容の確認待ち(status が waiting_confirmation)で止まっている自動化について、コンテンツの内容を確認済みにし、続き(SNS 用の文章の作成・投稿など)を実行します。画面で内容を確認したときと同じ操作です。成功すると自動化は pending に戻り、すぐに実行が始まります。

パラメータ
名前 場所 型 必須 既定値 説明
auto_unique パス string 必須 — 自動化の実行のID
Idempotency-Key ヘッダー string 任意 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
auto_unique string 自動化の実行のID
mode string moviemode / blogmode / carouselmode
project object プロジェクト {project_unique, project_name}
content.variation_unique string コンテンツのID
content.title string | null タイトル(postmode はコンセプト名)
run_no integer そのコンテンツで何回目の実行か
status string 状態。pending(実行待ち。reserved_at が未来なら予約)/ executing(実行中)/ waiting_confirmation(内容の確認待ち。確認すると続きを実行)/ completed(完了)/ failed(失敗)/ stopped(停止)/ token_shortage(トークン不足で終了)
execution_mode string sequential(1件ずつ実行)/ parallel(同時に実行)
phases object 段階ごとの状態 {setup, step1, step2, step3}。not_started(未着手)/ running(実行中、または止まった段階)/ done(完了。スキップ、および completed した run では自動化の範囲外にした手順も含む)/ error(失敗)
template.setup_template_name string | null 開始時に使ったセットアップテンプレートの名前
template.automation_template_name string | null 開始時に使った自動化テンプレートの名前
reserved_at string | null 予約した実行日時
executed_at string | null 実行を始めた日時
completed_at string | null 終了した日時(completed / failed / stopped / token_shortage のとき)
created_at string 実行を登録した日時
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
404 not_found 自動化が無い、または取得できる範囲外(Automation not found.)
409 automation_not_waiting_confirmation 確認待ち(waiting_confirmation)ではない
409 content_readonly コンテンツがプランのダウングレードで閲覧専用
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
503 automation_dispatch_failed 続きの実行の開始に失敗した。自動化は failed になります(コンテンツは確認済みのままなので、続きは新しく自動化を開始してください)
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "carouselmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My carousel title" },
    "run_no": 1,
    "status": "pending",
    "execution_mode": "parallel",
    "phases": { "setup": "done", "step1": "done", "step2": "done", "step3": "running" },
    "template": { "setup_template_name": null, "automation_template_name": "Weekly carousel" },
    "reserved_at": null,
    "executed_at": "2026-10-21T09:00:00Z",
    "completed_at": null,
    "created_at": "2026-10-21T09:00:00Z"
  }
}

投稿の確認

投稿(ポストモード)の自動化で、投稿前の確認をあり・任意にしたコンテンツの投稿を、承認・すぐ投稿・日時の変更・取り消しします。画面の確認待ちの一覧や確認メールのリンク先と同じ投稿が対象で、同じ規則で動きます。一覧はプランに関係なく使え、操作は Pro プラン以上で使えます。

GET › /post-confirms

確認待ちの投稿一覧

確認メールを送った投稿のうち、予定時刻の前(upcoming)と期限切れ(expired)のものを予定時刻の近い順に取得します。upcoming は承認待ち(awaiting。承認しないと投稿されない)と通知のみ(notice。そのまま投稿される)の投稿です。expired は承認されないまま予定時刻を過ぎて投稿されなかった投稿で、予定時刻から30日間だけ返します。スレッドは最初の投稿を1件として返し、2件目以降は thread に入ります。プランに関係なく使えます。

パラメータ
名前 場所 型 必須 既定値 説明
state クエリ string 任意 — upcoming(予定時刻の前)または expired(期限切れ)で絞り込みます。省略時は両方
project_unique クエリ string 任意 — このプロジェクトの投稿だけを返します
page クエリ integer 任意 1 取得するページ(1から)
per_page クエリ integer 任意 20 1ページの件数(1〜100)
レスポンス項目
項目型説明
data[].schedule_unique string 投稿の予定のID。操作のパスに使います
data[].state string | null upcoming(予定時刻の前)/ expired(期限切れ)。承認・日時の変更などで確認の対象でなくなった投稿は null(操作の応答だけ)
data[].confirm_state string awaiting(承認待ち。承認するまで投稿されない)/ notice(通知のみ。そのまま投稿される)/ confirmed(承認済み)/ none(確認なし)
data[].confirm_mode string コンテンツの確認の設定。required(承認するまで投稿しない)/ optional(承認しなくても投稿する)/ none(確認しない)
data[].can_approve boolean 承認できるか(upcoming で awaiting のとき true)
data[].can_post_now boolean すぐ投稿できるか(expired のとき true)
data[].can_reschedule boolean 日時を変更できるか(expired のとき true)
data[].scheduled_at string 投稿する予定日時
data[].scheduled_at_local string 予定日時(timezone の現地時刻。YYYY-MM-DDTHH:MM:SS)
data[].timezone string 予定を作ったときのタイムゾーン
data[].deadline_at string | null 操作できる期限。upcoming は予定時刻(過ぎると expired)、expired は予定時刻の30日後(過ぎると一覧から消え、操作できない)。state が null なら null
data[].project object プロジェクト {project_unique, project_name}
data[].concept object コンセプト {concept_unique, concept_name}
data[].variation_unique string コンテンツのID
data[].post_unique string 投稿のID(投稿スケジュールの items[].post_unique と同じ)
data[].post_type string 投稿タイプ。assertion(主張)/ knowhow(ノウハウ)/ experience(体験)/ casual(日常)
data[].text string 投稿の本文(スレッドの最初の投稿)
data[].thread[] object スレッドの2件目以降の投稿 {text, image}(順番どおり。スレッドでなければ空の配列)
data[].image object | null 添付する画像 {url, expires_at}(署名付きURL。1時間で失効)。無ければ null
meta.total integer 条件に合う総件数
meta.current_page integer 現在のページ
meta.per_page integer 1ページの件数
meta.last_page integer 最後のページ
エラー
ステータスコード発生する条件
404 not_found プロジェクトが無い、または取得できる範囲外(Project not found.)
422 validation_error パラメータが不正
リクエスト例
curl "https://stepeee.com/public-api/v1/post-confirms?state=upcoming" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/post-confirms?state=upcoming",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-confirms?state=upcoming", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-confirms?state=upcoming")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-confirms?state=upcoming"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-confirms?state=upcoming");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "schedule_unique": "aB3dE5fG7hJ9",
      "state": "upcoming",
      "confirm_state": "awaiting",
      "confirm_mode": "required",
      "can_approve": true,
      "can_post_now": false,
      "can_reschedule": false,
      "scheduled_at": "2026-10-19T13:00:00Z",
      "scheduled_at_local": "2026-10-19T22:00:00",
      "timezone": "Asia/Tokyo",
      "deadline_at": "2026-10-19T13:00:00Z",
      "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
      "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
      "variation_unique": "Vr5Ws7Xt9Yu1",
      "post_unique": "Ps3Qt5Ru7Sv9",
      "post_type": "knowhow",
      "text": "First post of the thread",
      "thread": [
        { "text": "Second post", "image": null },
        { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
      ],
      "image": null
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
POST › /post-schedules/{schedule_unique}/approve

投稿を承認する

承認待ち(upcoming で confirm_state が awaiting)の投稿を承認します。承認した投稿は予定時刻に投稿されます。予定時刻を過ぎた投稿には、すぐ投稿か日時の変更を使ってください。

パラメータ
名前 場所 型 必須 既定値 説明
schedule_unique パス string 必須 — 投稿の予定のID(GET /post-confirms の schedule_unique)
Idempotency-Key ヘッダー string 任意 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
schedule_unique / state / … / image — 確認待ちの投稿一覧の1件と同じ(操作のあとの状態)
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
404 post_schedule_not_found GET /post-confirms に出ない投稿(存在しない・取得できる範囲外・確認の対象でない・承認済み)
409 confirm_expired 予定時刻を過ぎている(すぐ投稿か日時の変更を使う)
409 confirm_not_pending 承認待ちではない(通知のみ notice の投稿など)
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-19T13:00:00Z",
    "scheduled_at_local": "2026-10-19T22:00:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
POST › /post-schedules/{schedule_unique}/post-now

期限切れの投稿をすぐ投稿する

期限切れ(expired)の投稿を、いまから1分後の予定にして承認済みにします(まもなく投稿されます)。スレッドの2件目以降も同じだけ時刻をずらします。期限切れの投稿にだけ使えます。

パラメータ
名前 場所 型 必須 既定値 説明
schedule_unique パス string 必須 — 投稿の予定のID(GET /post-confirms の schedule_unique)
allow_close_slot 本文 boolean 任意 false 同じコンテンツの他の予約との間隔が最小間隔(90分)より短くなっても実行するなら true
Idempotency-Key ヘッダー string 任意 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
schedule_unique / state / … / image — 確認待ちの投稿一覧の1件と同じ(操作のあとの状態)
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
403 resource_readonly コンテンツがプランのダウングレードで閲覧専用
404 post_schedule_not_found GET /post-confirms に出ない投稿(存在しない・取得できる範囲外・確認の対象でない・承認済み)
409 confirm_not_expired 期限切れではない(予定時刻の前は承認を使う)
409 schedule_close_to_other_slot allow_close_slot が false で、同じコンテンツの他の予約との間隔が90分より短くなる。details に min_gap_minutes(最小間隔の分数)・timezone・conflicts(近い予約 {scheduled_at_local, minutes_apart} の配列)
409 schedule_locked 投稿中・投稿済み、または予定時刻の前後2分以内で投稿の処理と重なる
409 schedule_processing 投稿の処理と同時に操作され、変更できなかった
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 validation_error allow_close_slot が true / false ではない
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "allow_close_slot": true
}'
import requests

body = """{
  "allow_close_slot": true
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "allow_close_slot": true
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "allow_close_slot": true
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "allow_close_slot": true
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "allow_close_slot": true
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-21T12:01:00Z",
    "scheduled_at_local": "2026-10-21T21:01:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
PATCH › /post-schedules/{schedule_unique}

期限切れの投稿の日時を変更する

期限切れ(expired)の投稿の予定日時を変更して承認済みにします(指定した日時に投稿されます)。スレッドの2件目以降も同じだけ時刻をずらします。日時を変更できるのは期限切れの投稿だけです。

パラメータ
名前 場所 型 必須 既定値 説明
schedule_unique パス string 必須 — 投稿の予定のID(GET /post-confirms の schedule_unique)
scheduled_at 本文 string 必須 — 新しい予定日時(未来の日時)。時差つきの ISO 8601 で指定します(2026-10-21T09:30:00+09:00、2026-10-21T00:30:00Z など。秒は省略でき、秒未満は切り捨て)。投稿の timezone の時刻に直して保存します
allow_close_slot 本文 boolean 任意 false 同じコンテンツの他の予約との間隔が最小間隔(90分)より短くなっても実行するなら true
レスポンス項目
項目型説明
schedule_unique / state / … / image — 確認待ちの投稿一覧の1件と同じ(操作のあとの状態)
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
403 resource_readonly コンテンツがプランのダウングレードで閲覧専用
404 post_schedule_not_found GET /post-confirms に出ない投稿(存在しない・取得できる範囲外・確認の対象でない・承認済み)
409 confirm_not_expired 期限切れではない(予定時刻の前は承認を使う)
409 schedule_close_to_other_slot allow_close_slot が false で、同じコンテンツの他の予約との間隔が90分より短くなる。details に min_gap_minutes(最小間隔の分数)・timezone・conflicts(近い予約 {scheduled_at_local, minutes_apart} の配列)
409 schedule_locked 投稿中・投稿済み、または予定時刻の前後2分以内で投稿の処理と重なる
409 schedule_processing 投稿の処理と同時に操作され、変更できなかった
422 confirm_reschedule_past scheduled_at が現在以前
422 validation_error scheduled_at が無い・時差が無い・日時として読めない、または allow_close_slot が true / false ではない
リクエスト例
curl -X PATCH "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}'
import requests

body = """{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}"""

response = requests.request(
    "PATCH",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "scheduled_at": "2026-10-22T09:30:00-05:00",
    "allow_close_slot": false
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9")!)
request.httpMethod = "PATCH"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("PATCH", HttpRequest.BodyPublishers.ofString("""
        {
          "scheduled_at": "2026-10-22T09:30:00-05:00",
          "allow_close_slot": false
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-22T14:30:00Z",
    "scheduled_at_local": "2026-10-22T23:30:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
DELETE › /post-schedules/{schedule_unique}

投稿を取り消す

投稿を取り消します(予定時刻の前でも、期限切れでも)。投稿・スレッドの2件目以降・予約をまとめて削除します。元に戻せません。

パラメータ
名前 場所 型 必須 既定値 説明
schedule_unique パス string 必須 — 投稿の予定のID(GET /post-confirms の schedule_unique)
レスポンス項目
項目型説明
schedule_unique string 取り消した投稿の予定のID
deleted boolean 常に true
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
403 resource_readonly コンテンツがプランのダウングレードで閲覧専用
404 post_schedule_not_found GET /post-confirms に出ない投稿(存在しない・取得できる範囲外・確認の対象でない・承認済み)
409 post_posting_locked 投稿中(スレッドの2件目以降を含む)で取り消せない
リクエスト例
curl -X DELETE "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "deleted": true
  }
}

Webhook

登録した URL へ、自動化や投稿の出来事を JSON で送ります。完了・失敗・確認待ちを、APIを繰り返し呼ばずに知りたいときに使います。登録と送信テストは Pro プラン以上、一覧と削除はプランに関係なく使えます。

GET › /webhooks

通知先一覧

登録した通知先を登録順に取得します(最大5件。ページングはありません)。署名用のシークレットは含みません。プランに関係なく使えます。

レスポンス項目
項目型説明
data[].webhook_unique string 通知先のID
data[].url string 送信先の URL
data[].events string[] 受け取るイベント名
data[].description string | null メモ
data[].is_active boolean いまイベントを送る状態か。持ち主が Pro プラン以上(チームのメンバーはチームのオーナーが Team プラン)のとき true。false のあいだに起きた出来事は送りません
data[].last_delivery_at string | null 直近の送信を試みた日時(送信テストは含みません)
data[].last_delivery_status string | null 直近の送信の結果。succeeded(成功)/ failed(失敗)。まだ送っていなければ null
data[].last_response_status integer | null 直近の送信で受け取った HTTP ステータス(応答が無ければ null)
data[].last_error string | null 直近の送信が失敗した理由。値は送信テストの error と同じ
data[].created_at string 作成日時
リクエスト例
curl "https://stepeee.com/public-api/v1/webhooks" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/webhooks",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": [
    {
      "webhook_unique": "Xk3pQ9vLm2Ta",
      "url": "https://example.com/hooks/stepeee",
      "events": ["automation.completed", "post.published"],
      "description": "production hook",
      "is_active": true,
      "last_delivery_at": "2026-10-21T12:01:00Z",
      "last_delivery_status": "failed",
      "last_response_status": 503,
      "last_error": "non_2xx_response",
      "created_at": "2026-10-20T09:00:00Z"
    }
  ]
}
POST › /webhooks

通知先を登録する

通知先を登録します。応答の secret(署名用のシークレット)はこの応答でだけ返し、あとから表示する方法はありません。失くした場合は、通知先を削除して登録し直してください。登録できるのは5件までです。登録する前に起きた出来事は送りません。

パラメータ
名前 場所 型 必須 既定値 説明
url 本文 string 必須 — 送信先の URL(https のみ、ポートは 443 のみ(省略可)、2048文字以内)。ユーザー名・パスワードを含む URL は登録できません。内部・予約済みのアドレス(プライベート IP・ループバック・リンクローカル・localhost など)に解決される URL と、名前解決できない URL は登録できません
events 本文 string[] 必須 — 受け取るイベント名(イベントの一覧から1件以上、重複不可)
description 本文 string | null 任意 — メモ(100文字以内)
Idempotency-Key ヘッダー string 任意 — 操作ごとに作った一意な文字列(1〜255文字の表示可能な ASCII)。同じキーで同じ内容を再送すると、最初の応答をそのまま返します(共通仕様の Idempotency-Key を参照)
レスポンス項目
項目型説明
webhook_unique string 通知先のID
url string 送信先の URL
events string[] 受け取るイベント名
description string | null メモ
is_active boolean いまイベントを送る状態か。持ち主が Pro プラン以上(チームのメンバーはチームのオーナーが Team プラン)のとき true。false のあいだに起きた出来事は送りません
last_delivery_at string | null 直近の送信を試みた日時(送信テストは含みません)
last_delivery_status string | null 直近の送信の結果。succeeded(成功)/ failed(失敗)。まだ送っていなければ null
last_response_status integer | null 直近の送信で受け取った HTTP ステータス(応答が無ければ null)
last_error string | null 直近の送信が失敗した理由。値は送信テストの error と同じ
created_at string 作成日時
secret string 署名用のシークレット(whsec_ で始まる)。この応答でだけ返します
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
409 webhook_limit_reached すでに5件登録している
409 idempotency_request_in_progress 同じ Idempotency-Key のリクエストがまだ処理中
422 validation_error 入力が不正(https ではない URL、443 以外のポート、ユーザー名・パスワードを含む URL、内部のアドレスに解決される・名前解決できない URL、知らないイベント名、イベント名の重複など)
422 idempotency_key_invalid Idempotency-Key が1〜255文字の表示可能な ASCII ではない
422 idempotency_key_reused 同じ Idempotency-Key を別の内容のリクエストに使った
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/webhooks" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}'
import requests

body = """{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/webhooks",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "url": "https://example.com/hooks/stepeee",
    "events": ["automation.completed", "post.published"],
    "description": "production hook"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "url": "https://example.com/hooks/stepeee",
          "events": ["automation.completed", "post.published"],
          "description": "production hook"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/webhooks");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "webhook_unique": "Xk3pQ9vLm2Ta",
    "url": "https://example.com/hooks/stepeee",
    "events": ["automation.completed", "post.published"],
    "description": "production hook",
    "is_active": true,
    "last_delivery_at": null,
    "last_delivery_status": null,
    "last_response_status": null,
    "last_error": null,
    "created_at": "2026-10-21T12:00:00Z",
    "secret": "whsec_5f0c2a9e8b7d4c3a1f6e9d8c7b6a5f4e3d2c1b0a9f8e7d6c"
  }
}
DELETE › /webhooks/{webhook_unique}

通知先を削除する

通知先を削除します。まだ送っていないイベントと再試行待ちのイベントも送りません。プランに関係なく使えます。

パラメータ
名前 場所 型 必須 既定値 説明
webhook_unique パス string 必須 — 通知先のID
レスポンス項目
項目型説明
webhook_unique string 削除した通知先のID
deleted boolean 常に true
エラー
ステータスコード発生する条件
404 not_found 通知先が無い、または他のユーザーの通知先
リクエスト例
curl -X DELETE "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "webhook_unique": "Xk3pQ9vLm2Ta",
    "deleted": true
  }
}
POST › /webhooks/{webhook_unique}/test

送信をテストする

webhook.test イベントをその場で1回送り、結果を返します。本番と同じ署名・ヘッダー・送信先の検査で送るので、受け取る側の署名の検証を確かめるときに使えます。再試行はせず、last_delivery_at などにも記録しません。

パラメータ
名前 場所 型 必須 既定値 説明
webhook_unique パス string 必須 — 通知先のID
レスポンス項目
項目型説明
delivered boolean 2xx の応答を受け取ったか
response_status integer | null 受け取った HTTP ステータス(応答が無ければ null)
error string | null 失敗の理由。url_blocked(https ではない・443 以外のポート・ユーザー名とパスワードを含む、または送信の直前に内部のアドレスに解決された・名前解決できなかった)/ timeout(5秒以内に応答が無かった)/ connection_failed(接続・TLS に失敗した)/ non_2xx_response(2xx 以外の応答。リダイレクトも失敗として扱い、追いません)。成功したときは null
エラー
ステータスコード発生する条件
403 plan_required APIキーの持ち主が Pro プラン未満
403 team_plan_lost チームのメンバーで、チームのオーナーが Team プランでなくなった
404 not_found 通知先が無い、または他のユーザーの通知先
リクエスト例
curl -X POST "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
レスポンス例
{
  "data": {
    "delivered": false,
    "response_status": 500,
    "error": "non_2xx_response"
  }
}

イベント

通知先に登録したイベントが起きると、登録した URL へ POST します。送るのは、通知先の持ち主がその時点で取得できるプロジェクトの出来事だけです。出来事は1分ごとに確かめるため、届くまで数分かかることがあります。通知先を登録する前の出来事と、持ち主が Pro プラン未満のあいだ(チームのメンバーはチームのオーナーが Team プランでないあいだ)の出来事は送りません。

イベント意味
automation.waiting_confirmation自動化(動画・ブログ・カルーセル)が内容の確認待ちで止まった
automation.completed自動化が最後まで完了した
automation.failed自動化が失敗(failed)・停止(stopped)・トークン不足(token_shortage)で終わった
post.publishedSNS へ投稿した(動画・ブログ・カルーセルの投稿結果が success になった、投稿(ポストモード)を X に投稿した)。手動の投稿も自動化の投稿も対象です
post.failed投稿に失敗した(動画・ブログ・カルーセルの投稿結果が failed・partial_success になった、投稿(ポストモード)が投稿や本文の作成に失敗して見送られた)
post.confirm_required投稿(ポストモード)の承認待ちの投稿が GET /post-confirms に出た(承認するまで投稿されない)
webhook.test送信テスト(POST /webhooks/{webhook_unique}/test)。通知先に登録するイベントには使えません

送信する本文

本文は {id, type, created_at, data} の JSON(UTF-8)です。id はイベントのID(evt_ で始まる)、type はイベント名、created_at はイベントを記録した日時です。同じイベントを再送するときは本文は同じで、署名の t だけが変わります。data の形はイベントごとに次のとおりです。

イベントdata の形
automation.*GET /automations の data[] の1件と同じ形。status は automation.waiting_confirmation が waiting_confirmation、automation.completed が completed、automation.failed が failed / stopped / token_shortage
post.published
post.failed
動画・ブログ・カルーセル: GET /projects/{project_unique}/publications の data[] の1件に project を加えた形。post.failed の status は failed または partial_success で、error_code に投稿結果と同じ失敗のコードが入ります。投稿(ポストモード): 同じ形に schedule_unique を加えたもの。publication_unique は投稿のID(本文の作成に失敗した予定では null)、content.title はコンセプト名、account は null、error_code は token_expired / api_error / not_found / insufficient_token / no_x_account / node_ws_timeout です。is_automation で自動化の投稿かどうかを区別できます
post.confirm_requiredGET /post-confirms の data[] の1件と同じ形で、イベントを記録した時点の値です。通知のみ(notice)の投稿では送りません。image の署名付きURLは記録から1時間で失効するので、遅れて届いた場合は GET /post-confirms で取り直してください。同じ予定の投稿が作り直されると、新しい post_unique で再び届きます
webhook.test{"webhook_unique": "…"}

本文の例

automation.failed
{
  "id": "evt_Q2x8Lr0aZk9MvB3pT7cYw1Nd",
  "type": "automation.failed",
  "created_at": "2026-10-21T12:01:03Z",
  "data": {
    "auto_unique": "a8Kd02LmQz",
    "mode": "blogmode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Vb3Nq8Ls1Kd0", "title": "How to start" },
    "run_no": 2,
    "status": "token_shortage",
    "execution_mode": "sequential",
    "phases": { "setup": "done", "step1": "done", "step2": "running", "step3": "not_started" },
    "template": { "setup_template_name": "Default", "automation_template_name": null },
    "reserved_at": null,
    "executed_at": "2026-10-21T11:40:00Z",
    "completed_at": "2026-10-21T12:00:41Z",
    "created_at": "2026-10-21T11:39:58Z"
  }
}
post.published
{
  "id": "evt_7hT2mWq9Zp3LxR8cVb1Nk5Ds",
  "type": "post.published",
  "created_at": "2026-10-21T12:02:10Z",
  "data": {
    "publication_unique": "Lg4Hs9Pq2Wx7",
    "mode": "moviemode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Mv8Kq2Zt5Rb1", "title": "5 tips" },
    "platform": "youtube",
    "account": { "account_unique": "Ac1Bd2Ef3Gh4", "name": "My Channel" },
    "status": "success",
    "post_url": "https://www.youtube.com/watch?v=xxxxxxxx",
    "error_code": null,
    "is_automation": true,
    "posted_at": "2026-10-21T12:01:55Z",
    "created_at": "2026-10-21T12:01:20Z"
  }
}
post.failed
{
  "id": "evt_9Zq1Lm4Xc7Vb2Nk8Ds3Pt6Wr",
  "type": "post.failed",
  "created_at": "2026-10-21T09:00:40Z",
  "data": {
    "publication_unique": "Pp5Kd8Lw2Qz9",
    "mode": "postmode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Pv4Lk9Qz2Wx6", "title": "My X concept" },
    "platform": "x",
    "account": null,
    "status": "failed",
    "post_url": null,
    "error_code": "token_expired",
    "is_automation": true,
    "posted_at": null,
    "created_at": "2026-10-20T21:00:12Z",
    "schedule_unique": "Sc6Hj1Kl8Mn3"
  }
}
post.confirm_required
{
  "id": "evt_3Kd8Lq2Wz7Xc1Vb9Nm4Pt6Rs",
  "type": "post.confirm_required",
  "created_at": "2026-10-19T08:15:02Z",
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": "upcoming",
    "confirm_state": "awaiting",
    "confirm_mode": "required",
    "can_approve": true,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-19T13:00:00Z",
    "scheduled_at_local": "2026-10-19T22:00:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": "2026-10-19T13:00:00Z",
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null }
    ],
    "image": { "url": "https://...", "expires_at": "2026-10-19T09:15:02Z" }
  }
}
webhook.test
{
  "id": "evt_Q2x8Lr0aZk9MvB3pT7cYw1Nd",
  "type": "webhook.test",
  "created_at": "2026-10-21T12:00:00Z",
  "data": { "webhook_unique": "Xk3pQ9vLm2Ta" }
}

送信するヘッダー

ヘッダー説明
Content-Type: application/json本文の形式
Stepeee-Signature: t=1792584000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd署名。t は送信した時刻(UNIX 秒)、v1 は署名(HMAC-SHA256 の16進)です。検証の方法は下の署名の検証を見てください
Stepeee-Event-Id: evt_Q2x8Lr0aZk9MvB3pT7cYw1NdイベントのID(本文の id と同じ)。再送でも変わらないので、重複を除くのに使います
Stepeee-Event-Type: automation.failedイベント名(本文の type と同じ)
User-Agent: Stepeee-Webhooks/1.0送信元

署名の検証

受け取った本文が Stepeee から送られ、書き換えられていないことを確かめるため、次の手順で署名を検証してください。

  1. Stepeee-Signature ヘッダーを「,」で区切り、t= の値(UNIX 秒)と v1= の値(16進64文字)を取り出します。
  2. 受け取った本文をバイト列のまま使い(JSON を読み込んで作り直さない)、t の値・「.」・本文をつなげた文字列を作ります。
  3. 登録したときに受け取った secret(whsec_ を含む全体)を鍵にして HMAC-SHA256 を計算し、小文字の16進にします。
  4. 計算した値と v1 を、かかる時間が内容によって変わらない比較(Python の hmac.compare_digest、PHP の hash_equals など)で比べます。一致しなければ 400 などを返し、処理しません。
  5. 古いリクエストの再送を防ぐため、t が現在時刻から5分以上ずれていたら拒否することをおすすめします。
  6. 本文の id で、すでに処理したイベントを除きます。

検証のコード例

import hmac, hashlib, time

def verify(body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, v1 = parts.get("t"), parts.get("v1")
    if not t or not v1 or abs(time.time() - int(t)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

# Flask: verify(request.get_data(), request.headers["Stepeee-Signature"], SECRET)
const crypto = require("crypto");

function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = parts.t, v1 = parts.v1;
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.`).update(rawBody).digest("hex");
  return v1.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

// Express: receive the body as raw bytes with express.raw()
app.post("/hooks/stepeee", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.get("Stepeee-Signature"), process.env.STEPEEE_WEBHOOK_SECRET)) return res.sendStatus(400);
  const event = JSON.parse(req.body.toString("utf8"));
  res.sendStatus(200);
});
function verifyStepeeeSignature(string $body, string $header, string $secret, int $tolerance = 300): bool
{
    $parts = [];
    foreach (explode(',', $header) as $part) {
        [$k, $v] = array_pad(explode('=', $part, 2), 2, '');
        $parts[$k] = $v;
    }
    if (! isset($parts['t'], $parts['v1']) || abs(time() - (int) $parts['t']) > $tolerance) {
        return false;
    }
    $expected = hash_hmac('sha256', $parts['t'].'.'.$body, $secret);

    return hash_equals($expected, $parts['v1']);
}

$ok = verifyStepeeeSignature(file_get_contents('php://input'), $_SERVER['HTTP_STEPEEE_SIGNATURE'] ?? '', $secret);
# BODY: raw request body, T: t from Stepeee-Signature, SECRET: whsec_...
printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}'
# The signature is valid if the output equals v1

成功の条件と再試行

5秒以内に 2xx を返すと、届いたものとして扱います。応答の本文は読まず、リダイレクトは追いません。2xx 以外の応答・タイムアウト・接続の失敗は再試行し、最初の送信を含めて最大8回送ります。次に送るまでの間隔は 1分 → 5分 → 30分 → 2時間 → 4時間 → 6時間 → 10時間 で、8回とも失敗したらそのイベントは送りません。送る時点で持ち主が Pro プラン未満(チームのメンバーはチームのオーナーが Team プランでない)なら、そのイベントは送りません。送る時点で持ち主がそのプロジェクトにアクセスできなくなっている(チームから外れた・権限を外された・プロジェクトが削除された)場合も送りません。

2xx を受け取るまで同じイベントを再送するため、同じイベントが2回以上届くことがあります。Stepeee-Event-Id(本文の id)で重複を除いてください。届く順番は保証しません。重い処理は 2xx を返したあとで行ってください。

送信先の条件

送信先は https の URL だけで、ポートは 443 に限ります。ユーザー名・パスワードを含む URL も登録できません。内部・予約済みのアドレス(プライベート IP・ループバック・リンクローカル・localhost など)に解決される URL と、名前解決できない URL は登録できません。送る直前にも名前を解決して確かめ、内部のアドレスに解決された場合は送らずに url_blocked として失敗にします。