開発者/連携
商品と注文
このガイドでは、購入の流れを最初から最後まで説明します。残高の確認、商品の検索、価格の確認、注文、コードの受け取りの順に進みます。
#アカウントと残高
#アカウント
GET/api/v1/account では、貴社の会社情報と、APIが有効になっているかどうかを確認できます。
{
"merchant_id": "M00000001",
"name": "Acme Shop",
"legal_name": "Acme Shop Ltd",
"billing_email": "[email protected]",
"status": "active",
"kyb_status": "approved",
"api_access_enabled": true,
"default_currency": "USD",
"purchase_limits": {
"currency": "USD",
"verified": true,
"max_order_amount": "1000.00",
"daily_order_amount_limit": "10000.00",
"daily_order_count_limit": 1000,
"used_today_amount": "120.50",
"used_today_count": 3,
"day_resets_at": "2026-10-01T00:00:00+00:00"
}
}default_currencyはウォレットの通貨です。支払う金額はすべてこの通貨で表示されます。api_access_enabledは、CardVが貴社の審査を承認するとtrueになります。
#残高
GET/api/v1/balance では、使える残高を確認できます。
{
"currency": "USD",
"balance": "1520.40",
"reserved_amount": "0.00",
"available_balance": "1520.40",
"low_balance_threshold": "200.00",
"low_balance_notified_at": null,
"is_active": true
}available_balanceは、今すぐ使える金額です。balanceからreserved_amountを引いた額です。available_balanceを超える注文は拒否され、代金は引き落とされません。low_balance_thresholdは、残高不足のメール通知が届く基準額です。Portalで設定できます。- 入金はPortalで行ってください。
#為替レート
GET/api/v1/fx-rates?quote=EUR は、USD から他の通貨への為替レートを返します。
ストアが USD 以外の通貨で販売している場合に使います。CardV はウォレットから常に USD で引き落とします。このレートは自社の価格設定のためだけのものです。
{
"base": "USD",
"quote": "EUR",
"rate": "0.9234",
"as_of": "2026-10-11T07:05:00Z"
}quoteは ISO 4217 の通貨コードです(例:EUR、GBP、JPY)。baseは省略できます。対応しているのはUSDのみです。rateは 1 USD あたりのquote通貨の数量です。10 進数の文字列なので、浮動小数点数として読まないでください。as_ofは CardV がこのレートを最後に更新した日時です。レートは 1 時間ごとに更新されます。quote=USDは"rate": "1"を返します。- レートは自社側で保存してください。1 日に数回の取得で十分です。
| ステータス | 意味 | 対応 |
|---|---|---|
| 400 | quote がない、3 文字のコードではない、または base が USD ではない | リクエストを修正する |
| 404 | No exchange rate for this currency. | この通貨の価格は自社で設定する |
| 503 | Exchange rate temporarily unavailable. | 最後に保存したレートを使い続け、後で再試行する |
このリクエストも他と同じく署名が必要です。署名するパスにはクエリ文字列を含めます(例:/api/v1/fx-rates?quote=EUR)。
#商品(SKU)
SKUとは、購入できる1つの商品のことです。たとえば「Steam Wallet 10 USD」が1つのSKUです。IDは S000456 のような形です。見積もりと注文はSKU単位で行います。
#商品モデル
すべてのSKUは、次のいずれかのモデルに当てはまります。denomination_type と product_type で見分けてください。
| モデル | 見分け方 | 価格 | 注文 | 受け取るもの |
|---|---|---|---|---|
| 固定額 | denomination_type: "fixed" | merchant_price が1個あたりの価格です。 | quantity を送ります。 | deliveries 内のコード。 |
| 金額指定 | denomination_type: "range" | merchant_price_min から merchant_price_max。実際の価格は金額によって決まるため、見積もりを取得してください。 | quantity と amount を送ります。 | deliveries 内のコード。 |
| 直接チャージ | product_type: "direct_charge" | 固定額と同じです。 | inputs も送ります(直接チャージを参照)。 | 通常コードはありません。succeeded はアカウントへのチャージが完了したことを示します。 |
| モバイルチャージ | このカタログには含まれません | 専用の見積もり | 専用のAPI | モバイルチャージを参照してください。 |
verticalは商品ラインであり、モデルではありません。直接チャージでもvertical: "gift_card"の場合があります。- 固定額・金額指定のどのSKUも、コードの代わりに CardV 引き換え用リンク で届けられることがあります。その場合SKUは
delivery_mode: "voucher"です。リンクを受け取ります(delivery_type: "link"、リンクはredeem_urlにあります)。お客様がリンクを開くとコードを受け取れます。コードと同じようにお客様へ送ってください。
GET/api/v1/skus では、購入できるSKUの一覧を取得できます。例:
GET /api/v1/skus?search=steam®ion=US&limit=50&offset=0絞り込み条件(すべて任意):
| 条件 | 例 | 対象 |
|---|---|---|
search | steam | SKU ID、商品名、ブランド |
brand | Steam | ブランド名(大文字・小文字は区別しません) |
region | US | 国コードまたは国名;GLC = グローバル、EU = ヨーロッパ |
category | Travel | ビジネスカテゴリ(例:Travel、Digital Wallets & Payment、Game Credits) |
vertical | gift_card | 商品カテゴリー |
product_type | pin_code | 受け取り方法 |
ページング:limit(初期値100、上限500)と offset を指定します。
offset を増やしながら、offset が count に達するまで取得を続けてください。
{
"count": 7,
"limit": 2,
"results": [
{
"sku_id": "S000456",
"product_id": "P000123",
"name": "Steam Wallet 10 USD",
"product_name": "Steam Wallet US",
"brand": "Steam",
"region": "US",
"vertical": "gift_card",
"product_type": "pin_code",
"denomination_type": "fixed",
"denomination_value": "10",
"face_currency": "USD",
"merchant_price": "9.25",
"merchant_price_min": "9.25",
"merchant_price_max": "9.25",
"settlement_currency": "USD",
"availability": "available",
"min_quantity": 1,
"max_quantity": 100,
"required_input_schema": [],
"...": "more fields"
},
{
"sku_id": "S006126",
"product_id": "P002210",
"name": "Apple ES",
"product_name": "Apple ES",
"brand": "Apple",
"region": "ES",
"vertical": "gift_card",
"product_type": "pin_code",
"denomination_type": "range",
"denomination_value": "0",
"min_face_value": "2",
"max_face_value": "250",
"amount_step": null,
"face_currency": "EUR",
"merchant_price": "2.28",
"merchant_price_min": "2.28",
"merchant_price_max": "284.15",
"price_label": "From 2.28 USD",
"settlement_currency": "USD",
"availability": "available",
"...": "more fields"
}
],
"filter_options": {"brands": [], "regions": [], "categories": [], "verticals": []}
}GET/api/v1/skus/{sku_id} では、同じフィールドを持つ1つのSKUを取得できます。
特によく使うフィールド:
| フィールド | 意味 |
|---|---|
sku_id | 見積もりと注文に使うIDです。 |
merchant_price | 貴社の1個あたりの価格(settlement_currency 建て)。range SKU では min_face_value の金額の価格(開始価格)にすぎません。他の金額には使わず、amount を付けて見積もりを取得してください。 |
availability | available または unavailable。注文できるのは available のSKUだけです。 |
denomination_type | fixed または range。固定額と金額指定を参照してください。 |
denomination_value | fixed SKU の額面。range SKU では "0"。 |
min_face_value、max_face_value | range SKU:お客様が選べる最小・最大金額(face_currency 建て)。 |
merchant_price_min、merchant_price_max | 最小金額と最大金額の価格。fixed SKU では merchant_price と同じです。価格帯の表示に使えますが、注文前には必ず正確な金額で見積もりを取得してください。現時点で価格を算出できない場合、merchant_price_max は "" です。 |
price_label | merchant_price の表示用テキスト。range SKU では From で始まります(例:From 2.28 USD)。 |
face_value_label | 額面の表示用テキスト(例:10 USD、50 - 1000 GBP)。 |
discount | 額面に対する割引(例:7.50% off face value)。カードの通貨がウォレットの通貨と同じ fixed SKU のみ。それ以外は ""。 |
amount_step | 金額指定型のSKUのみ。金額はこの値の倍数にしてください。たとえば "1" は整数のみという意味です。null は刻みがないことを示します。 |
face_currency | カードに記載されている通貨です。ウォレットの通貨と異なる場合があります。 |
min_quantity, max_quantity | 1つの注文明細で指定できる数量の範囲です。 |
product_type | pin_code(コードを受け取る)または direct_charge(CardVがアカウントに直接チャージする)。 |
delivery_type | サプライヤーが届ける形式:code、code_pin、code_serial、url、direct_charge。delivery_mode が voucher の場合は、代わりにリンクを受け取ります。 |
delivery_mode | code(コードそのものを受け取る)または voucher(CardV 引き換え用リンクを受け取る)。 |
voucher_instructions | voucher SKU のみ:お客様にリンクの使い方を伝えるテキスト。それ以外は ""。 |
vertical、category | 商品ラインと業務カテゴリー。絞り込みや表示に使います。 |
region、region_name、region_label | 国・地域コード、その名称、表示用ラベル。 |
required_input_schema | 直接チャージで送る必要がある情報です。 |
brand_logo_url, image_url | CardVが提供する画像、または "" です。 |
description, redemption_instructions, terms, disclaimer | エンドユーザー向けに表示できる説明文です。 |
ポイント:
- 表示されるのは、有効で、かつ貴社のアカウントで購入できるSKUだけです。それ以外のSKUには404が返ります。
- SKU一覧は5~15分ごとに同期してください。注文の直前には、必ず見積もりを取ってください。
- 顧客に表示する価格には、同期したSKU一覧の価格を使ってください。ページ表示や訪問者ごとに見積もりエンドポイントを呼び出さないでください。
- 金額指定 SKU の価格は仕入れコストに連動し、1日に数回変わることがあります。SKU の同期時に
merchant_price_minとmerchant_price_maxも更新してください。 filter_optionsには、絞り込みに使えるブランド、地域、商品カテゴリーが入っています。
#商品単位で同期する
ストアで「1 商品 1 ページ、ページ内で金額を選ぶ」形式を取る場合は、SKU ではなく商品単位で同期してください。
GET/api/v1/products は商品の一覧を返し、各商品には購入できるすべての SKU が含まれます。
GET /api/v1/products?brand=Steam®ion=GB&limit=50&offset=0フィルターとページングは GET/api/v1/skus と同じです。count は商品数、sku_count はその SKU 数です。
{
"count": 1,
"sku_count": 4,
"limit": 50,
"results": [
{
"product_id": "P000123",
"product_name": "Steam Wallet UK",
"brand": "Steam",
"category": "Gaming",
"region": "GB",
"product_type": "pin_code",
"image_url": "https://b2b.cardv.net/api/v1/catalog-assets/steam.png",
"required_input_schema": [],
"skus": [
{
"sku_id": "S000456",
"name": "Steam Wallet 5 GBP",
"label": "5 GBP",
"denomination_type": "fixed",
"denomination_value": "5",
"face_currency": "GBP",
"merchant_price": "7.61",
"settlement_currency": "USD",
"availability": "available",
"min_quantity": 1,
"max_quantity": 100,
"...": "more fields"
}
]
}
],
"filter_options": {"brands": [], "regions": [], "categories": [], "verticals": []}
}GET/api/v1/products/{product_id} は 1 つの商品とその SKU に加え、description、redemption_instructions、terms、disclaimer を返します。
skus内の各 SKU はGET/api/v1/skusと同じフィールド・同じ値です。見積もりと注文はいつもどおりsku_idで行います。- 選択肢の表示には
labelを使います(例:5 GBP、Tinder Plus 1 Month)。金額ではなくプランの商品もあります。 - 1 つの商品の額面通貨と金額タイプは 1 種類だけです。範囲指定の SKU は必ず独立した商品になります。
- 一覧には長文の説明は含まれません。商品ごとに
GET/api/v1/products/{product_id}で 1 回取得してください。
#固定額と金額指定
ほとんどのSKUは、10 USDのように額面が固定されています。一部のSKUは金額指定型で、5~500 USDのようにエンドユーザーが金額を選べます。
| 種類 | 見積もりのとき | 注文のとき |
|---|---|---|
fixed | quantity を送る | amount は送らない |
range | quantity と amount を送る | amount を送る |
金額指定型のSKUでは、amount を min_face_value 以上、max_face_value 以下にしてください。
amount の通貨は face_currency です。
金額指定 SKU の価格。 SKU 一覧と商品一覧の merchant_price と price_label は min_face_value の金額の価格だけです。merchant_price_min と merchant_price_max は最小金額と最大金額の価格です。その間の金額の価格は、どちらの単純な倍数でもありません。販売価格を決める前や注文前に、実際の amount で見積もりを取得し、その merchant_price を expected_unit_price として送ってください。
金額指定型のSKUには、amount_step が設定されているものもあります。null でない場合、amount はその倍数にしてください。たとえば "amount_step": "1" の場合、25 は送れますが 25.50 は送れません。刻みに合わない金額で見積もりや注文をすると、HTTP 400が返り、代金は引き落とされません。
#直接チャージ
一部の商品は、ゲームのアカウントなど、エンドユーザーのアカウントに直接チャージします。この場合、CardVはチャージ先のアカウント情報を必要とします。必要な項目はSKUに記載されています。
"required_input_schema": [
{"key": "player_id", "label": "Player ID", "type": "text", "required": true},
{"key": "server", "label": "Server", "type": "text", "required": false}
]注文明細の inputs に、各 key を使って値を入れて送ります。
"inputs": {"player_id": "123456789", "server": "EU"}"required": falseと書かれていない項目は必須です。typeはフォーム項目の種類のヒントです(例:text)。- 必須の値が抜けていると、注文は
itemsエラーで拒否されます。 - これらの値はエンドユーザーの個人情報です。大切に扱ってください(セキュリティを参照)。
#見積もり
見積もりでは、指定した数量での現在の価格がわかります。
GET /api/v1/skus/S000456/quote?quantity=2
GET /api/v1/skus/S000789/quote?quantity=1&amount=25.00{
"sku_id": "S000456",
"settlement_currency": "USD",
"merchant_price": "9.25",
"quantity": 2,
"total_price": "18.50",
"min_quantity": 1,
"max_quantity": 100,
"availability": "available"
}- 見積もりを取っても、価格は確保されません。価格はいつでも変わる可能性があります。
- 見積もりは、顧客が購入手続きをするときに1回だけ、5秒程度の短いタイムアウトで取得してください。タイムアウトした場合は、同期済みの価格を表示したまま再試行してください。見積もりが遅いことを理由にエラーページを表示しないでください。
- 注文するときは、見積もりの
merchant_priceをexpected_unit_priceとして送ってください。自分で計算した価格ではなく、見積もりで返された価格を送ってください。1セント単位まで完全に一致している必要があります。価格が変わっていた場合、CardVは注文を拒否し、代金は引き落とされません。 - 数量や金額が範囲外の場合、または金額が
amount_stepの倍数でない場合は、HTTP 400とquantityまたはamountのエラーが返ります。
#注文する
POST/api/v1/orders で1つ以上のSKUを購入し、ウォレットから支払います。ほかの呼び出しと同じく、署名が必要です。
{
"external_order_id": "SHOP-20260929-10001",
"items": [
{"sku_id": "S000456", "quantity": 2, "expected_unit_price": "9.25"},
{"sku_id": "S000789", "amount": "25.00", "expected_unit_price": "23.75"},
{
"sku_id": "S000900",
"expected_unit_price": "4.90",
"inputs": {"player_id": "123456789"}
}
]
}| フィールド | 必須 | 意味 |
|---|---|---|
external_order_id | 必須 | 自社の注文番号です。1~120文字で、重複は不可です。 |
items | 必須 | 1つ以上の注文明細です。 |
items[].sku_id | 必須 | 購入するSKUです。 |
items[].quantity | 任意 | 数量です。省略すると1になります。 |
items[].amount | 金額指定型のSKUで必須 | 購入する額面です。min_face_value、max_face_value、amount_step に合わせてください。 |
items[].expected_unit_price | 推奨 | 見積もりで返された merchant_price です。必ず送ってください。 |
items[].inputs | 直接チャージで必須 | 直接チャージのアカウント情報です。 |
CardVが注文を受け付けると、その時点で合計金額がウォレットから引き落とされます。その後、商品の納品がバックグラウンドで始まります。
レスポンスはHTTP 201 です。
{
"idempotent_replay": false,
"order": {
"order_id": "O-00001234",
"external_order_id": "SHOP-20260929-10001",
"status": "accepted",
"total_amount": "46.20",
"...": "more fields"
}
}order.order_id を保存してください。このレスポンスにはコードは含まれません。コードは後で取得します(注文の照会を参照)。
#注文が拒否された場合
注文が拒否されるとHTTP 400が返り、代金は引き落とされません。理由はエラーのキーでわかります。
| キー | 原因 | 対処 |
|---|---|---|
items | 価格が変わった、SKUが購入できない、金額が正しくない、必須情報が足りない | 見積もりを取り直し、内容を直して再送する |
balance | ウォレットの残高不足 | Portalで入金する |
risk | 1回の注文額または1日の上限を超えた | CardVに問い合わせる |
external_order_id | 自社の注文番号が、別の注文ですでに使われている | 安全な再送を参照する |
価格が変わった場合の例:
{
"items": "SKU S000456 price changed from 9.25 to 9.41 USD; refresh quote and confirm again."
}アカウントには、1回の注文額、1日の購入額、1日の注文件数の上限があります。
GET/api/v1/account の purchase_limits で、上限と本日の利用状況を確認できます。
0 は上限なしを意味します。1日の上限は00:00(UTC)にリセットされます。
#安全な再送
自社の注文番号(external_order_id)には、二重購入を防ぐ役割があります。同じ注文番号で同じ注文をもう一度送っても、CardVは再度引き落としません。すでにある注文をそのまま返します。
| 送った内容 | 結果 |
|---|---|
| 新しい注文番号 | HTTP 201。新しい注文が作成され、ウォレットから引き落とされます。 |
| 同じ注文番号で同じ注文 | HTTP 200と "idempotent_replay": true。既存の注文が返り、引き落としはありません。 |
| 同じ注文番号で違う注文 | external_order_id のHTTP 400。何も処理されません。 |
「同じ注文」とは、明細の数と並び順が同じで、各明細のSKU、数量、金額、入力情報もすべて同じであることを指します。
expected_unit_price を送る場合は、最初の注文の価格と一致している必要があります。
重複した注文かどうかは、残高や価格のチェックより前に判定されます。そのため、その後に価格が変わっていても、必ず最初の注文が返ります。
#安全な再送の手順
はっきりした応答が得られなかったときは、同じ注文をそのまま再送してください。
注文番号 R で POST /orders を送信
├─ 201 または 200 → order_id を保存して完了。
├─ 400 items / balance / risk → 注文は作成されていない。
│ 原因を解消して再送する。R はそのまま使ってよい。
├─ 400 external_order_id → R は別の注文で使われている。処理を止めて確認する。
├─ 403 署名エラー → 署名を作り直し、同じ本文を送る。
├─ 429 → Retry-After の秒数だけ待ち、署名を作り直して同じ本文を送る。
└─ タイムアウト、5xx、接続切れ
→ 同じ R で同じ本文をもう一度送る。
201 なら最初の送信は届いていなかった、200 なら届いていた。ルール:
- 応答が届かなかったからといって、新しい注文番号を作らないでください。 最初のリクエストが届いていた場合、すべて二重に購入することになります。
- 再送のたびに、タイムスタンプ、nonce、署名は新しく作ります。本文は変えません。
#注文の照会
GET/api/v1/orders/{order_id} では、注文の内容、ステータス、コードを取得できます。
{
"order_id": "O-00001234",
"external_order_id": "SHOP-20260929-10001",
"status": "succeeded",
"currency": "USD",
"total_amount": "18.50",
"created_at": "2026-09-29T08:15:30.123456Z",
"updated_at": "2026-09-29T08:15:41.004211Z",
"items": [
{
"sku_id": "S000456",
"product_name": "Steam Wallet US",
"quantity": 2,
"unit_price": "9.25",
"total_price": "18.50",
"delivery_count": 2,
"deliveries": [{"...": "see Codes below"}]
}
],
"...": "more fields"
}total_amountは、注文が受け付けられたときに引き落とされた金額です。items[].unit_priceは、この注文で確定した単価です。items[].deliveriesにはコードがそのまま入っています。レスポンス全体を秘密情報として扱ってください。invoice_urlとdelivery_file_urlは、請求書とコードのCSVへのパスです。どちらもPortal専用で、APIキーで呼び出すとHTTP 403が返ります。- ほかに、
id(旧形式の番号。使わないでください)、events(表示用の履歴)、明細ごとの納品の進み具合も返りますが、無視して構いません。 - 存在しない注文IDを指定すると、HTTP 404が返ります。
#注文のステータスとコード
#ステータス
accepted ──► processing ──► succeeded
│
├──► partially_succeeded (一部の明細だけ納品済み)
│
└──► failed ──► refunded (代金はウォレットに返金)| ステータス | 完了か | 対応 |
|---|---|---|
accepted | いいえ | 待ちます。代金は引き落とし済みで、納品はまだ始まっていません。 |
processing | いいえ | 待ちます。もう一度注文しないでください。 |
succeeded | はい | コードを取得し、エンドユーザーに渡します。 |
partially_succeeded | はい | 届いた分を渡します。残りは後で返金されます。 |
failed | まだ | refunded になるまで待ちます。failed の時点ではまだ返金されていません。 |
refunded | はい | 代金がウォレットに戻っています。 |
Webhookを使わない場合は、次の間隔でポーリングしてください:5秒後、10秒後、30秒後、60秒後、その後は5分ごと。レート制限を超えないようにしてください。ほとんどの注文は数秒で完了しますが、手動での確認が必要な注文は数時間かかることがあります。
#コード
納品された商品1個ごとに、items[].deliveries のオブジェクトが1つあります。
{
"status": "stored",
"delivery_type": "card_pin",
"card_number": "X1234",
"pin_code": "9876",
"redeem_url": "",
"expiry_date": "2027-09-29",
"instructions": "Redeem at ..."
}| フィールド | 内容 |
|---|---|
card_number | メインのコード:カード番号、バウチャーコード、またはPIN。 |
pin_code | 2つ目のコード(PINやセキュリティコードなど)。ない場合は空です。 |
redeem_url | 引き換え用リンク。link 形式では、リンクそのものがコードです。 |
expiry_date | コードを使用できる最終日(YYYY-MM-DD 形式)。"" は仕入先が有効期限を提供していないことを意味し、コードの期限切れを意味するわけではありません。 |
- 空でないフィールドはすべてエンドユーザーに渡してください:
card_number、pin_code、redeem_url、expiry_date、instructions。 delivery_typeは受け取った形式を表します:code、card_pin、link、code_link、qr。redeem_urlはコードと同様に、外部に漏れないようにしてください。expiry_dateが空であることを理由に、コードを削除・非表示・無効化しないでください。有効期限は、空でない場合にのみお客様に表示してください。statusがvoidedのものは、エンドユーザーに渡さないでください。- 直接チャージの商品には、通常コードはありません。
succeededはアカウントへのチャージが完了したことを意味します。 - Webhookにはコードは含まれません。Webhookを受け取ったら、注文を照会してください。
連携についてご不明な点は、Merchant ID と注文 ID またはリクエスト ID を添えて [email protected] までお問い合わせください。