Tuneping API v1
インターネットラジオ局がいま流している曲と、過去に流した曲を返す JSON API です。ベース URL は https://api.tuneping.com/v1。メタデータのみ: 各ストリームの公開タイトル行を読み取るだけで、音声には一切触れません。
クイックスタート
いま Madonna を流しているのはどの局?
curl "https://api.tuneping.com/v1/now-playing/search?q=madonna&limit=3"
ID がわかっている局で再生中の曲(ID は Radio Browser の局 UUID です):
curl "https://api.tuneping.com/v1/stations/159824f0-5475-4263-bcc8-59a48a213896/now-playing"
局が直近 24 時間に流した曲(履歴付きのキーが必要です。Developer プラン以上):
curl -H "Authorization: Bearer tp_live_…" \
"https://api.tuneping.com/v1/stations/159824f0-5475-4263-bcc8-59a48a213896/history"
レスポンスはすべて JSON です。エラーは application/problem+json です(エラーを参照)。不明なクエリパラメーターは無視せずに 400 で拒否するため、タイプミスはすぐに表面化します。
キーの取得
tuneping.com/signup からセルフサービスで取得できます。メールアドレスを入力し、届いたリンクを 60 分以内に開くと、キーが一度だけ表示されます。同じ 2 つのステップは API としても使えます。POST /v1/signup に {"email": "…", "plan": "free|developer|pro"} を送ると 202 が返り、メールが送信されます。リンクに含まれる {"token": "…"} を POST /v1/signup/verify に送ると、201 でキーが返ります。Free ではこれ以上何も必要ありません。Developer と Pro は、レスポンス内のリンクから Stripe Checkout に進みます。支払いから 1 分以内にオーナーのプランが切り替わり、そのオーナーのすべてのキーに反映されます。
キーを紛失した場合は、同じアドレスで再登録してください。キーがローテーションされ、古いキーは 24 時間使えます。有効なキーは Free と Developer で 1 つ、Pro で 5 つ、Business で 20 個です。さらに、どのプランでも tp_test_ キーを 1 つ、ポータルの公開までは依頼に応じて発行します。
認証
キーは Bearer トークンとして、または X-Api-Key で送信します。
Authorization: Bearer tp_live_a1b2c3…
X-Api-Key: tp_live_a1b2c3…
キーは tp_live_ または tp_test_ で始まり、その後に 43 文字が続きます。キーのないリクエストは匿名として扱われ、IP アドレスごとに制限されます。形式が不正なキー、不明なキー、失効したキーは、匿名なら利用できたエンドポイントであっても、即座に 401 を返します。以下で キー と記したエンドポイントは、キーがないと 401 unauthenticated を返します。
スコープ。 キーは、より狭いリスト(たとえば読み取り専用)で発行されたものでない限り、すべてのスコープ(read、exports、webhooks、wishlists)を持ちます。キーのスコープは GET /v1/me で確認できます。ウィッシュリストとウェブフックには wishlists と webhooks のスコープが必要です(webhook 配信のウィッシュリストには両方が必要で、プランより先にチェックされます)。スコープのないキーは、required_scope 付きで 403 forbidden_scope を返し、WWW-Authenticate には error="insufficient_scope" が入ります。
テストキー。 tp_test_ キーは同じライブデータを Free の制限で読み取り、独自のウィッシュリスト、マッチ、ウェブフックエンドポイント(livemode: false)を持ちます。ライブ側のものを参照したり変更したりすることはないため、テストスイートから本番環境に触れずに空のウィッシュリストセットを PUT できます。テストモードのウェブフックの送信先は webhook.site に限られます。
リトライ。 キーまたはパートナートークンが必要なエンドポイントへの POST、PATCH、DELETE は、Idempotency-Key ヘッダー(論理的なリクエストごとに 1 つの UUID)を受け付けます。登録用のエンドポイントは受け付けません。同じキーで同じリクエストをリトライすると、2 つ目のウィッシュリストやエンドポイントを作成する代わりに、最初に成功したレスポンスが Idempotent-Replayed: true 付きで再び返ります。キーは 24 時間記憶されます。別のリクエストに再利用すると 422 idempotency_key_reused、最初のリクエストがまだ実行中のときのリトライは 409 idempotency_in_progress になります。エラーは記憶されないため、エラー後のリトライは再度実行されます。このヘッダー付きのリクエストは、接続が切れてもキャンセルされません。処理は最後まで実行され、成功したレスポンスは記憶されるので、リトライでそれを受け取れます。20 秒を過ぎても実行中のリクエストは、何も変更せずにキャンセルされ、Retry-After: 1 付きで 503 unavailable を返します。同じキーでリトライしてください。
パートナーアプリ(現在は Tapelark)は、キーの代わりに署名付きの利用権トークンを送ります:Authorization: Bearer TPE1-…。トークンはパートナーの Ed25519 鍵に対してオフラインで検証され、下の表にあるパートナープランに解決されます。API がエンドユーザーの身元を知ることはありません。形式が不正または不明なトークンは 401 token_invalid、期限切れのトークンは 401 token_expired(更新してください)、別のオーディエンス向けのトークンは 401 token_audience、失効または取り消された利用権は 403 entitlement_revoked を返します。
レート制限とクォータ
| プラン | レート | クォータ | 一括取得の ID 数 | 履歴 |
|---|---|---|---|---|
| 匿名(IP ごと) | 2 req/s、バースト 5 | 1,000 / 日 | 20 | なし |
| Free | 2 req/s、バースト 5 | 1,000 / 日 | 20 | なし |
| Developer | 10 req/s、バースト 20 | 100,000 / 月 | 100 | 7 日 |
| Pro | 50 req/s、バースト 100 | 1,000,000 / 月 | 100 | 12 か月 |
| Business | 個別 | 個別 | 100 | 12 か月 |
| Tapelark(利用権トークン、ライセンスごと) | 5 req/s、バースト 10 | 2,000 / 日 | 50 | 7 日 |
毎秒の制限はトークンバケットです。バケットが空になると、Retry-After 付きで 429 rate_limited が返ります。クォータを使い切ると、ウィンドウがリセットされるまでの秒数を Retry-After に入れて 429 quota_exceeded が返ります。
共有キャッシュできない認証済みレスポンスには、IETF のレート制限フィールドが付きます。
RateLimit-Policy: "burst";q=10;w=1, "monthly";q=100000;w=2592000
RateLimit: "burst";r=7;t=1
共有キャッシュ可能なレスポンス(検索、一括取得、局ごとの再生中の曲、局、統計、ヘルスの時系列)には、レート制限ヘッダーが付きません。エッジが同じ本文を別の呼び出し元に返すことがあるためです。残りの利用枠はいつでも GET /v1/me で確認できます。
キャッシュ
ライブのレスポンスは 5 秒間キャッシュ可能(Cache-Control: public, max-age=5, s-maxage=5)で、弱い ETag が付きます。If-None-Match を送ると、変化がなければ 304 が返ります。304 はオリジンでのクォータに数えられません。局ディレクトリは 60 秒、単一の局は 300 秒キャッシュされます。履歴は private, max-age=30 です。ヘルスとキーのエンドポイントは no-store です。
すべてのレスポンスに X-Request-Id が付きます。サポートに連絡するときはこの値を添えてください。
エラー
エラーは RFC 9457 の problem details に従い、2 つの拡張メンバーを持ちます。安定した機械可読の文字列である code と、エンドポイント固有の追加情報(バリデーション失敗時の errors[] や 403 時の required_tier など)です。
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://tuneping.com/docs/errors/#validation_failed",
"title": "Validation failed",
"status": 422,
"detail": "One or more query parameters are invalid.",
"instance": "urn:tuneping:request:req_01a18837c239727fbacb40d6c488405a",
"code": "validation_failed",
"errors": [ { "field": "q", "code": "length", "message": "`q` is required and must be 2–120 characters." } ]
}
すべてのコードとその意味はエラーカタログにあります。最初に出会うのは次のものです。
| HTTP | code | 発生条件 |
|---|---|---|
| 400 | invalid_request | 不明なクエリパラメーター、または形式が不正なリクエスト |
| 400 | invalid_cursor | カーソルの形式が不正、期限切れ(24 h。マッチフィードの since_cursor は 30 日)、または異なるフィルターで使用された |
| 401 | unauthenticated · invalid_api_key · key_revoked | キーがない、不明、または失効している |
| 403 | forbidden_tier | エンドポイントまたはパラメーターに上位のプランが必要。required_tier がどのプランかを示す |
| 403 | forbidden_scope | キーがそのスコープなしで発行された。required_scope がどのスコープかを示す |
| 404 | not_found · station_opted_out | 不明な ID、または局がインデックス化しないよう求めた |
| 422 | validation_failed | フィールドのエラーが errors[] に入る |
| 429 | rate_limited · quota_exceeded | リクエストを減らす。Retry-After は秒単位 |
| 503 | unavailable | データベースが利用できない、または Idempotency-Key 付きのリクエストが 20 秒後にキャンセルされた。Retry-After の後にリトライ |
GET/v1/now-playing/search キー不要 public, max-age=5 · ETag
ライブ検索
いま q を流している局を返します。あいまい一致で、アクセント記号を区別しません。gronemeyer manner で Grönemeyer – Männer が見つかります。行は類似度の順に並び、同じなら新しくタイトルが現れたものが先です。ページネーションはありません。インデックスは数秒ごとに変わるため、ページを分けると行が抜けたり重複したりします。代わりに limit を増やしてください。
| パラメーター | 型 | 既定値 | 意味 |
|---|---|---|---|
q | string、2〜120 文字 | 必須 | アーティスト、タイトル、またはその両方。3 文字以上ではトライグラム照合、それより短いクエリは部分文字列一致です。 |
country | ISO 3166-1 alpha-2、複数指定可 | すべて | 指定した国の局のみ。 |
codec | string | すべて | 例:MP3、AAC。 |
min_bitrate | integer | 0 | kbit/s。 |
classification | enum | song | song、ident、programme、ad_break、empty、junk、unknown、または any。 |
max_age_seconds | 30〜900 | 180 | この秒数以内にポーリングに成功した局の行のみ。 |
limit | 1〜100 | 20 | 返す行数。truncated: true は、さらに行があったことを示します。 |
レスポンス · 200 · application/json
{
"data": [
{
"station": { "id": "159824f0-5475-4263-bcc8-59a48a213896", "name": "Radio 10 80's Hits", "country": "NL",
"codec": "MP3", "bitrate": 128, "is_hls": false,
"stream_url": "http://…/TLPSTR20.mp3", "homepage": "http://www.radio10.nl/", "recordability": "recordable" },
"raw_title": "Madonna - Holiday",
"artist": "Madonna", "title": "Holiday",
"track": { "id": "trk_c6f", "mbid": "d4708b79-62e7-4ce4-a6ca-247237d4ef4e", "artist_id": "art_fn" },
"classification": "song", "match_grade": "high", "confidence": "high",
"started_at": "2026-10-29T15:08:44.883Z", "start_uncertainty_seconds": 32,
"observed_at": "2026-10-29T15:09:26.631Z", "confirmed_at": "2026-10-29T15:10:30.679Z",
"method": "icy", "poll_interval_seconds": 60, "similarity": 0.5
}
],
"truncated": false,
"query": { "q": "madonna", "normalized": "madonna", "max_age_seconds": 180 }
}
行の読み方
- started_at RFC 3339 · 推定
- 現在のタイトルの推定開始時刻。前後に ±
start_uncertainty_secondsの幅があります。 - observed_at RFC 3339
- Tuneping がこのタイトルを最初に確認した時刻。
- confirmed_at RFC 3339
- その局の最新のポーリング成功時刻。「この時点でまだ再生中」という意味です。鮮度の判断に使ってください。
- track object · 省略可
- タイトルが MusicBrainz のレコーディングにひも付けられた場合に存在します。
- similarity 0〜1
- しきい値は各自で決めてください。
GET/v1/now-playing キー不要 public, max-age=5 · ETag
再生中の曲の一括取得
複数の局の現在のタイトルを 1 回の呼び出しで返します。お気に入り画面向けです。
| パラメーター | 型 | 既定値 | 意味 |
|---|---|---|---|
station_ids | カンマ区切りの UUID | 必須 | 匿名または Free では最大 20、Developer 以上では 100。ID はキャッシュ前に並べ替えと重複除去が行われるため、同じお気に入りを持つ 2 つのクライアントは 1 つのキャッシュ済み本文を共有します。 |
max_age_seconds | 30〜86400 | 900 | これより古い行も返されますが、is_stale: true が付きます。 |
{ "data": [ { …same row shape as search, without similarity, plus "is_stale": false… } ],
"missing": [ "ids that are unknown or opted out" ],
"max_age_seconds": 900 }
GET/v1/stations/{id}/now-playing キー不要
局ごとの再生中の曲
1 つの局について 1 行を返します。まだタイトルが確認されていない場合は 404 not_found、局がインデックス化しないよう求めた場合は 404 station_opted_out です。
GET/v1/stations GET/v1/stations/{id} キー不要 max-age=60 · 300
局
コミュニティが管理する Radio Browser ディレクトリをもとに作られ、Tuneping が各局をどう読み取るかの情報を加えたディレクトリです。
| パラメーター | 型 | 既定値 | 意味 |
|---|---|---|---|
q | string | — | 局名(あいまい一致)。 |
country | alpha-2、複数指定可 | すべて | |
tag | string、複数指定可 | すべて | 指定したタグがすべて一致する必要があります。 |
codec, min_bitrate | 検索と同じ。 | ||
has_now_playing | boolean | false | Tuneping が現在タイトルを読み取っている局のみ。 |
sort | enum | clickcount | clickcount(人気順、降順)、name、bitrate。 |
limit | 1〜200 | 50 | |
cursor | 不透明な文字列 | — | 前のページの next_cursor から取得。有効期間は 24 時間で、同じフィルターでのみ使えます。 |
{ "data": [ {
"id": "159824f0-5475-4263-bcc8-59a48a213896", "name": "Radio 10 80's Hits", "country": "NL", "state": null,
"language": "dutch", "tags": ["80s", "hits"], "codec": "MP3", "bitrate": 128, "is_hls": false,
"stream_url": "http://…", "homepage": "http://www.radio10.nl/", "favicon_url": "https://…/favicon.png",
"clickcount": 1234, "recordability": "recordable",
"metadata": { "method": "icy", "poll_interval_seconds": 60, "lag_seconds": 9, "last_ok_at": "2026-10-29T15:10:30Z", "coverage": "live" },
"created_at": "2026-10-29T10:12:03Z", "updated_at": "2026-10-29T15:10:30Z" } ],
"next_cursor": "eyJ…" }
favicon_url はディレクトリからテキストとしてそのまま渡されます。Tuneping がロゴをコピーしたり配信したりすることはありません。
GET/v1/stations/{id}/history キー · Developer 以上 private, max-age=30
再生履歴
局が流した曲を、新しい順に、推定の開始・終了時刻とともに返します。さかのぼれる期間はプランによって異なり、Developer では 7 日、Pro と Business では 12 か月です。それより古い from を指定すると、required_tier 付きで 403 forbidden_tier を返します。期間を黙って切り詰めることはありません。
| パラメーター | 型 | 既定値 | 意味 |
|---|---|---|---|
from, to | RFC 3339 | to = 現在、from = to − 24 h | 1 回の呼び出しで最大 31 日。 |
classification | enum | song | 検索と同じ。 |
limit | 1〜200 | 50 | |
cursor | 不透明な文字列 | — | 期間はカーソルに固定されます。 |
{ "data": [ {
"id": "pe_…", "station": { …station ref… },
"raw_title": "Hecht - Charlotta", "artist": "Hecht", "title": "Charlotta",
"track": { "id": "trk_…", "mbid": "…", "artist_id": "art_…" },
"classification": "song", "match_grade": "high",
"started_at": "2026-10-29T10:31:12Z", "start_uncertainty_seconds": 10,
"ended_at": "2026-10-29T10:34:40Z", "duration_seconds": 208,
"method": "icecast_json", "confidence": "high" } ],
"next_cursor": null,
"window": { "from": "2026-10-28T15:00:00Z", "to": "2026-10-29T15:00:00Z" } }
GET/v1/me GET/v1/me/usage キー no-store
キーと利用状況
/v1/me は、キー、そのオーナーのプランと状態、適用される制限、現在のウィンドウでのここまでの利用量を返します。/v1/me/usage?from=&to= は 1 日あたりのリクエスト数を返します(オリジンへのリクエストのみ。エッジキャッシュのヒットは数えません)。
{ "key": { "id": "key_…", "hint": "tp_live_a1b2c3…", "scopes": ["read", "exports", "webhooks", "wishlists"], "livemode": true,
"created_at": "…", "last_used_at": "…" },
"owner": { "id": "own_…", "tier": "developer", "status": "active",
"current_period_start": "…", "current_period_end": "…" },
"limits": { "requests_per_second": 10, "burst": 20, "requests_per_day": null, "requests_per_month": 100000,
"history_days": 7, "batch_station_ids": 100, "webhooks": 0, "wishlists": 10,
"sse_connections": 1, "tightened_stations": 200 },
"usage": { "period_requests": 41230, "today_requests": 1810, "resets_at": "…" } }
GET/v1/health GET/v1/health/series GET/v1/stats キー不要
ヘルスと統計
/v1/health は status が ok または degraded の 200 を返し、データベースがダウンしているときは 503 を返します。死活監視はここに向けてください。/v1/health/series?minutes=60(5〜1440)は、ポーラーの 1 分ごとの数値を返します:polls、ok、titles_changed、songs、bytes_in、bytes_out、latency_p50_ms、latency_p90_ms、inflight_max、ips_paused、queue_lag_seconds と、by_method の内訳です。/v1/stats はステータスページに表示している公開のカバー範囲のスナップショットです:局の総数、ポーリング中の局、ライブのメタデータがある局、1 分あたりのタイトル変化、曲の割合、方式別、国別。
POST/v1/wishlists PUT/v1/wishlists GET/v1/wishlists/matches キー · Developer 以上 no-store
ウィッシュリスト
曲、アーティスト、または自由入力のタイトルを指定すると、どこかの局がそれを流し始めたときにわかります。タイトルの変化はすべて、読み取った時点でウィッシュリストと照合され、新しいウィッシュリストは 30 秒以内に有効になります。保持できるウィッシュリストは Developer で 10 件、Pro で 100 件、Business で 1,000 件です。マッチは 30 日間保持されます。
| フィールド | 型 | 意味 |
|---|---|---|
kind | artist · track · query | artist と track は検索で得た ID(art_…、trk_…)を取り、正規化処理がその ID にひも付けた別表記も捕捉します。query は自由入力のテキストを取り、通常は Artist - Title の形式です。 |
value | string、≤ 240 | ID またはテキスト。 |
match | exact · fuzzy | query のみ。exact は正規化したテキストを比較し、fuzzy はトライグラム類似度 0.6 以上を一致とみなします。 |
station_filter | object | station_ids(≤ 500)と countries(alpha-2、大文字小文字を問わず受け付け、大文字で返す)のどちらかまたは両方。局が一覧に含まれるか、一覧にある国の局であれば、タイトルは一致します。フィルターなしはすべての局を意味します。 |
delivery | array | poll(既定)、sse、webhook。ウェブフック配信は Pro 以上で、webhook_id と webhooks スコープを持つキーが必要です。 |
description | string、≤ 200 | 自由に使えます。 |
curl -H "Authorization: Bearer tp_live_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"kind":"query","value":"Daft Punk - One More Time","station_filter":{"countries":["FR","BE"]}}' \
https://api.tuneping.com/v1/wishlists
station_ids を明示的に指定すると、ウィッシュリストが有効な間、Tuneping はそれらの局を 60 秒ごとではなく 30 秒ごとに読み取り、レスポンスでは tightens: true でそのことを示します。指定した局の和集合にはプランごとの上限があります(/v1/me の limits.tightened_stations)。上限を超えるウィッシュリストは 422 validation_failed を返し、errors[] には code が tightened_stations_exceeded のエントリが入ります(フィールドは station_filter.station_ids、PUT では data)。国フィルターは引き続き一致しますが、各局の通常の間隔で判定されます。
GET /v1/wishlists/{id}、PATCH(局フィルター、match、delivery、webhook、description、status: enabled | paused)、DELETE は想定どおりに動作します。PUT /v1/wishlists に {"data": [ … ]} を送ると、セット全体を 1 回の呼び出しで置き換えます。変更のない項目は ID とマッチ数を保ち、それ以外は作成または削除されます。アプリがローカルに持つ一覧を同期するもっとも簡単な方法です。この本文は最大 1 MiB まで、それ以外のリクエスト本文は 64 KiB までです(413 payload_too_large)。
マッチは追記型のフィードです。GET /v1/wishlists/matches はすべてのウィッシュリストを、GET /v1/wishlists/{id}/matches はそのうち 1 つを対象にします。行は古い順に返ります。各レスポンスの next_cursor を保存し、since_cursor として送り返してください。これが null になることはなく、30 日間の保持期間中は有効で、再起動後も使えます。カーソルなしでは最新のマッチが返ります。limit は 1〜500、既定は 100 です。
{ "data": [ {
"id": "wm_…", "wishlist_id": "wl_…",
"station": { "id": "…", "name": "…", "country": "FR", "codec": "MP3", "bitrate": 128, "is_hls": false,
"stream_url": "https://…", "homepage": "https://…", "recordability": "recordable" },
"raw_title": "Daft Punk - One More Time", "track": { "id": "trk_…", "mbid": "…", "artist_id": "art_…" },
"started_at": "2026-10-30T21:04:10Z", "start_uncertainty_seconds": 10,
"observed_at": "2026-10-30T21:04:20Z", "matched_at": "2026-10-30T21:04:20Z",
"confidence": "high", "expected_end_hint_at": "2026-10-30T21:07:52Z" } ],
"next_cursor": "eyJ0Ijo…" }
started_at はタイトルを確認した時刻に基づいてすでに補正されているため、録音アプリは「約 N ± U 秒前に開始」と表示できます。expected_end_hint_at は started_at に曲の長さの中央値である 222 秒を加えたもので、予測ではなく目安です。confidence は、ひも付けられたトラックまたはアーティストの ID でマッチした場合は high、正規化したアーティストとタイトルでは medium、テキストクエリでは low です。
POST/v1/webhooks GET/v1/webhooks/{id}/deliveries キー · Pro 以上 no-store
ウェブフック
Tuneping は、イベントが発生するたびにあなたの HTTPS エンドポイントへ POST します。エンドポイント数は Pro で 5 個、Business で 20 個です。
| イベント | 発生条件 | Pro で必要なもの |
|---|---|---|
wishlist.matched | webhook_id でこのエンドポイントを指定したウィッシュリストがマッチした。 | — |
station.title_changed | 局のタイトル行が変わった。 | filters.station_ids(≤ 200) |
track.started | ひも付けられたトラックが始まった。 | filters.track_ids または artist_ids(≤ 200) |
artist.started | ひも付けられたアーティストの曲が始まった。 | filters.track_ids または artist_ids(≤ 200) |
フィルターには countries と classification も指定できます。国だけのフィルターと、フィルターなしのタイトル変化の全件ストリームは Business 向けです。各エンドポイントには 1 日あたりのイベント数の上限があり、Pro で 50,000、Business で 500,000 です。上限を超えると、そのエンドポイントは翌日(UTC)まで paused_budget となり、メールが届きます。
curl -H "Authorization: Bearer tp_live_…" -H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/tuneping","events":["wishlist.matched"]}' \
https://api.tuneping.com/v1/webhooks
レスポンスには署名用の secret(whsec_…)が一度だけ含まれます。配信は Standard Webhooks に従います。ヘッダーは webhook-id、webhook-timestamp、webhook-signature: v1,<base64> で、署名は {webhook-id}.{webhook-timestamp}.{body} に対して secret のバイト列で計算した HMAC-SHA256 です。タイムスタンプが 5 分以上ずれているものは拒否し、重複の除去には webhook-id を使ってください。この値はリトライをまたいで変わりません。
{ "id": "evt_…", "type": "wishlist.matched", "created_at": "2026-10-30T21:04:20Z",
"data": { "station_id": "…", "station": { …station ref… }, "wishlist_id": "wl_…", "match_id": "wm_…",
"raw_title": "Daft Punk - One More Time", "artist": "Daft Punk", "title": "One More Time",
"track_id": "trk_…", "artist_id": "art_…", "classification": "song",
"started_at": "…", "start_uncertainty_seconds": 10, "observed_at": "…",
"confidence": "high", "expected_end_hint_at": "…" },
"links": { "station": "/v1/stations/…", "wishlist": "/v1/wishlists/wl_…" } }
10 秒以内に任意の 2xx で応答してください。リダイレクトはたどりません。失敗した配信は 5 s、5 min、30 min、2 h、5 h、10 h、14 h、20 h、24 h 後にリトライされ、合計で約 3 日間、エンドポイントごとに 1 件ずつ行われます。410 を返したエンドポイント、または 5 日連続で失敗したエンドポイントは無効化され、メールが届きます。修正したら PATCH で status を enabled に戻してください。
POST /v1/webhooks/{id}/rotate-secret は新しい secret を返します。その後 24 時間は、すべての配信に secret ごとに 1 つずつ、2 つの署名が付きます。POST /v1/webhooks/{id}/test は ping を送ります。GET /v1/webhooks/{id}/deliveries?status=pending|succeeded|failed は 30 日分の配信を一覧表示し、POST …/deliveries/{dl_id}/redeliver は 1 件を再送します。テストキー(tp_test_…)の送信先は webhook.site に限られます。
GET/v1/stream キー · Developer 以上 text/event-stream
イベントストリーム
同じイベントを、server-sent events 形式の 1 本の長い HTTP レスポンスで受け取れます。サーバーやネイティブアプリ向けです。station_ids(最大 100)か wishlist_id(all、または 1 つの wl_… ID)のどちらかを渡してください。
curl -N -H "Authorization: Bearer tp_live_…" -H "Accept: text/event-stream" \
"https://api.tuneping.com/v1/stream?station_ids=159824f0-5475-4263-bcc8-59a48a213896"
retry: 3000
id: evt_1m675e1tkfdxtn7axmq6qktz8
event: station.title_changed
data: {"id":"evt_1m675e1tkfdxtn7axmq6qktz8","type":"station.title_changed","created_at":"…","data":{…}}
: ping
| パラメーター | 既定値 | 意味 |
|---|---|---|
station_ids | — | カンマ区切りの局 ID、最大 100。 |
wishlist_id | — | all またはウィッシュリスト ID。wishlist.matched を送ります。 |
events | station.title_changed | 局のストリームでは、station.title_changed、track.started、artist.started の任意の組み合わせ。 |
classification | song | song または any。局のストリーム用。 |
data はウェブフックが受け取るものと同じ JSON です。イベントのない状態が 20 秒続くと : ping コメントが届くため、クライアントのアイドルタイムアウトは 60 秒以上に設定してください。接続が切れたら、最後に受け取った id を Last-Event-ID ヘッダーに設定して再接続してください。直近 10 分間のイベントが再送されます。それより古い位置からの場合は、取得可能な最も古い ID を含む event: gap が届きます。抜けた部分は履歴またはマッチフィードで補ってください。キーごとに開けるストリーム数は Developer で 1、Pro で 5、Business で 20、Tapelark ではデバイスごとに 1 です。それを超えると 429 too_many_connections が返ります。
ブラウザではここで EventSource を使えません。Authorization ヘッダーを送れず、キーを URL に含めることも認めていないためです。代わりに fetch() でストリームを読み取ってください。
フィールドと列挙値
- classification enum
song·ident(局名またはスローガン) ·programme·ad_break·empty·junk·unknown。再生履歴になるのは曲だけで、ライブの行にはすべてが残ります。- match_grade enum
high·medium·none。タイトルが MusicBrainz のレコーディングにどの程度うまくひも付けられたか。- confidence enum
high·medium·low。分類、マッチグレード、局が最後に確認されてからの経過時間、局のこれまでの実績から、行ごとに算出します。検証できるように仕組みを公開しています。- method enum
- Tuneping が局を読み取る方式:
icy(ストリーム内メタデータ)、icecast_json(サーバーステータス JSON)、shoutcast_stats(ステータス XML)、shoutcast_currentsong、seven_html。内部的な識別子であり、推奨を意味するものではありません。表示する場合は「ストリーム内」「ステータスページ」としてください。 - recordability enum
- 録音クライアントから見て、局のストリームが録音可能なプレーンな HTTP ストリームかどうか。参考情報です。
- ID
- 局には Radio Browser の UUID を使います。トラックは
trk_…、アーティストはart_…、再生イベントはpe_…、キーはkey_…、オーナーはown_…、ウィッシュリストはwl_…、マッチはwm_…、ウェブフックはwh_…、配信はdl_…、イベントはevt_…です。いずれも不透明な文字列として扱ってください。 - タイムスタンプ
- RFC 3339、UTC。ソースが持つ場合はミリ秒精度。
OpenAPI
この API の機械可読な記述は /docs/openapi-v1.yaml(OpenAPI 3.1)にあります。クライアント生成の元になるもので、オペレーション ID は変わりません。
クレジット表記と公正な利用
Free プランと匿名での利用では、データを表示する場所に「Data by Tuneping」のリンクを見える形で表示してください(バッジ)。再生は局のメタデータから検出したもので、認定されたモニタリングではありません。証拠として示す場合は「局のメタデータから検出」と記してください。局名はテキストです。Tuneping はロゴやアートワークを提供しません。利用規約をご覧ください。