Nexus - 決済アプリプロバイダー向け

注) 本ドキュメントはNexusの導入を検討している決済事業者様向けのドキュメントです。

Nexusで決済を導入したい加盟店様はこちらを御覧ください。

概要

KOMOJU Nexus は、すべての決済アプリでの決済を実現するソリューションです。 Nexus を使用すれば、加盟店は統一的なQRコードを生成することができ、このQRコードは決済アプリのカメラまたはモバイルのシステムカメラでスキャンすることができます。

このソリューションは決済サービスプロバイダー(以下、プロバイダー)が提供する決済方法を有効にしているすべての加盟店の決済を処理します。カスタマーはプロバイダーの決済アプリを使い、Nexus QRコードをスキャンすることで決済できます。

用語集

用語 説明
プロバイダー 決済サービスを運営している組織
クライアント プロバイダーが提供する決済アプリ
バックエンド プロバイダーの運営するサービスのバックエンド
加盟店 オンラインまたはオフラインで商品やサービスを販売する法人または個人
カスタマー 加盟店から商品やサービスを購入する人

動作概要

  1. カスタマーがクライアントアプリまたはシステムカメラで Nexus QR コードをスキャンします。
  2. クライアントアプリが Authorization リクエストを Nexus 経由でプロバイダーに送信します。
  3. Authorization レスポンスを用いて、クライアントアプリが決済をキャプチャします。
  4. プロバイダーは決済の完了を通知するため、 Nexus にコールバックを送信します。

How it works

導入について

Nexusの導入についての全体の概要です。

  1. Nexus プロバイダーとして登録します。
  2. テスト用のツールについて弊社から連絡を差し上げます。
  3. 御社にてインテグレーションの開発していただきます。クライアントインテグレーションバックエンドインテグレーションをご参照ください。
  4. リリース可能であることを弊社までご連絡ください。
  5. 本番リリース。

プロバイダーの登録

あなたの決済サービスをNexusで利用可能にするためには、Nexusへのプロバイダーの登録が必要です。登録についてはcontact@komoju.comまでご連絡ください。

プロバイダーの登録には以下の情報が必要です。

  • プロバイダーのドメイン名
    • Nexus とプロバイダーとの通信を行うためのドメイン名
    • 例: examplepay.com
  • APIパス
    • Nexusが Authorization と返金のリクエストのために使用します。
    • 例: APIパスが "/nexus/api" の場合、Nexusのリクエストは "https://examplepay.com/nexus/api" に送信されます。
    • 詳細は バックエンドインテグレーションを御覧ください。
  • モバイルランディングパス
    • ディープリンクまたはapp-schemeによりユーザーのウェブブラウザから直接クライアントアプリを開くためのパスです。
    • 例: モバイルランディングパスが "/nexus/activate" の場合、カスタマーを "https://examplepay.com/nexus/activate" にリダイレクトします。
    • 詳細はユースケースを御覧ください。
  • プロバイダー名
    • クライアントを一意に識別するための名前です。英数字と "-" のみ使用できます。
    • 例: "example-pay"
  • 公開鍵
    • PEMフォーマット
    • RSAとECDSAがサポートされています。
    • 認証についてをご確認ください。

登録が完了すれば、クライアントインテグレーションバックエンドインテグレーションを開始することができます。

クライアントインテグレーション

本セクションではあなたのクライアントにNexusを組み込むための開発について説明します。 (クライアントは一般的にはモバイルアプリですが、その他のもの、例えばウェブサイトでも可能です)

決済の流れはまず、クライアントが Nexus Linkを発見するところから始まります。

このドキュメントでは、Nexusリンクの例をいくつか示します:

  • https://komoju.com/s/p/dc1y676t3m59hdxx89lfhr6p0
  • https://komoju.com/s/p/xxxxx
  • etc.

URLの正確なフォーマットは将来変更になる可能性があります。 Nexusリンクかどうかを判定する方法は検証ステップをご参照ください。

ユースケース

クライアントがインテグレーション開発を通してサポートしなければならないユースケースは大きく分けて2つあります。1つはデスクトップやその他クライアント外の決済でのQRコードのスキャン、もう1つはクライアント内部での決済ではリダイレクトの仕組みです。

また、これらの2つのシナリオを「Nexus Linkの発見」と呼びます。

ユースケース1: モバイル以外のデバイスで作成された決済をQRコードにより処理する

