Stripe でクーポンを作って、対象商品を applies_to で絞ったのに、取得しても applies_to が出てこない。そうなったら、保存されていないと思いませんか。
私はそう思って、10日間そのつもりで運用していました。実際は、applies_to は既定では返ってこない項目で、expand[]=applies_to を付けたときだけ返ります。
| 取り方 | 応答に applies_to は |
|---|---|
| 作成(POST /v1/coupons) | 無い |
| 取得(GET /v1/coupons/{id}) | 無い |
取得+ expand[]=applies_to
|
ある(指定した8つの商品 ID) |
(2026年9月21日に作ったクーポンを、10月1日に取り直した結果)
| 当時の私の読み | 実際 |
|---|---|
applies_to が保存されていない |
保存されていた |
| クーポンは全商品に効く | 指定した8商品にだけ効く |
| 書き方を変えても無駄 | どの書き方でも、取り出し方が同じなら見えない |
(判断を誤った箇所を並べたもの。誤りは、応答に無いことを、データが無いことと読んだ1点)
先に断っておくと、これは Stripe のリファレンスに書いてあることです。Coupon オブジェクトの applies_to には「includable (not returned by default; request it with the expand request parameter)」とあります。ここで書くのは、それを読まずに「無視された」と判断したときに、何が起きたかです。
9月21日:応答に applies_to が無かった
ブラックフライデー用に、20%引きのクーポンを API で作りました。対象は2製品の8商品で、applies_to[products][] に8つの商品 ID を渡しています。
確認用のスクリプトで取得すると、応答はこうでした。
{
"id": "rapls-bf26",
"object": "coupon",
"amount_off": null,
"created": 1789955683,
"currency": null,
"duration": "once",
"duration_in_months": null,
"livemode": true,
"max_redemptions": null,
"metadata": {},
"name": "Black Friday 2026 - 20 percent off",
"percent_off": 20.0,
"redeem_by": 1796209200,
"times_redeemed": 0,
"valid": true
}
applies_to がありません。スクリプトは「キーが存在しない → 全商品が対象」と表示しました。
書き方を変えて試した
指定の書き方が悪いのかと思い、捨てる前提のクーポンを作って試しました。applies_to[products][]=... と、添字付きの applies_to[products][0]=... などです。作成の応答を grep applies_to で見ても、どれにも出てきません。
それで、この API バージョンでは applies_to がエラーも出さずに無視される、と判断しました。調べものは AI と一緒にやっていて、AI もそう読みました。
守りを決済リンクに寄せた
対象外にしたかったのは、まだ先行価格で売っている別製品の有料版です。そこで、決済リンクの「プロモーションコードを許可」をオフにして、入力欄そのものを出さないようにしました。運用の手順書には、この設定だけが守りだと書きました。
余談ですが、プロモーションコードは削除できず、同じコード文字列も二度と使えません。クーポンを作り直していたら、媒体別に用意した15本のコード名も捨てるところでした。作り直さなかったのは、結果的に正解でした。
10月1日:expand を付けたら返ってきた
この件を記事にする前に、リファレンスを読み直して、冒頭の一文を見つけました。Windows で作業していたので、PowerShell で取り直しています。
$r = Invoke-RestMethod -Method Get `
-Uri "https://api.stripe.com/v1/coupons/rapls-bf26?expand%5B%5D=applies_to" `
-Headers @{ Authorization = "Bearer $SK" }
$r.applies_to | ConvertTo-Json -Depth 5
{
"products": [
"prod_U9WGVxYjyYh3Tf",
"prod_U9WGsDEnjf4MzK",
"prod_U9WGR2it0BIMM1",
"prod_U9WGLekazaIkJ3",
"prod_UcNBJGkFwtQ62V",
"prod_UcN9i1zpZ97uCx",
"prod_UcNDUsSjwYkN5t",
"prod_UcNCMlZmtPrhrU"
]
}
9月21日に渡した8つが、そのまま入っていました。
なぜ無いと読んだのか?
作成の応答にも、ふつうの取得にも出てこないので、「どの取り方でも出ない」と思い込んでいました。実際は、どちらも同じ「既定の返し方」で、条件は1つしか変えていなかった。書き方を何通り試しても、取り出し方が同じなら結果は同じです。テストを重ねたことで、確かめた気になっていました。
スクリプトも直す
確認用のスクリプトは、「キーが存在しない → 全商品が対象」と表示していました。無いことに意味を足して表示していたのが、誤解を固めた一因です。取得に expand[]=applies_to を付けて、それでも無いときだけ「絞り込みなし」と出すように直します。
守りは二重のまま残す
いまは、クーポン自体が8商品にしか効かず、さらに対象外の決済リンクには入力欄も出ません。手順書の「この設定だけが守り」という書き方は直しますが、決済リンク側の設定は残します。片方が何かで外れても、もう片方が効くからです。
なお、作成のリクエストに expand[]=applies_to を付ければ、作った直後の応答でも確かめられるはずです。こちらはまだ試していません。
applies_to のように、既定では返ってこない項目は、ほかの API にもあると思います。応答に無いのを見て「保存されていない」と判断する前に、何を確かめていますか。
確かめるコマンド
bash / zsh(curl)の場合です。zsh では read -rsp が使えないので、read -rs "SK?key: " にしています。キーを打つ行と、その後の行は分けて貼ってください。続けて貼ると、後ろの行がキーとして読み込まれます。
read -rs "SK?key: "; echo
curl -sS -G https://api.stripe.com/v1/coupons/rapls-bf26 -u "$SK:" \
-d "expand[]=applies_to" | python3 -m json.tool | grep -A12 applies_to
unset SK
PowerShell(Windows PowerShell 5.1 / PowerShell 7)の場合です。
$sec = Read-Host "key" -AsSecureString
$SK = [System.Net.NetworkCredential]::new("", $sec).Password
$r = Invoke-RestMethod -Method Get `
-Uri "https://api.stripe.com/v1/coupons/rapls-bf26?expand%5B%5D=applies_to" `
-Headers @{ Authorization = "Bearer $SK" }
$r.applies_to | ConvertTo-Json -Depth 5
Remove-Variable SK, sec
expand[] の角かっこは、URL に直接書くと崩れることがあるので、PowerShell 版では %5B%5D にしています。
ふだんはraplsworks.comで、WordPressプラグイン開発やClaude Codeまわりのことを書いています。
https://raplsworks.com/