audio_urlstring必須書き起こす音声です。アップロードした MP3 か WAV、または MP3、WAV、M4A、FLAC、OGG、Opus、AAC、MP4、MKV の公開 URL を指定します。1 秒〜2 時間。この音声の長さが課金対象です。
- デフォルト値
- 指定なし
- 制約
- minLength:1format:"uri"contentMediaType:["audio/mpeg","audio/wav"]
Grok STT は xAI の speech-to-text で、音声 URL を送ると書き起こしテキストに単語単位のタイミングと検出言語が付いて返ります。25 言語、チャンネル別の書き起こし、キーワードのヒントに対応します。
例は、選択中のエンドポイントの公開パラメーター定義から作っています。API キーとサンプル素材を差し替えて、ご自身のサーバーから送信してください。
SDK・連携https://api.spicyapi.ai/api/v1/jobs/createTaskAPI キーはサーバーの環境変数 SPICY_API_KEY に保存します。Bearer 認証を使用し、JSON リクエストには Content-Type: application/json を指定してください。
Authorization: Bearer $SPICY_API_KEY# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
-d '{
"model": "xai/grok-stt/speech-to-text",
"input": {
"audio_url": "https://example.com/reference.mp3"
}
}'
# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"このモデルの入力スキーマから生成した例です。API はどのリクエストも、同じスキーマで検証します。
これらのフィールドは、リクエスト本文の input オブジェクトに指定します。名前と型は API と一致します。デフォルト値の指定がない項目に、デフォルト値があると想定しないでください。
このモデルには項目どうしの依存関係があります。「条件付きで必須」の項目は、ほかの入力の内容によって必須になります。詳しい条件は、下の JSON Schema で確認してください。
audio_urlstring必須書き起こす音声です。アップロードした MP3 か WAV、または MP3、WAV、M4A、FLAC、OGG、Opus、AAC、MP4、MKV の公開 URL を指定します。1 秒〜2 時間。この音声の長さが課金対象です。
multichannelboolean任意オンにすると、マルチチャンネルのファイル(最大 8 チャンネル)をチャンネルごとに別々に書き起こし、チャンネル順に 1 行ずつ返します。話者が別々のチャンネルに録音されているときに使います。既定はオフです。料金には影響しません。
filler_wordsboolean任意オンにすると um や uh などのフィラーを書き起こしに残します。オフ(既定)では取り除きます。料金には影響しません。
keytermsarray<object>任意書き起こしで優先させたい単語や短いフレーズを最大 100 個(各 50 文字まで)指定します。名前、ブランド名、専門用語向けです。料金には影響しません。
keyterms[].termstringオブジェクト内で必須A word or short phrase, up to 50 characters.
text_normalizationboolean任意オンにすると、話された数字、価格、日付、単位を算用数字で書きます(言葉ではなく「$1,250」「March 14」)。language が必要です。既定はオフ。料金には影響しません。
languagestring条件付きで必須話されている言語の言語コードです。空にすると自動判定され、どちらの場合も対応言語の発話は書き起こされます。text_normalization がオンのときは必須です。料金には影響しません。
"ar""cs""da""nl""en""fil""fr""de""hi""id""it""ja""ko""mk""ms""fa""pl""pt""ro""ru""es""sv""th""tr""vi"{
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"text_normalization": {
"const": true
}
},
"required": [
"text_normalization"
]
},
"then": {
"required": [
"language"
]
}
}
],
"properties": {
"audio_url": {
"contentMediaType": [
"audio/mpeg",
"audio/wav"
],
"description": "Audio to transcribe: an uploaded MP3 or WAV, or a public URL to a common audio or video format. 1 second to 2 hours.",
"format": "uri",
"minLength": 1,
"type": "string",
"x-ui": {
"accept": [
"audio/mpeg",
"audio/wav",
"video/mp4"
],
"max_size_mb": 90,
"order": 100,
"primary": true,
"widget": "upload"
}
},
"filler_words": {
"default": false,
"description": "Keep filler words such as um and uh in the transcript.",
"type": "boolean",
"x-ui": {
"order": 60,
"widget": "switch"
}
},
"keyterms": {
"default": [],
"description": "Names and terms to spell the way you list them, up to 100.",
"items": {
"additionalProperties": false,
"properties": {
"term": {
"description": "A word or short phrase, up to 50 characters.",
"maxLength": 50,
"minLength": 1,
"type": "string"
}
},
"required": [
"term"
],
"type": "object"
},
"maxItems": 100,
"type": "array",
"x-ui": {
"order": 70,
"widget": "object-list"
}
},
"language": {
"description": "Spoken language. Leave empty to detect it; required when text_normalization is on.",
"enum": [
"ar",
"cs",
"da",
"nl",
"en",
"fil",
"fr",
"de",
"hi",
"id",
"it",
"ja",
"ko",
"mk",
"ms",
"fa",
"pl",
"pt",
"ro",
"ru",
"es",
"sv",
"th",
"tr",
"vi"
],
"type": "string",
"x-ui": {
"enum_labels": {
"ar": "Arabic",
"cs": "Czech",
"da": "Danish",
"de": "German",
"en": "English",
"es": "Spanish",
"fa": "Persian",
"fil": "Filipino",
"fr": "French",
"hi": "Hindi",
"id": "Indonesian",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"mk": "Macedonian",
"ms": "Malay",
"nl": "Dutch",
"pl": "Polish",
"pt": "Portuguese",
"ro": "Romanian",
"ru": "Russian",
"sv": "Swedish",
"th": "Thai",
"tr": "Turkish",
"vi": "Vietnamese"
},
"order": 90,
"widget": "select"
}
},
"multichannel": {
"default": false,
"description": "Transcribe each channel separately, one line per channel. Turn on when speakers are on separate channels.",
"type": "boolean",
"x-ui": {
"order": 50,
"widget": "switch"
}
},
"text_normalization": {
"default": false,
"description": "Write spoken numbers, prices, dates and units in digits. Needs language.",
"type": "boolean",
"x-ui": {
"order": 80,
"widget": "switch"
}
}
},
"required": [
"audio_url"
],
"type": "object",
"x-pricing": {
"billingMode": "duration_capped",
"variantFields": []
}
}HTTP 202 はタスクを受け付けたという意味で、生成が終わったという意味ではありません。返ってきた taskId を保存し、そのタスクの状態を問い合わせてください。結果を待っている間に、同じ内容でタスクを作り直さないでください。
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3
{
"code": 200,
"msg": "success",
"request_id": "req_example_create",
"data": {
"taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
"state": "queued",
"estimatedCost": "0.750000"
}
}受理レスポンスには今回の概算料金が含まれるため、アプリのタスク履歴と請求画面に同じ金額を表示できます。
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
--data-urlencode "taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"ポーリングは約 2 秒間隔から始め、徐々に間隔を延ばします。終了状態になったら止めてください。通信が切れたときも、元の taskId で状態を確認します。作成をやり直すときは、同じ冪等キーと同じ本文をそのまま使い回してください。
import { verifyWebhook } from "@spicyapi/sdk";
// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
const { payload } = verifyWebhook({
rawBody: req.body,
timestamp: req.header("X-Webhook-Timestamp"),
signature: req.header("X-Webhook-Signature"),
payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
secret: process.env.SPICY_WEBHOOK_SECRET,
});
res.status(200).end();
void handleFinishedTask(payload);
});タスク作成時に callBackUrl を渡せば、完了したレコードが POST で届きます——ポーリングは一切不要です。配信には毎回 X-Webhook-Timestamp、X-Webhook-Signature、X-Webhook-Payload-Version が付きます。署名は taskId.timestamp.sha256(body) に対する HMAC-SHA256(base64)なので、生のバイト列で検証してください。JSON を解析して再度文字列化するとバイト列が変わり、検証は必ず失敗します。失敗した配信は再送されるため同じ taskId が二度届くことがあります。ハンドラーは冪等に。まず 2xx を返し、処理はその後で——応答が遅いと配信失敗として扱われます。
output を読むのは、state が succeeded のときだけにしてください。失敗したときは errorCode、errorMessage、request_id を手がかりに調べます。例に出ている料金や状態は、実際の請求ではありません。
{
"code": 200,
"msg": "success",
"request_id": "req_example_record",
"data": {
"taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
"model": "xai/grok-stt/speech-to-text",
"state": "succeeded",
"output": {
"text": "…"
},
"cost": "0.750000",
"settled": true,
"createdAt": "2026-08-28T12:00:00Z",
"completedAt": "2026-08-28T12:00:30Z"
}
}利用可能なファイルは assets[].url からそのまま開くか、ダウンロードできます。API の Authorization ヘッダーは不要です。署名付き URL は expiresAt で失効しますが、保存期間内であればタスクを再取得することで更新できます。処理中または利用できないファイルに URL はありません。署名付き URL は非公開情報として扱ってください。
アプリ、ターミナル、AI アシスタント、ビジュアルワークフローで SpicyAPI を活用。接続ガイドを選んでください。
上のコードを書く必要はありません。MCP サーバーを 1 回接続すれば、MCP に対応するエージェント(Claude Code、Codex、Cursor、Windsurf、VS Code、Gemini CLI、Cline、LibreChat)がこのモデルを名前で実行できます。シェルから 1 つのコマンドで実行することもできます。
Use xai/grok-stt/speech-to-text to generate a portrait of a dancer under neon light, and save it to ./out/.
エージェントは公開カタログからモデルを引き、ローカルファイルを代わりにアップロードし、正確な見積もりと上限額を示して確認を待ちます。承認するまで課金は発生しません。
claude mcp add spicyapi -e SPICY_API_KEY=$SPICY_API_KEY \
-- npx --yes --package=@spicyapi/mcp spicyapi-mcp
npx skills add spicyapi-ai/spicy-skill1 行目でツールを、2 行目で Skill を渡します。Skill は使い方の取り決めです——課金の前に見積もりを取り、ローカルファイルはバイト列を貼らずにアップロードし、完成した成果物の URL を推測せずに読む。ほかのクライアントも同じサーバーをそれぞれの設定ファイルから使います。開発者向けページをご覧ください。
npx @spicyapi/cli tasks create --model xai/grok-stt/speech-to-text \
--input-json '{"audio_url":"https://example.com/reference.mp3"}' \
--wait入力は上の例と同じ、このエンドポイント固有のスキーマに従います。--wait はタスクの完了までポーリングして結果を表示します。CI では --yes を追加すると確認を省略できます。先に SPICY_API_KEY を設定してください。API、CLI、MCP サーバーで同じキーを使えます。
npx @spicyapi/cli files upload ./poster.png
# -> spicy://uploads/01k3m8x9q2z4v7n5p6r8s0t1w3
npx @spicyapi/cli tasks create --model xai/grok-stt/speech-to-text \
--input-json '{"audio_url":"spicy://uploads/01k3m8x9q2z4v7n5p6r8s0t1w3"}' \
--waitリクエストが受け取るのは URL であってバイト列ではありません。先にアップロードし、出力される spicy:// URI を渡してください。上のフィールド名はこのエンドポイントのスキーマから取ったものです。MCP 経由のエージェントはこの手順を代わりに済ませます——前述の一文が ./poster.png をそのまま指せるのはそのためです。公開 HTTPS で参照できるメディアならアップロードは不要です。
npx @spicyapi/cli tasks create --model xai/grok-stt/speech-to-text \
--input-json '{…}' --retention 1h --wait
npx @spicyapi/cli tasks get $TASK_ID # read back the retention that applied--retention は保持期間を短くするだけです——30m、1h、7d、あるいは 0 なら終了と同時に削除。実際に効くのはリクエスト・アカウント設定・プラットフォーム上限のうち最も短い値なので、指定した数値が通った前提で進めず、タスクレコードから読み戻してください。アカウントの許容より長い値を渡しても何も起きません。
ComfyUI Manager か下のコマンドで SpicyAPI ノードをインストールしたら、キャンバスで Grok STT · Speech to Text を検索してください。このノードにはこのページと同じオプションがあり、実行前に価格が表示されます。
cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi埋め込みパネルはこのページと同じスキーマを参照するため、API 仕様とのずれを防げます。ドキュメント内の検索対象にする場合は、/api/embed/models/ の JSON を取得して描画してください。
<iframe src="https://spicyapi.ai/embed/ja/models/grok-stt/api?model=xai%2Fgrok-stt%2Fspeech-to-text" width="100%" height="560" loading="lazy" title="リクエスト例" style="border:1px solid rgba(0,0,0,.12)"></iframe>