デスクトップのアプリケーションやウェブサイトで作成された決済を処理するため、NexusはQRコードを表示し、カスタマーにQRコードのスキャンによる支払いを促します。

Nexus QRコードの例:

Case 1

カスタマーがクライアントアプリでQRコードをスキャンしたら、QRコードのデータをNexus Linkとして、NexusのHTTP APIを呼び出すことができます。

ユースケース2: モバイルデバイスで作成された決済をリダイレクトにより処理する

モバイルのウェブサイトやアプリで作成された決済を処理するとき、NexusはカスタマーをプロバイダーのモバイルランディングURLに以下の形式でリダイレクトさせます。

https://{endpoint}{mobile_landing_path}?nexus_link=https://komoju.com/s/p/xxxxxxxx

endpointmobile_landing_pathは、プロバイダー登録時に指定された情報です。

この場合にどのような処理をするかはプロバイダー次第です。一般的には、ディープリンクやapp-schemeを使用してクライアントアプリを起動します。あるいは、決済情報をweb上に表示することもできます。どちらの方法でも、nexus_link のパラメータをNexus LinkとしてNexusの HTTP APIが呼ばれることが期待されます。

Nexus経由で決済を完了する

Nexus Linkを発見するとすぐに決済の処理を開始できます。 Nexusの決済フローは検証、承認、そしてキャプチャのシンプルな3ステップです。

ClientClientNexusNexusProviderProvider1. VerifyGET https://komoju.com/s/p/xxxxxContent-Type "application/vnd.nexus-link+json"2. AuthorizePOST https://komoju.com/s/p/xxxxx{"provider": "provider-name"}Reserve Payment APIsuccesssuccess3. CaptureCapture paymentCapture callback

これら3つのステップはNexusのサーバーとプロバイダーのサーバーのなりすましを防ぐようにデザインされています。 Nexusになりすました不正なサーバーは決済の承認を実施することができません。また、プロバイダーになりすましたサーバーはキャプチャコールバックを送信することができません。詳しくは認証の項をご確認ください。

ClientClientNexusNexusProviderProviderGET https://komoju.com/s/p/xxxxxContent-Type "application/vnd.nexus-link+json"

Nexus Linkを発見した後、クライアントは必ずNexus Linkの検証を実施しなければなりません。 検証するにはまず、GETリクエストを発見したNexus Linkに送信してください。

## Request
GET https://komoju.com/s/p/xxxxx HTTP/1.1
Content-Type: application/json

## Response
200 HTTP/1.1
Content-Type: application/vnd.nexus-link+json
Nexus-Signature: aaaaaabbbbbbccccccdddddd...

{
  "id": "dc1y676t3m59hdxx89lfhr6p0",
  "resource": "session",
  "type": "payment",
  "timestamp": 11111111
}

レスポンスに含まれるContent-Typeヘッダーがapplication/vnd.nexus-link+jsonであることを確認してください。 また、Nexus-Signature認証の項で説明されている方法で検証してください。

このステップは、クライアントが盲目的に任意のエンドポイントへ承認リクエストを送ることを防ぎます。

注意)Nexus Linkのホスト名を検証に使用しないでください。使用されているドメイン名は将来的に予告なく変更される可能性があります。

Step 2: Nexus経由で決済を承認する

ClientClientNexusNexusProviderProviderPOST https://komoju.com/s/p/xxxxx{"provider": "provider-name"}Reserve Payment APIsuccesssuccess

検証後、クライアントはPOSTリクエストをNexus Linkに送信します。provider パラメータはNexusに登録時に指定したプロバイダー名です。

## Request
POST https://komoju.com/s/p/dc1y676t3m59hdxx89lfhr6p0 HTTP/1.1
Content-Type: application/json

{
  "provider": "your-provider-name-here"
}

## Response
200 HTTP/1.1

{
  "id": "dc1y676t3m59hdxx89lfhr6p0",
  "type": "payment",
  "payment": {
    "id": "1zk24mmsez27d369pp7wqaoen",
    "status": "authorized",
    "amount": 1000,
    "currency": "JPY",
    "payment_details": {
      "type": "nexus",
      "authorization_response_text": "your backend’s response body here"
    },
    ...
  }
}

このリクエストが送信されると、Nexusは同期的に承認リクエストをプロバイダーに送信します。 プロバイダーが返却したレスポンスのボディはそのままの形でpayment.payment_details.authorization_response_textに含まれています。

Step 3. 決済をバックエンドを通じてキャプチャする

