開発者/連携
商品と注文
このガイドでは、購入の流れを最初から最後まで説明します。残高の確認、商品の検索、価格の確認、注文、コードの受け取りの順に進みます。
#アカウントと残高
#アカウント
GET/api/v1/account では、貴社の会社情報と、APIが有効になっているかどうかを確認できます。
{
"merchant_id": "M00000001",
"name": "Acme Shop",
"legal_name": "Acme Shop Ltd",
"tier": "standard",
"billing_email": "[email protected]",
"status": "active",
"kyb_status": "approved",
"api_access_enabled": true,
"default_currency": "USD"
}default_currencyはウォレットの通貨です。支払う金額はすべてこの通貨で表示されます。api_access_enabledは、CardVが貴社の審査を承認するとtrueになります。
#残高
GET/api/v1/balance では、使える残高を確認できます。
{
"currency": "USD",
"balance": "1520.4000",
"reserved_amount": "0.0000",
"available_balance": "1520.4000",
"low_balance_threshold": "200.0000",
"low_balance_notified_at": null,
"is_active": true
}available_balanceは、今すぐ使える金額です。balanceからreserved_amountを引いた額です。available_balanceを超える注文は拒否され、代金は引き落とされません。low_balance_thresholdは、残高不足のメール通知が届く基準額です。Portalで設定できます。- 入金はPortalで行ってください。
#商品(SKU)
SKUとは、購入できる1つの商品のことです。たとえば「Steam Wallet 10 USD」が1つのSKUです。IDは S000456 のような形です。見積もりと注文はSKU単位で行います。
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 | 国コードまたは国名 |
vertical | gift_card | 商品カテゴリー |
product_type | pin_code | 受け取り方法 |
ページング:limit(初期値100、上限500)と offset を指定します。
offset を増やしながら、offset が count に達するまで取得を続けてください。
{
"count": 7,
"limit": 1,
"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.0000",
"face_currency": "USD",
"merchant_price": "9.2500",
"settlement_currency": "USD",
"availability": "available",
"min_quantity": 1,
"max_quantity": 100,
"required_input_schema": [],
"...": "more fields"
}
],
"filter_options": {"brands": [], "regions": [], "verticals": []}
}GET/api/v1/skus/{sku_id} では、同じフィールドを持つ1つのSKUを取得できます。
特によく使うフィールド:
| フィールド | 意味 |
|---|---|
sku_id | 見積もりと注文に使うIDです。 |
merchant_price | 貴社の1個あたりの購入価格です。通貨は settlement_currency です。 |
availability | available または unavailable。注文できるのは available のSKUだけです。 |
denomination_type | fixed または range。固定額と金額指定を参照してください。 |
face_currency | カードに記載されている通貨です。ウォレットの通貨と異なる場合があります。 |
min_quantity, max_quantity | 1つの注文明細で指定できる数量の範囲です。 |
product_type | pin_code(コードを受け取る)または direct_charge(CardVがアカウントに直接チャージする)。 |
required_input_schema | 直接チャージで送る必要がある情報です。 |
brand_logo_url, image_url | CardVが提供する画像、または "" です。 |
description, redemption_instructions, terms | エンドユーザー向けに表示できる説明文です。 |
ポイント:
- 表示されるのは、有効で、かつ貴社のアカウントで購入できるSKUだけです。それ以外のSKUには404が返ります。
- SKU一覧は5~15分ごとに同期してください。注文の直前には、必ず見積もりを取ってください。
filter_optionsには、絞り込みに使えるブランド、地域、商品カテゴリーが入っています。
#固定額と金額指定
ほとんどの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 です。
#直接チャージ
一部の商品は、ゲームのアカウントなど、エンドユーザーのアカウントに直接チャージします。この場合、CardVはチャージ先のアカウント情報を必要とします。必要な項目はSKUに記載されています。
"required_input_schema": [
{"key": "player_id", "label": "Player ID", "required": true},
{"key": "server", "label": "Server", "required": false}
]注文明細の inputs に、各 key を使って値を入れて送ります。
"inputs": {"player_id": "123456789", "server": "EU"}"required": falseと書かれていない項目は必須です。- 必須の値が抜けていると、注文は
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.2500",
"quantity": 2,
"total_price": "18.5000",
"min_quantity": 1,
"max_quantity": 100,
"availability": "available"
}- 見積もりを取っても、価格は確保されません。価格はいつでも変わる可能性があります。
- 注文するときは、見積もりの
merchant_priceをexpected_unit_priceとして送ってください。価格が変わっていた場合、CardVは注文を拒否し、代金は引き落とされません。 - 数量や金額が範囲外の場合は、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.2500"},
{"sku_id": "S000789", "amount": "25.00", "expected_unit_price": "23.7500"},
{
"sku_id": "S000900",
"expected_unit_price": "4.9000",
"inputs": {"player_id": "123456789"}
}
]
}| フィールド | 必須 | 意味 |
|---|---|---|
external_order_id | 必須 | 自社の注文番号です。1~120文字で、重複は不可です。 |
items | 必須 | 1つ以上の注文明細です。 |
items[].sku_id | 必須 | 購入するSKUです。 |
items[].quantity | 任意 | 数量です。省略すると1になります。 |
items[].amount | 金額指定型のSKUで必須 | 購入する額面です。 |
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.2000",
"...": "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.2500 to 9.4100 USD; refresh quote and confirm again."
}1回の注文額、1日の購入額、1日の注文件数の上限は、アカウントの契約プランによって決まります。 1日の上限は00:00(UTC)にリセットされます。貴社の上限はCardVにお問い合わせください。
#安全な再送
自社の注文番号(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.5000",
"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.2500",
"total_price": "18.5000",
"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",
"display_fields": [
{"key": "card_number", "label": "Card number", "value": "X1234", "kind": "secret"},
{"key": "pin_code", "label": "PIN", "value": "9876", "kind": "secret"}
],
"redeem_url": "",
"expiry_date": "2027-09-29",
"instructions": "Redeem at ...",
"is_masked": false
}- エンドユーザーには
display_fieldsを表示してください。各項目にlabelとvalueがあります。redeem_url、expiry_date、instructionsも、空でなければ表示してください。 kindは、コードやPINならsecret、シリアル番号などならreferenceです。delivery_typeは受け取った形式を表します:code、card_pin、link、code_link、qr。新しい形式が追加されることがあるため、表示は必ずdisplay_fieldsをもとに組み立ててください。link形式では、redeem_urlそのものがコードです。外部に漏れないようにしてください。statusがvoidedのものは、エンドユーザーに渡さないでください。- 直接チャージの商品には、通常コードはありません。
succeededはアカウントへのチャージが完了したことを意味します。 card_numberやpin_codeなどは、別のフィールドにも同じ値が入っています。空の場合もあります。- Webhookにはコードは含まれません。Webhookを受け取ったら、注文を照会してください。
連携についてご不明な点は、Merchant ID と注文 ID またはリクエスト ID を添えて [email protected] までお問い合わせください。