SWAPay APIREST · JSON · v1SWAPay-Version 2026-11-07
決済を、
数行のコードで。
PaymentIntent を1つ作って、返ってきた checkout_url にお客様を案内するだけ。カード番号は、あなたのサーバーも SWAPay も通りません。結果は署名つきのウェブフックで届きます。
$ curl https://www.swapay-app.com/api/v1/payment_intents \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: order-1029" \ -d amount=3300 -d currency=jpy
HTTP/1.1 201 Created{ "id": "pi_01jbx3q4w2k8m5n6p7r8s9t0va", "object": "payment_intent", "amount": 3300, "status": "requires_payment_method", "checkout_url": "https://www.swapay-app.com/pay/01jbx3q4w2k8m5n6p7r8s9t0va"}
SWAPay-Signature: t=1762761600,v1=5f2c9a…{
"id": "evt_01jbx9e1v2e3n4t5a6b7c8d9e0",
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_01jbx3q4w2k8m5n6p7r8s9t0va",
"amount": 3300,
"status": "succeeded"
}
}
}料金
API の利用料は、かかりません。
かかるのは決済手数料だけ。
消費税込み。API からの決済も、QR コード・リンク・店頭レジからの決済も同じ率です。
業種・業態と審査の結果によって、ご契約の率が決まります。取扱高の多い事業者さまはご相談ください。
店頭レジ・オンラインストアの月額プランなど、料金の詳しい内容は SWAPay PLUS の料金 をご覧ください。
はじめ方
作って、案内して、受け取る。
加盟店画面の「API管理」でキーを発行したら、あとは3つだけ。検証用のキー(sk_test_)なら、本番のお金を動かさずに最後まで試せます。
curl https://www.swapay-app.com/api/v1/payment_intents \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: order-1029" \ -d amount=3300 \ -d currency=jpy \ -d description="ご注文 1029" \ -d "metadata[order_id]=1029" \ -d return_url=https://shop.example.co.jp/thanks
$ch = curl_init('https://www.swapay-app.com/api/v1/payment_intents'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('SWAPAY_SECRET_KEY'), 'Content-Type: application/json', 'Idempotency-Key: order-1029', ], CURLOPT_POSTFIELDS => json_encode([ 'amount' => 3300, 'currency' => 'jpy', 'description' => 'ご注文 1029', 'metadata' => ['order_id' => '1029'], 'return_url' => 'https://shop.example.co.jp/thanks', ]), ]); $pi = json_decode(curl_exec($ch), true);
const r = await fetch('https://www.swapay-app.com/api/v1/payment_intents', { method: 'POST', headers: { Authorization: `Bearer ${process.env.SWAPAY_SECRET_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-1029', }, body: JSON.stringify({ amount: 3300, currency: 'jpy', description: 'ご注文 1029', metadata: { order_id: '1029' }, return_url: 'https://shop.example.co.jp/thanks', }), }); const pi = await r.json();
# 返ってきた checkout_url に、お客様を案内します { "id": "pi_01jbx3q4w2k8m5n6p7r8s9t0va", "object": "payment_intent", "amount": 3300, "status": "requires_payment_method", "checkout_url": "https://www.swapay-app.com/pay/01jbx3q4w2k8m5n6p7r8s9t0va" }
// お客様の画面を、SWAPay の決済画面へ header('Location: ' . $pi['checkout_url'], true, 303); exit; // 支払いが終わると return_url に戻ります。 // 注文の確定は、戻り先ではなくウェブフックで。
// お客様の画面を、SWAPay の決済画面へ(Express の例) res.redirect(303, pi.checkout_url); // 支払いが終わると return_url に戻ります。 // 注文の確定は、戻り先ではなくウェブフックで。
# 届くウェブフックの本文(POST・application/json) # ヘッダー SWAPay-Signature: t=…,v1=… { "id": "evt_01jbx9e1v2e3n4t5a6b7c8d9e0", "object": "event", "type": "payment_intent.succeeded", "api_version": "2026-11-07", "data": { "object": { "id": "pi_01jbx3q4w2k8m5n6p7r8s9t0va", "object": "payment_intent", "amount": 3300, "amount_received": 3300, "status": "succeeded", "metadata": { "order_id": "1029" } } } }
$payload = file_get_contents('php://input'); $header = $_SERVER['HTTP_SWAPAY_SIGNATURE'] ?? ''; // t=<UNIX秒>,v1=<署名>(鍵の入れ替え中は v1 が2つ) $t = 0; $sigs = []; foreach (explode(',', $header) as $part) { [$k, $v] = array_pad(explode('=', $part, 2), 2, ''); if ($k === 't') $t = (int) $v; if ($k === 'v1') $sigs[] = $v; } $expected = hash_hmac('sha256', $t . '.' . $payload, getenv('SWAPAY_WEBHOOK_SECRET')); $ok = abs(time() - $t) <= 300 && array_filter($sigs, fn ($s) => hash_equals($expected, $s)); if (!$ok) { http_response_code(400); exit; } $event = json_decode($payload, true); if ($event['type'] === 'payment_intent.succeeded') { // 注文を「支払い済み」に(同じ event.id は1回だけ処理) } http_response_code(200);
import crypto from 'node:crypto'; app.post('/webhooks/swapay', express.raw({ type: 'application/json' }), (req, res) => { const header = req.get('SWAPay-Signature') ?? ''; let t = 0; const sigs = []; for (const part of header.split(',')) { const [k, v] = part.split('='); if (k === 't') t = Number(v); if (k === 'v1') sigs.push(v); } const expected = crypto.createHmac('sha256', process.env.SWAPAY_WEBHOOK_SECRET) .update(`${t}.${req.body}`).digest('hex'); const ok = Math.abs(Date.now() / 1000 - t) <= 300 && sigs.some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected))); if (!ok) return res.sendStatus(400); const event = JSON.parse(req.body); if (event.type === 'payment_intent.succeeded') { // 注文を「支払い済み」に(同じ event.id は1回だけ処理) } res.sendStatus(200); });
エンドポイント https://www.swapay-app.com/api/v1 すべてのリクエストに Authorization: Bearer <キー>
PaymentIntent の状態
ひとつの決済は、ひとつのオブジェクトで追えます。
requires_payment_method作った直後。お客様が決済画面でお支払い方法を選ぶのを待っています。
requires_action3D セキュアの認証中。お客様の操作を待っています。
processingスマホ決済などの結果待ち。届きしだい次へ進みます。
succeeded支払い完了。payment_intent.succeeded が届きます。
期限を過ぎたもの・取り消したものは canceled。取消返金は /refunds で、全額でも一部でも。
ウェブフック・送り直し
通信が切れても、取りこぼさない。
二重にも決済しない。
- 署名つきで届くヘッダー
SWAPay-Signatureの v1 と、「t.本文」を署名用シークレットで HMAC-SHA256 した値を比べます。時刻が5分以上ずれていれば受け付けないでください。 - 2xx を返すまで送り直す同じイベントは同じ id で届くので、id で重複を除いてください。届かなかったときは
GET /eventsで30日分を確かめられます。 - Idempotency-Key で二重決済を防ぐPOST に付けると、同じ値で送り直したときは最初の結果を返します(7日間)。違う内容で同じキーを使うとエラーで止まります。
- エラーは同じ形で決済代行会社の生のエラーは返しません。
retryableが true のときだけ、同じ Idempotency-Key で送り直してください。
{
"error": {
"type": "invalid_request",
"code": "parameter_invalid",
"message": "amount は 1 以上にしてください。",
"param": "amount",
"retryable": false,
"request_id": "req_01jbx…"
}
}送り直しの間隔
2xx が返らないときは、間隔をあけて最大16回送ります。最後の送り直しは、1回目の52時間51分後です。
時間の目盛りは対数です(はじめは短い間隔で、だんだん長く)。
API の一覧
決済のあとまで、API で。
加盟店画面でできることの多くを、あなたのシステムから。項目の詳しい説明は API リファレンスと OpenAPI をご覧ください。
決済
- POST/payment_intents
- GET/payment_intents/{id}
- GET/payment_intents
- POST/payment_intents/{id}/cancel
- GET/charges
- ほか 1
取消返金
- POST/refunds
- GET/refunds/{id}
- GET/refunds
リンク決済・QR コード
- POST/payment_links
- GET/payment_links/{id}
- POST/payment_links/{id}
- POST/qr_codes
請求書
- POST/invoices
- POST/invoices/{id}/send
サブスクリプション
- GET/prices
- POST/subscriptions
- GET/subscriptions/{id}
- POST/subscriptions/{id}/cancel
- POST/subscriptions/{id}/pause
顧客・カードの登録
- POST/setup_sessions
- GET/setup_sessions/{id}
- GET/setup_sessions
- POST/setup_sessions/{id}/cancel
- GET/payment_methods
- ほか 7
精算
- GET/settlements
イベント
- GET/events
sk_test_検証環境のキー。本番のお金を動かさずに試せます。本番と検証のキーを取り違えるとエラーで止まります。
sk_live_本番のキー。発行したときに一度だけ表示し、SWAPay はハッシュだけを保存します。使える IP アドレスを絞れます。
rk_権限を絞った制限付きキー。読み取りだけ・決済だけ、など用途ごとに分けられます。
応答の形はキーを作った日の版(SWAPay-Version)に固定されます。いまの版は 2026-11-07。OpenAPI(JSON)
まずは検証用のキーで。
加盟店のお申し込みがお済みでない方は、SWAPay PLUS からお申し込みください。
旧 API との違い
| 旧 API | 新しい API |
|---|---|
POST /v1/order → payment_url | POST /payment_intents → checkout_url |
Authorization: <キー> | Authorization: Bearer sk_… |
金額は小数(1000.0) | 金額は整数(1000) |
注文ごとの callback_url | 署名つきのウェブフック |
| カード番号を API で送る決済 | 決済画面で入力(API では受け付けません) |