Help us understand the problem. What is going on with this article?

PayPalのエクスプレスチェックアウトをRestAPIで再現する

More than 3 years have passed since last update.

はじめに

公式サイトでは一見ClassicAPIの使用を勧めているように見えますが、DeveloperサイトからGithub行ってREADMEを見ると「ClassicAPIはもう使わなくなるからRestAPI使ってね」と書いてあります。

・・・すでに回りくどい書き方をしているので察しがつく方もいると思いますが、
公式が非常にわかりにくい
Webで調べてたら同じ意見が日英問わず出ているので、これはもう仕様です。動作確認するために公式のあちこちを参照しました。まとめといてくれよ・・・。誰かの参考になるかもしれないので技術メモを残します。

アプリケーションを登録する

PayPalのRestAPIはOauth2.0を採用しています。Twitterでアプリを作ったことがある人はピンとくると思いますが、PayPalでもアプリの登録が必要です。以下のサイトから登録できます。
https://developer.paypal.com/developer/applications
「あ?なんも出てこねーぞ?」って方、右上からログインしてください。
「あ?つくれねーぞ?」って方、sandboxで売り手アカウント作って下さい。

アプリを作ったら、Client IDSecretを入手できるのでどこかにメモしておいてください。

Java側の実装

まずはMavenでライブラリを取得。最新は1.4.1

<dependency>
  <groupId>com.paypal.sdk</groupId>
  <artifactId>rest-api-sdk</artifactId>
  <version>1.4.1</version>
</dependency>

実装の基本的な流れは公式のこちらのリンクを見ればわかります。
※ここにたどり着くのに1日かかった。

https://devtools-paypal.com/guide/pay_paypal
ちなみに補足なしではちゃんと動作しません。なので補足します。

Paymentを作って、客にPayPalで認証させる

仮に、あなたのサービスでお客さんがformが送信したとします。そして以下のコードでそれをキャッチしたとします。

Map<String,String> paypalConfig = new HashMap<String,String>();
paypalConfig.put("mode", env.getRequiredProperty("mode"));

String CLIENT_ID = "your.client.id";
String CLIENT_SECRET = "your.client.secret";
String CANCEL_URL = "your.cancel.url";
String RETURN_URL = "your.return.url";

String accessToken = new OAuthTokenCredential(CLIENT_ID, CLIENT_SECRET, paypalConfig).getAccessToken();
APIContext apiContext = new APIContext(accessToken);
apiContext.setConfigurationMap(paypalConfig);

Amount amount = new Amount();
amount.setCurrency("JPY");
amount.setTotal("400");

Transaction transaction = new Transaction();
transaction.setDescription("400 yen mo-rai!");
transaction.setAmount(amount);

List<Transaction> transactions = new ArrayList<Transaction>();
transactions.add(transaction);

Payer payer = new Payer();
payer.setPaymentMethod("paypal");

Payment payment = new Payment();
payment.setIntent("sale");
payment.setPayer(payer);
payment.setTransactions(transactions);
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setCancelUrl(CANCEL_URL);
redirectUrls.setReturnUrl(RETURN_URL);
payment.setRedirectUrls(redirectUrls);

Payment createdPayment = payment.create(apiContext);
for (Links links : createdPayment.getLinks()) {
  if (links.getRel().equals("approval_url")) {
    return "redirect:"+links.getHref();
  }
}

最後のreturn "redicrect:"+links.getHref();は私がspring bootでシミュレートしたからこうなっているだけで、ここは開発環境にあわせて変更してください。リダイレクトできれば何でもいいです。

このコードが実行されると、客は店のサイトからPayPalに移動します。そして、400円を店にあげるかどうかを聞かれるわけです。
※あくまでデモ

支払いの部分はPayPalがやってくれます。キャンセルにせよ、支払うにせよ、処理が終われば客はまた店のサイトに戻ってきます。
※実際に動かして、sandboxアカウントで支払ってみてください。

Paymentを確定する

ここでは客が支払ったとします。
PayPalからはGETでpaymentIdtokenPayerIDRETURN_URLに返してきます。そのあとの処理は

String accessToken = "さっきと一緒のやり方で取得";
APIContext apiContext = new APIContext(accessToken);
apiContext.setConfigurationMap(paypalConfig);

Payment payment = new Payment();
payment.setId(paymentId);
PaymentExecution paymentExecute = new PaymentExecution();
paymentExecute.setPayerId(payerID);
Payment executedPayment = payment.execute(apiContext, paymentExecute);

executeすると支払いが実行されます。
ちなみに、上記のコードはとりあえず動作を確認するためだけのものなので、実際に運用するとなると修正は必要です。

最後に

使い勝手で言ったら完全にWebPayの方がいいです。PayPalのドキュメントは本当に見づらい。ClassicAPIですら使い方がとっちらかってます。これは完全に妄想ですが、PayPalのドキュメントを見てると「プログラムを次々と書いてたらワケワカメになっちゃった。今どこで何が動いてるのかワカランチン。てへぺろ」という状況になっていないか心配です。公式ドキュメント(英語)ですら新旧の情報が入り混じっていて、しかもまとまっていないし、developerサイトとsandboxサイトで情報が共有されていないし・・・。これがプログラムでも起こっていたら、そのうち肝心のペイメントのところで大ポカやらかすんじゃないかと不安になりました。今考えているサービスでは店と客で双方向に送金できる方がありがたいのでPayPalを見てましたが、WebPay採用して店から客への送金部分は人力でやろうかなあ。

keigohtr
機械学習+自然言語処理/画像処理の研究者しつつ、ICT系WebAPIのマーケットプレイスApitoreを運営しつつ
https://apitore.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした