メインコンテンツへスキップ

Documentation Index

Fetch the complete documentation index at: https://docs.zafapay.com/llms.txt

Use this file to discover all available pages before exploring further.

概要

サーバー間決済(S2S)では、ホスト型チェックアウトページの代わりに、自社の決済フォームでカード情報を収集できます。カードデータはJavaScript SDKを使用してブラウザ上で安全にトークン化され、そのトークンをサーバーに送信して決済を作成します。
S2S統合にはPCI SAQ A-EP準拠が必要です。PCI準拠レベルが不明な場合は、ホスト型チェックアウトをご利用ください。

仕組み

1

ブラウザでカード情報をトークン化

公開キーpk_live_* / pk_test_*)を使用して POST /v1/tokens でカード情報をトークン化します。JavaScript SDKまたはAPI直接呼び出しが使用できます。生のカード番号がサーバーに送信されることはありません。
2

決済を作成

tok_* トークンをバックエンドに送信し、シークレットアクセストークンを使用して token パラメータ付きで POST /v1/payments を呼び出します。
3

3Dセキュアの処理(必要な場合)

レスポンスのステータスが requires_action の場合、顧客を redirect_url にリダイレクトして3Dセキュア認証を完了させます。

統合手順

1. カード情報のトークン化

決済ページでカード情報を収集し、公開キーを使用して POST /v1/tokens に送信します。JavaScript SDKを使用するか、APIを直接呼び出すことができます。
// 読み込み: <script src="https://js.zafapay.com/v1/zafapay.js"></script>
const zafapay = Zafapay('pk_test_xxxxx');

try {
  const { token, card } = await zafapay.createToken({
    number: '4242424242424242',
    exp_month: 12,
    exp_year: 2027,
    cvc: '123',
    cardholder_name: 'John Doe'  // 任意
  });

  console.log(token);      // "tok_xxxxxxxxxxxxxxxxxxxxxx"
  console.log(card.brand);  // "visa"
  console.log(card.last4);  // "4242"

  // トークンをサーバーに送信
  await fetch('/your-server/pay', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token, amount: 1000, currency: 'jpy' })
  });
} catch (error) {
  console.error(error.message);
}
レスポンスのプロパティ:
フィールド説明
idトークンID(tok_ プレフィックス)。有効期限30分、1回のみ使用可能。
card.last4下4桁
card.brandカードブランド(visa, mastercard, amex 等)
card.exp_month有効期限(月)
card.exp_year有効期限(年)
expires_atトークンの有効期限(ISO 8601形式)
JavaScript SDKは便宜上、トークンIDを id ではなく token として返します。APIを直接呼び出す場合、フィールド名は id です。

2. トークンで決済を作成

サーバーサイドで、トークンを使って POST /v1/payments を呼び出します。
curl -X POST https://api.sandbox.zafapay.com/v1/payments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "jpy",
    "token": "tok_xxxxxxxxxxxxxxxxxxxxxx",
    "return_url": "https://your-site.com/payment-complete",
    "external_id": "order_12345"
  }'

3. レスポンスの処理

レスポンスのステータスによって次のアクションが決まります:
ステータスHTTPコードアクション
completed201決済成功。成功ページを表示。
authorized201オーソリ成功(capture_method: "manual" の場合)。後でキャプチャ。
requires_action2023Dセキュアが必要。顧客を redirect_url にリダイレクト。
failed400決済失敗。エラーを顧客に表示。
3Dセキュアの処理:
const payment = await response.json();

if (payment.status === 'requires_action') {
  // 顧客を3DS認証ページにリダイレクト
  window.location.href = payment.redirect_url;
  // 3DS完了後、顧客はreturn_urlにリダイレクトされます
}
S2S決済では必ず return_url を指定してください。3Dセキュアが発生した場合、認証後に顧客はこのURLに status=succeeded または status=failed のクエリパラメータ付きでリダイレクトされます。return_url がない場合、3DS後のリダイレクト先がなくなります。

カード保存と継続決済

S2Sトークン決済時に save_card: truecustomer_id を追加することで、顧客のカード情報を保存できます。決済完了後(3Dセキュアを含む)、カードが保存され、Webhookで payment_method_id が返されます。

リクエスト

