開発者/連携

商品と注文

このガイドでは、購入の流れを最初から最後まで説明します。残高の確認、商品の検索、価格の確認、注文、コードの受け取りの順に進みます。

関連ドキュメント:認証 · 共通ルール · Webhook

#アカウントと残高

#アカウント

GET/api/v1/account では、貴社の会社情報と、APIが有効になっているかどうかを確認できます。

JSON
{
  "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 では、使える残高を確認できます。

JSON
{
  "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の一覧を取得できます。例:

HTTP
GET /api/v1/skus?search=steam&region=US&limit=50&offset=0

絞り込み条件(すべて任意):

条件例対象
searchsteamSKU ID、商品名、ブランド
brandSteamブランド名(大文字・小文字は区別しません)
regionUS国コードまたは国名
verticalgift_card商品カテゴリー
product_typepin_code受け取り方法

ページング:limit(初期値100、上限500)と offset を指定します。 offset を増やしながら、offset が count に達するまで取得を続けてください。

JSON
{
  "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 です。
availabilityavailable または unavailable。注文できるのは available のSKUだけです。
denomination_typefixed または range。固定額と金額指定を参照してください。
face_currencyカードに記載されている通貨です。ウォレットの通貨と異なる場合があります。
min_quantity, max_quantity1つの注文明細で指定できる数量の範囲です。
product_typepin_code(コードを受け取る)または direct_charge(CardVがアカウントに直接チャージする)。
required_input_schema直接チャージで送る必要がある情報です。
brand_logo_url, image_urlCardVが提供する画像、または "" です。
description, redemption_instructions, termsエンドユーザー向けに表示できる説明文です。

ポイント:

  • 表示されるのは、有効で、かつ貴社のアカウントで購入できるSKUだけです。それ以外のSKUには404が返ります。
  • SKU一覧は5~15分ごとに同期してください。注文の直前には、必ず見積もりを取ってください。
  • filter_options には、絞り込みに使えるブランド、地域、商品カテゴリーが入っています。

#固定額と金額指定

ほとんどのSKUは、10 USDのように額面が固定されています。一部のSKUは金額指定型で、5~500 USDのようにエンドユーザーが金額を選べます。

種類見積もりのとき注文のとき
fixedquantity を送るamount は送らない
rangequantity と amount を送るamount を送る

金額指定型のSKUでは、amount を min_face_value 以上、max_face_value 以下にしてください。 amount の通貨は face_currency です。

#直接チャージ

一部の商品は、ゲームのアカウントなど、エンドユーザーのアカウントに直接チャージします。この場合、CardVはチャージ先のアカウント情報を必要とします。必要な項目はSKUに記載されています。

JSON
"required_input_schema": [
  {"key": "player_id", "label": "Player ID", "required": true},
  {"key": "server", "label": "Server", "required": false}
]

注文明細の inputs に、各 key を使って値を入れて送ります。

JSON
"inputs": {"player_id": "123456789", "server": "EU"}
  • "required": false と書かれていない項目は必須です。
  • 必須の値が抜けていると、注文は items エラーで拒否されます。
  • これらの値はエンドユーザーの個人情報です。大切に扱ってください(セキュリティを参照)。

#見積もり

見積もりでは、指定した数量での現在の価格がわかります。

HTTP
GET /api/v1/skus/S000456/quote?quantity=2
GET /api/v1/skus/S000789/quote?quantity=1&amount=25.00
JSON
{
  "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を購入し、ウォレットから支払います。この呼び出しには署名が必要です。

JSON
{
  "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 です。

JSON
{
  "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で入金する
risk1回の注文額または1日の上限を超えたCardVに問い合わせる
external_order_id自社の注文番号が、別の注文ですでに使われている安全な再送を参照する

価格が変わった場合の例:

JSON
{
  "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 を送る場合は、最初の注文の価格と一致している必要があります。

重複した注文かどうかは、残高や価格のチェックより前に判定されます。そのため、その後に価格が変わっていても、必ず最初の注文が返ります。

#安全な再送の手順

はっきりした応答が得られなかったときは、同じ注文をそのまま再送してください。

Text
注文番号 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} では、注文の内容、ステータス、コードを取得できます。

JSON
{
  "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が返ります。

#注文のステータスとコード

#ステータス

Text
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つあります。

JSON
{
  "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] までお問い合わせください。