ClientClientNexusNexusProviderProviderCapture paymentCapture callback

実際に決済をキャプチャする前に、ユーザーに決済の確認を促すようにしてください。残高の表示、決済金額の表示等を実施し、本当に決済を実行してよいか確認してください。

authorization_response_textに含まれる情報を使用することで、クライアントはバックエンドを通じて直接決済をキャプチャします。クライアントとバックエンドのコミュニケーションについてはプロバイダー次第ですので、本ドキュメントでは規定しません。 キャプチャが成功したら、プロバイダーはコールバックをNexusに送信してください

バックエンドインテグレーション

Nexusとの決済承認、返金、決済完了時のコールバック通知のやりとりのためにバックエンド実装が必要です。 プロバイダーとNexus間の安全性確保のため、すべてのリクエストはSHA-2 HMACによりデジタル署名されます。 詳細については認証の項をご参照ください。

Nexusのインテグレーション

機能1: Nexusからの承認リクエストの受信

Nexusは決済を承認するために、プロバイダーに決済の予約リクエストを送信します。このリクエストを処理するため、プロバイダーはプロバイダー側で同期的に決済を作成、承認します。


POST https://provider/path/to/handler HTTP/1.1
Content-Type: application/json
Nexus-Signature: xxxxxxxxxx

{
  "type": "payment.create",
  "mode": "test",
  "payment": {
    "id": "86rzkcrvcf82s0audo5himdi3",
    "amount": 1000,
    "currency": "JPY",
    "description": "",
    "merchant": {
      "id": "9ccxr6ymcpsyq4fupp7qb6arl",
      "name": "Komoju Mart"
    }
  }
}
注意)決済はこのステップはまだキャプチャされていません。キャプチャは、カスタマーの確認の後にクライアントとバックエンドの間で直接発生します。Nexusがキャプチャのリクエストをプロバイダーに送信することはありません。

決済の承認時、プロバイダーは任意のレスポンスボディを返却することができます。キャプチャはクライアントとプロバイダーの間で直接(Nexusを通さずに)発生するため、キャプチャに必要となるすべての情報(内部的なIDなど)を含めることを推奨します。


HTTP/1.1 200
Content-Type: application/json

{
  "success": true,
  "my_internal_transaction_id": "abc123xyz"
}

このような任意のレスポンスはpayment.payment_details.authorization_response_textフィールドを通じてクライアントが参照することができます。類似の例はこちらにあります。

機能2: Nexusからの返金リクエストの受信

Nexusは、カスタマーや加盟店からの要請に応じて、返金リクエストをプロバイダーに送信します。

POST https://provider/path/to/handler HTTP/1.1
content-type: application/json
komoju-signature: xxxxxxxxxx

{
  "type": "payment.refund",
  "payment_id": "86rzkcrvcf82s0audo5himdi3",
  "mode": "test",
  "amount": 100
}

指定された決済の返金が不可能な場合、200台以外のHTTPステータスコードまたは{ "success": false }を含むJSONオブジェクトを返却してください。

HTTP/1.1 200
Content-Type: application/json

{
  "success": true
}

機能3: Nexusへのキャプチャコールバックの送信

クライアントはバックエンドとの間で直接決済をキャプチャします。決済がどのようにキャプチャされるかはNexusは関知しません。決済がキャプチャされたら、プロバイダーはキャプチャコールバックをNexusに送る必要があります。キャプチャコールバックは、決済の予約リクエストで受信したものと一致するpayment_idパラメータを含んでいなければなりません。

POST https://komoju.com/callbacks/providers/provider-name HTTP/1.1
Content-Type: application/json
Nexus-Provider-Signature: xxxxxxxx

{
  "type": "payment.captured",
  "payment_id": "xxxxxxxx" // payment.id provided by Reserve Payment API
}

Error Handling

Most exceptional cases such as the user having insufficient balance are probably already handled by your client. This section will cover what to do in cases where communication between your backend and Nexus is in conflict.

Authorization errors

Under normal operating conditions, the authorization request should never fail. If something exceptional happens, returning a response in this format will greatly assist in debugging.

HTTP/1.1 400
Content-Type: application/json

{
  "success": false,
  "error": { "message": "<your error message here>" }
}

Refund errors

Refunds have many reasons to potentially fail. Even so, we currently have no special behavior for different types of refund failures. Just like for authorization, a response in the following format is preferred in case an investigation is required.

HTTP/1.1 400
Content-Type: application/json