curl -X POST https://api.sandbox.zafapay.com/v1/payments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "jpy",
    "token": "tok_xxxxxxxxxxxxxxxxxxxxxx",
    "customer_id": "cust_abc123",
    "save_card": true,
    "return_url": "https://your-site.com/payment-complete",
    "external_id": "order_12345"
  }'
save_card
boolean
true を指定すると、決済完了後にカード情報が保存されます。
customer_id
string
save_cardtrue の場合は必須。顧客を識別する一意のID。

Webhook

決済完了時のWebhookに、保存された payment_method_id が含まれます:
{
  "event": "payment.succeeded",
  "transaction_id": "tx_abc123",
  "status": "succeeded",
  "amount": "1000",
  "currency": "jpy",
  "external_id": "order_12345",
  "payment_method": "card",
  "payment_method_id": "pmi_xyz789",
  "save_card": true,
  "is_recurring": false,
  "customer_id": "cust_abc123",
  "card_brand": "visa",
  "card_last4": "4242",
  "card_country": "JP",
  "card_funding": "credit",
  "metadata": {},
  "created_at": "2026-04-08T10:00:00.000Z",
  "timestamp": "2026-04-08T10:00:05.000Z"
}

2回目以降の継続決済

保存された payment_method_id を使用して、カード入力やトークン化なしで課金できます:
curl -X POST https://api.sandbox.zafapay.com/v1/payments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "jpy",
    "customer_id": "cust_abc123",
    "payment_method_id": "pmi_xyz789",
    "external_id": "subscription_renewal_002"
  }'
保存済みカードの管理や継続決済の失敗処理の詳細は、継続決済(リカーリング)をご覧ください。

完全な実装例

クライアントサイド(ブラウザ)

<form id="payment-form">
  <input type="text" id="card-number" placeholder="カード番号" />
  <input type="text" id="card-expiry-month" placeholder="MM" />
  <input type="text" id="card-expiry-year" placeholder="YYYY" />
  <input type="text" id="card-cvc" placeholder="CVC" />
  <input type="text" id="cardholder-name" placeholder="カード名義" />
  <button type="submit">¥1,000 を支払う</button>
</form>

<script src="https://js.zafapay.com/v1/zafapay.js"></script>
<script>
const zafapay = Zafapay('pk_test_xxxxx');

document.getElementById('payment-form').addEventListener('submit', async (e) => {
  e.preventDefault();

  try {
    // 1. カードをトークン化
    const { token } = await zafapay.createToken({
      number: document.getElementById('card-number').value,
      exp_month: parseInt(document.getElementById('card-expiry-month').value),
      exp_year: parseInt(document.getElementById('card-expiry-year').value),
      cvc: document.getElementById('card-cvc').value,
      cardholder_name: document.getElementById('cardholder-name').value
    });

    // 2. トークンをサーバーに送信
    const response = await fetch('/api/pay', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token })
    });

    const payment = await response.json();

    // 3. 結果を処理
    if (payment.status === 'requires_action') {
      window.location.href = payment.redirect_url;
    } else if (payment.status === 'completed' || payment.status === 'authorized') {
      window.location.href = '/success';
    } else {
      alert('決済失敗: ' + payment.error?.message);
    }
  } catch (error) {
    alert('エラー: ' + error.message);
  }
});
</script>

サーバーサイド

const express = require('express');
const app = express();
app.use(express.json());

app.post('/api/pay', async (req, res) => {
  const { token } = req.body;

  // 本番環境では、金額・通貨を注文データベースから取得してください
  const response = await fetch('https://api.sandbox.zafapay.com/v1/payments', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      amount: 1000,
      currency: 'jpy',
      token,
      return_url: 'https://your-site.com/payment-complete',
      external_id: `order_${Date.now()}`
    })
  });

  const payment = await response.json();
  res.json(payment);
});

公開キー

公開キー(pk_test_* / pk_live_*)は、ブラウザからのトークン化リクエストの認証に使用されます。トークンの作成のみに使用でき、決済、顧客情報、その他のAPIリソースにはアクセスできません。 公開キーは加盟店管理画面の 加盟店設定 > API設定 から取得できます。 詳細は認証をご覧ください。

テストカード

カード番号説明
4242424242424242決済成功
40000025000031553Dセキュア必要
4000000000000002拒否
4000000000009995残高不足
APIパラメータとレスポンスの詳細は、決済作成 APIリファレンスおよびトークン作成 APIリファレンスをご覧ください。