{
  "success": false,
  "error": { "message": "<reason for why the refund failed>" }
}

Callback errors

If Nexus returns a non-200 response code when trying to perform a capture callback, we expect your backend to try again periodically. The exact period is up to you. We are notified of callback errors and will usually resolve them quickly. If there is a payment whose capture callback fails for an excessive amount of time (24+ hours), please contact us and we will work to resolve it.

インテグレーション例

Nexusのインテグレーションの例 (バックエンド + JavaScriptによるモバイルアプリ) を公開しています。 以下のリンクからご参照ください。

github.com/komoju/nexus-example

クライアントはReact Native、バックエンドはExpressJSを使用して構築されています。非常に簡単にビルドして動作させることができます。もし、何かトラブルに遭遇したら、是非Issueをオープンしてください。

認証

NexusはほとんどのAPI通信に双方向の公開鍵暗号方式を用います。

  • 公開鍵暗号方式: 公開鍵・秘密鍵による署名と検証。RSAとECDSAをサポートしています。
  • 双方向: Nexusとプロバイダーの両者がそれぞれ鍵ペアを所持します。

要約すると、リクエストを送出する際は署名し、受信する際は署名を検証します。 登録の際にプロバイダーはプロバイダーの公開鍵を提出します。対応する秘密鍵は誰とも共有してはいけません。秘密鍵はバックエンドにのみ保存され、クライアント内に含んではいけません。クライアントからNexusへのリクエストは署名される必要はありません。

Nexusの公開鍵はこちらからダウンロードできます。

署名

バックエンドがNexusにリクエストを送る際は、リクエストに署名します。

プロバイダーの秘密鍵を使用してリクエストのボディ全体をSHA-256署名してください。

  1. 署名をBase64エンコードする。
  2. エンコードされた署名をNexus-Provider-Signature リクエストヘッダに付与する。

JavaScriptによるリクエスト署名の例


const fs = require("fs");
const crypto = require("crypto");

function createSignature(body) {
  const privateKey = fs.readFileSync('./private-key.pem', { encoding: "utf-8" });
  const sign = crypto.createSign("sha256");
  sign.update(body);
  sign.end();
  const signature = sign.sign(privateKey);

  let base64EncodedSignature = Buffer.from(signature).toString("base64");

  // must be added to the request as the Nexus-Provider-Signature header
  return base64EncodedSignature;
};

Rubyによるリクエスト署名の例


require 'openssl'
require 'json'
require 'base64'

def create_signature(body)
  key_string = File.read('private.pem')
  key = OpenSSL::PKey::EC.new(key_string)
  digest = OpenSSL::Digest::SHA256.new

  signature = key.sign(digest, body.to_json)

  # must be added to the request as the Nexus-Provider-Signature header
  Base64.encode64(signature)
end

署名の検証

Nexusがバックエンドにリクエストを送るとき、リクエストには特別な署名が含まれており、これを検証することでリクエストが間違いなくNexusから送信されていることを確認することができます。さらに、いくつかのNexusからのレスポンスにも署名が含まれており、検証に利用することができます。

  1. Nexusからリクエストまたはレスポンスを受信する。
  2. nexus-signatureヘッダを取得する。
  3. ヘッダの値をBase64デコードする。
  4. デコードされた署名を、Nexusの公開鍵とボディを使用して生成した値と比較する。

JavaScriptによる署名の検証

const fs = require("fs");
const crypto = require("crypto");

function verify(body, headers) {
  let base64Signature = headers["nexus-signature"];
  let publicKey = fs.readFileSync("./nexus-pub.pem", { encoding: "utf-8" });

  let verifier = crypto.createVerify("sha256");
  verifier.update(body);

  let signature = Buffer.from(base64Signature, "base64");

  return verifier.verify(publicKey, signature);
}

Rubyによる署名の検証

require 'openssl'
require 'base64'

def verify(body, headers)
  pem_string = File.read('./nexus-pub.pem')
  komoju_key = OpenSSL::PKey::EC.new(pem_string)

  return if komoju_key.nil?

  b64_signature = headers['HTTP_NEXUS_SIGNATURE']

  return 'Nexus-Signature header not found' if b64_signature.nil?

  signature = Base64.decode64(b64_signature)
  unless komoju_key.verify('sha256', signature, body)
    return 'Invalid Nexus-Signature header (verification failed)'
  end
rescue OpenSSL::PKey::PKeyError
  'Invalid Nexus-Signature header (verification failed)'
end