まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:api

【シリーズリンク】
#内容
1PayPay for Developers へサインアップ
2PayPay API について
3サンプルアプリケーション
4加盟店登録 ←今回


前回の続きです。今回は加盟店登録の手順を紹介します。

以前に紹介した PayPay for Developers にアカウント登録をすることで PayPay API を使ったアプリケーション開発の準備はできていて、実際の決済ではなく仮のお金を使ったテスト環境での決済による動作確認を行うことはできるようになっています(実際にアプリケーションを公開したり運用したりはできないけど、運用する PayPay 決済対応アプリケーションを開発して、公開せずに手元で動かすまではできる、という意味です)。

ただこれだけだとあくまで「(開発したアプリで)試しに使ってみる」段階であって、アプリが完成しても実際のお金を使った本環境での決済に移行することはできません。実際のお金を使った決済ができるようにするには PayPay for Developers のアカウントを作ることに加えて PayPay に加盟店登録をする必要があります。実際の決済をするつもりがなければ本ブログエントリは無視していただいてもいいのですが、私自身が試しに手続きを行った記録を公開する目的で紹介させていただきます。


【加盟店登録の法人登録と個人事業者登録の違い】
では PayPay 加盟店登録する手順を紹介します。PayPay for Developers アカウントを取得済みであることが前提となりますので、まだ取得されていない場合は以前の内容を参照いただいて取得しておいてください。

加盟店登録をする上で最初に決めておく必要のある項目があります。それは「法人登録」にするか、「個人事業者登録」にするか、ということです。どちらか1つを選んで登録することになります。

私のように経営主体となる法人を持っておらず、あくまで個人開発者としてサービスを運用することを想定するのであれば事実上選択肢はなく、個人事業者登録一択になります。個人事業者登録のメリットはなんといっても手続きが簡素であることです。提出書類も本人確認書類程度だし、公開するアプリケーションに必要な情報(ページ)が用意されていれば審査もさほど面倒ではありません※。

※法人登録したことないので、あくまで主観です。

一方、事業法人としてのサービス運用を行う場合は法人登録する選択肢もあります。こちらは手続きは比較的面倒ではあるのですが、個人事業者登録では使うことのできない機能(例えばサブスクリプション決済機能)もフルに活用することができ、より柔軟な機能実装や運用が可能になります。

以下では個人事業者として加盟店登録する手順を紹介します。ただこの手続きを最後まで行うには該当のウェブアプリケーションが既に公開されていて、その URL やサーバー IP アドレスを入力できる状態になっている必要があります。そこまで準備ができている状態で先に進めるようになる点にご注意ください。


なお、この手続きに関する PayPay の公式ドキュメントはこちらになります:
https://integration.paypay.ne.jp/hc/ja/article_attachments/4632569873039


【PayPay に個人事業者として加盟店登録する手順】
PayPay に個人事業者として加盟店登録する手順は2段階に分かれた入力作業を終える必要があります。まず第一段階の手順を紹介します。

PayPay for Developers にログインし、ダッシュボード画面から「アカウントの作成」と書かれた部分をクリックします:
2025060801


「加盟店登録をしましょう」というダイアログが表示されるので「今すぐ申し込む」をクリックします:
2025060802


すると申し込みフォームが表示されます。自分でアプリを作って運用する場合は「ユーザへのサービス提供の主体となる事業者」を選択します:
2025060803


すると質問項目が増えます。まずサービスの販売形態は「Web サービス/アプリ」にチェック、ご利用のサービスは「ウェブペイメント/動的ユーザースキャン/アプリコール」をチェック(サブスクである「継続課金」を使ってみたいところではありましたが・・・ 個人事業主は上のみ選択可能です)、最後に「お申込みフォームへ」をクリックします:
2025060804


すると画面が「PayPay オンライン加盟店のお申込み」ページに遷移します。自分の名前と連絡先電話番号、事業形態(個人事業主)を入力して、最後に「確認する」をクリックします:
2025060805


以下のような確認画面が表示されるので「申し込み開始」ボタンをクリックします。これで第一段階が完了です:
2025060806


この後、以下のようなページに遷移し、本登録である第2段階のフォーム入力となります。画面上部の「残り未完了項目」(必須項目で未入力のもの)がゼロにならないと先へ進めません:
2025060808


以下、要注意な部分のみ紹介します。まず個人事業主としての代表電話番号や住所の入力が必要です。ここには自分の電話番号や住所を記載します:
2025060809


次に開発して公開することになるウェブサービスの内容を記載する項目があります。名称や年商(予定)を記載します:
2025060810


販売形態は(ウェブサービスであれば)「web/アプリ」を選択し、サービス内容の詳細を記載・選択します。 なおこの中で「お取り扱い商品詳細」を指定するのですが、ここで指定する項目によって決済システム利用料(=PayPay 側に支払う手数料)が決まります:
2025060811


またここで実際に公開するウェブサービスの URL 等の情報が必要です。この中には特定商取引法に基づく表記の URL や(個人事業主としての)コーポレートサイトの URL も必須入力項目として必要な点に注意してください:
2025060812


更に決済サーバー(アプリケーションが稼働するサーバー)のグローバル IP アドレスも必要です:
2025060813


実決済を伴うサービスの申請となるため、緊急連絡先の登録が必要です。PayPay 決済サービス側の障害情報などもここで登録したメールアドレスに送付されます:
2025060814


規約等の内容を確認し、問題なければチェックを入れます。入力が完了したら「保存して次へ」をクリック:
2025060815


次に振り込み関する情報入力ページに遷移します。最初に入金サイクルを指定します:
2025060816


次に売り上げを入金してほしい金融機関を指定します:
2025060817


特定の商品を扱う場合はその資格書類が必要になるので、内容について該当項目があればチェックします。入力が完了したら「保存して次へ」をクリック:
2025060818


最後は本人確認書類の登録画面です。最初は入力内容の確認と、必要であれば(本人確認書類の登録前に)修正します:
2025060819


本人確認書類の登録に移ります。自動車運転免許など、登録する書類を選択し、指示に従って画像ファイルをアップロードします:
2025060820


必要な全ての画像ファイルをアップロードしたら「次へ」をクリックします:
2025060821


最後に内容確認画面が表示されます:
2025060822


内容に修正が必要なければ「内容を確認して申込む」ボタンをクリックします。これで登録作業そのものは完了です:
2025060823

私の場合は入力の数時間後に電話がかかってきて、いくつかの内容について電話確認が行われました。まあ電話番号の確認も兼ねたものだと思います。電話対応の後、数日後に以下のようなメールが送られてきました:
2025060824


メール本文にも書かれていたように、実際に利用開始できるようになるまでここから更に数日必要なようでしたが、手続きとしては無事に完了することができました。


【まとめ】
以上、4回に渡って PayPay API を使ったオンライン決済対応アプリケーションの作り方や、その前提となる PayPay for Developers アカウントの取得方法を紹介してきました。

アプリケーション開発に関しては、以下の点に注意する必要があると感じました:
・単に PayPay で決済するだけなら実装はシンプルでさほど難しくない
・一方で(テスト用のお金ではなく)実際のお金で決済するアプリを公開する前提で考えると、返金処理などにも対応した設計が必要になり、そのためには決済トランザクションをデータベースなどに記録して、後からどのトランザクションに対する返金なのかを照会できる仕組みも併せて必要

また今回は個人事業主アカウントしか作れなかったので、用意したサンプルもそこまで複雑な API を実装していないのですが、いずれは(現在、法人契約でないと使えない)サブスクリプション API も使えるようになったらいいなあ、、と思っています。






【シリーズリンク】
#内容
1PayPay for Developers へサインアップ
2PayPay API について
3サンプルアプリケーション ←今回
4加盟店登録


前回の続きです。今回は前回紹介した PayPay API(SDK) を使って決済・確認・返金に対応可能なアプリケーションのサンプルを作りましたので、その使い方を紹介します。 またこのサンプルアプリケーションには実際の決済を行うための加盟店登録(次回紹介予定)時の審査に必要な使い方ページや、特定商取引法に基づく表記のページも含めています。そのため、売りたいものやサービスが既にある場合は商品を自分のものに入れ替え、使い方ページや特定商取引法に基づく表記のページを自分のものに書き換えることで審査に使うこともできると思っています。


【サンプルアプリケーションを動かすための準備】
PayPay 決済のサンプルアプリケーションを手元で動かす上で大きく3つ、前提条件となる準備作業が必要です。

(1)Node.js
以下で紹介するサンプルアプリケーションは Node.js を使って実装されています(もう少し詳しく言うと Node.js + Express + EJS を使って実装したサーバーサイドアプリケーションで、jQuery や Bootstrap を使って UI を作っています。まあ昔ながらのシンプルな構成になっていると思ってください)。

このサンプルアプリケーションを手元の PC で動かすには Node.js がインストールされている必要があります(他のライブラリなどはサンプルアプリケーション側に用意されています)。既にインストール済みであれば先に進んでください。インストールできていない場合は公式サイトを参照し、自分の環境向けの Node.js をインストールしておいてください。

(2)PostgreSQL
前回のブログエントリでも紹介しましたが、サンプルアプリケーションは(返金などに対応するため)決済トランザクションをデータベースに記録します。そのデータベースが必要なんですが、本サンプルアプリケーションでは PostgreSQL を使う想定で記述されています。個人的にはデータベースは Docker 環境で用意するのがいいと思っていますが、なんらかの方法で PostgreSQL にアクセスできるような環境を用意しておいてください。

ちなみに Docker がインストール済みであれば以下のコマンドで PostgreSQL データベース(データベース名は mydb 、コンテナ名は mypostgres)を動かすことができます:
$ docker run -d --name mypostgres -p 5432:5432 -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=password -e POSTGRES_DB=mydb postgres

また以下のコマンドを追加で実行して、 mydb にトランザクション記録用テーブルである transactions を定義します:
$ docker container exec -it mypostgres psql -h localhost -U admin -d mydb

mydb=# create table if not exists transactions ( id varchar(100) not null primary key, order_id varchar(50) not null, amount int default 0, currency varchar(10) default '', created bigint default 0 );

mydb=# \q

このような PostgreSQL データベースと transactions テーブルが用意されている前提で以下を説明します。


(3)PayPay アプリ
またこのサンプルアプリケーションを使って(テスト環境で)商品を購入したり、購入した商品の返金対応をしたりするのですが、そのためにはスマホにインストールされた PayPay アプリが必要です。普段自分が使っている PayPay アプリでもできないことはないのですが、(環境切替が面倒だと思うので)できればアプリケーション試験用に普段使っているものとは別のスマホに PayPay アプリをインストールしておくのがいいと思います。



【サンプルアプリケーションを動かしてみる】
サンプルアプリケーションのソースコードはこちらから取得できます(zip でダウンロード&展開、または git clone):
https://github.com/dotnsf/paypayapi-sample

ソースコード展開後、とりあえず初回だけ必要なライブラリのインストール作業を済ませておきます:
$ cd paypayapi-sample

$ npm install

(正しく実行できると node_modules というフォルダが作られます)

次に動作設定ファイル .env を編集します。適当なエディタ(メモ帳でも可)で .env というファイルを開いて、以下の内容を入力して保存します:
DATABASE_URL=postgres://admin:password@localhost:5432/mydb
PGSSLMODE=disable
ADMIN_ID=user
ADMIN_PW=pass
PAYPAY_API_KEY=(PAYPAY API キーの値)
PAYPAY_API_SECRET=(PAYPAY API シークレットの値)
PAYPAY_MERCHANT_ID=(PAYPAY 加盟店 ID の値)
PAYPAY_REDIRECT_URL=http://localhost:8080/paypay/redirect

DATABASE_URL は前提準備で作った PostgreSQL データベースへの URL 、ADMIN_USER と ADMIN_PASS は管理者用画面にアクセスする際の ID とパスワード(この例だと ID が user で、パスワードは pass)を指定します。

そして PAYPAY_API_KEY と PAYPAY_API_SECRET は初回 PayPay for Developers に申し込んで取得した API キーとシークレットの値、PAYPAY_MERCHANT_ID は加盟店 ID です。それぞれ自分の環境で調べた値を指定してください(自分で取得した値を入れないと意味なくなります):
2025052910


最後に(これは編集せずにそのままでも動きますが)このサンプルアプリケーションで扱う商品の一覧ファイル items.json を必要に応じて編集します:
[
  {
    "name": "商品A",
    "imageurl": "/item-a.png",
    "amount": 500,
    "currency": "JPY"
  },
  {
    "name": "商品B",
    "imageurl": "/item-b.png",
    "amount": 1000,
    "currency": "JPY"
  },
  {
    "name": "商品C",
    "imageurl": "/item-c.png",
    "amount": 1200,
    "currency": "JPY"
  }
]

デフォルトの items.json では JSON 配列フォーマットで3つの商品が記載されています。各商品ごとに商品名、商品画像 URL 、価格とその通貨単位("JPY" は「日本円」です)が指定されているので、必要に応じて内容を書き換えたり、商品を追加削除してください。

ちなみに商品画像はリモートにある画像を使う場合はその URL を、手元にある画像の場合は public/ フォルダ以下にコピーしておくとサンプルのような記述が使えます。

ここまで完了していると実際にサンプルアプリケーションを動かすことができます。動かすには以下のコマンドを実行します(ちなみに実行終了は Ctrl+C です):
$ node app


実行中のサンプルアプリケーションにアクセスするには、同じ PC でブラウザを開き、http://localhost:8080/ にアクセスします。

下のような、3つ(items.json を変更した場合は変更内容によって変わります)の商品が縦に並んでいる画面になれば起動成功です。items.json で指定した商品が商品名、画像、価格が反映されて "Buy" というボタンを一緒に表示されています:
2025061301


実際に商品を購入する前に、概説ページと特定商取引法に基づく表記ページを確認します(管理者画面は後述します)。それぞれ画面上部のリンクから遷移できます:

(概説ページ)
2025061302

(特定商取引法に基づく表記ページ)
2025061303


どちらもここでは実質的に意味のないサンプルですが、実際の決済を行う際に必要な加盟店登録(次のブログで紹介予定)時には必要なページ(のサンプル)です。加盟店登録を行う際は同様のページを自分のショップ向けにカスタマイズして用意する必要があることを意識して内容を理解してください。


【テストアカウントで PayPay アプリにログイン】
改めて商品ページに戻り、今度はどれか1つを実際に購入してみましょう。そのために購入時に備えてスマホの PayPay アプリにログインしておきます。 ただ通常の(自分が普段使っている)PayPay アカウントでログインするのではなく、PayPay for Developers でテスト用に提供されているアカウントで(仮想のお金で)ログインします。 そのための手順を紹介しますが、可能であれば普段自分が使っているスマホではなく、(持っていればですが)別のスマホで以下の手順を実行することをお勧めします。

まず PayPay for Developers にログインし、ダッシュボードのテストユーザータブを開きます。すると3つのテストアカウントがあるので、どれか一つのユーザーネームとパスワード(下図では見えていませんが、目のアイコンをクリックすると表示されます)を確認しておきます(残金が少ない場合はこの画面からチャージもできます):
2025052909



このテストユーザーを使って PayPay アプリに Developer アカウントでログインします。Developer アプリにログインするにはアプリケーションを開いて(ログイン中の場合はログアウトして)、ログイン/新規登録画面内 PayPay ロゴの上部を7回連続でタップします:
2025061305


(途中からカウントダウンが表示されます)
2025061306


7回タップすると以下のような画面になります。「PayPay for Developers のアカウントでログイン」をクリックします:
2025061307


すると(テストモードでの)ログイン画面に切り替わります。ここで先ほど確認したテストユーザーの ID(電話番号)を入力します:
2025061308


パスワードも該当する電話番号のパスワードを入力してログインします:
2025061309


ログイン後の画面はスクリーンショットが撮影できないため文章のみでの説明になります。Developer モードでのログインができたことを確認してください。


【テストアカウントの PayPay アプリで決済】
ではテストアカウントの PayPay アプリで、サンプルアプリケーションの商品を購入してみましょう。

改めて購入する商品(下図の例では「商品A」)のアクション列にある "Buy" ボタンをクリックします:
2025061301


確認メッセージが表示されるので、間違いでなければ "OK" ボタンをクリック
2025061301


すると PayPay の QR コード画面に転送されます(ここでは前回紹介した内容の「ユースケース1 ウェブ決済」機能を使っています)。この QR コードを PayPay アプリで「スキャンして支払い」します:
2025061302


アプリ側で支払いするとサンプルアプリの画面も支払い完了時の画面に切り替わり、、、
2025061303


しばらくすると元の画面に再転送されます。これで決済できています。
2025061304


始めてやってみると不思議に感じるかもしれませんが、これで支払いは(今回の場合はテストユーザー用の仮想のお金で)完了しています。 他の商品も含めて何度か決済してみてください。


【管理画面と返金対応】
ユーザーの決済までの手順は(普段使っている PayPay アプリでの決済手順と比べてもほぼ同じだと思うので)分かりやすかったのではないかと思いました。これで支払いが完了して、(このサンプルアプリの場合は)そのトランザクションが記録されています。

最後に管理者としての管理画面にもアクセスしてみます。トップ画面右上の「管理画面」リンクをクリックします(または http://localhost:8080/admin にアクセスします):
2025061305


管理者画面へアクセスするためのユーザー名とパスワードの入力を求められるので、自分で .env に設定した内容(ADMIN_USER と ADMIN_PASS の内容)を入力してログインします:
2025061306


管理画面へのログインに成功すると以下のような画面になり、過去のトランザクション(取引)一覧(下図では1件だけ)が表示されます。トランザクションの詳細を表示するには該当レコードの "info" ボタンをクリックします:
2025061401


すると以下のようなダイアログが表示され、トランザクションの現在の状態が表示されます(日付や決済額などの情報が確認できます)。トランザクションのステータスはダイアログの最上部に表示されます(下図では "COMPLETED" になっていて、決済が完了していることを意味しています)。なお、ここでは前回紹介した内容の「ユースケース2 ウェブ決済状況確認」機能を使っています:
2025061402



最後に返金対応をシミュレートしてみましょう。もしこのトランザクションを実行したユーザー(お客様)から、「クーリングオフを理由に返金してほしい」という要望があった場合に(法律的にはクーリングオフは消費者の権利なので条件を満たしている限り対応しないわけにはいかないのですが)具体的に返金するにはどうすればよいか、というシミュレーションです。

返金対応をする上で重要なのは「どの取引に対して返金処理をすればよいのか?」を明確にするということです。トランザクションの履歴は管理画面に残っていることが確認できるのですが、この一覧の中のどのトランザクションに対して返金対応すればよいか、を正確に知る必要があるのです。

そのためにはまず利用者(お客様)から取引番号を伝えてもらう必要があります。以下の手順を利用者に伝えた上で、「返金を希望する PayPay 決済の取引番号を調べて送ってほしい」と伝えます。

利用者からみた取引番号の調べ方は以下の通りです。なお、PayPay アプリのスクショは撮れないようになっているので、以下は PayPay アプリの操作の様子を別のスマホで撮影した写真を添付します。またこの PayPay アプリは PayPay for Developers のテスト用アカウントでログインしているので、その旨のメッセージが画面上部に表示されています。


まず利用者に PayPay アプリにログインした状態で開いてもらいます:
2025061403


ここから「取引履歴」と書かれた部分をタップして、過去の取引履歴を表示してもらいます:
2025061404


直近の取引の履歴が表示されます。ここから返金を希望する取引を選んでタップしてもらい、
2025061405


返金対象の取引の画面が表示されます。ここで更に「詳細を見る」と書かれた箇所をタップしてもらうと、
2025061406


詳細情報が展開されます。その中に「取引番号」と書かれた箇所があります。返金対応にはこの情報が必要なので、取引番号の内容を伝えてもらってください:
2025061407


返金対象の取引番号が分かったら、改めてサンプルアプリの管理画面を開き、トランザクション一覧で order id がその取引番号になっているトランザクションを見つけます(下図の例だとトランザクションが1件しかないので簡単に見つかりますが、数多くあった場合はソートなどして見つけてください)。これで返金対象トランザクションが分かりました:
2025061408


返金対象トランザクションが分かったら、このトランザクションの返金対応を実施します。なお返金対応はアンドゥができない点に注意してください。また、ここでは前回紹介した内容の「ユースケース3 返金対応」機能を使って実装しています。

対象トランザクションの右側にある "Refund" ボタンをクリックします:
2025061408


最初の確認画面が表示されます。対象トランザクションが一致しているか確認して OK をクリック:
2025061409


返金処理には必ず理由を入力する必要があります。返金理由を記載して OK をクリック:
2025061410


返金処理前の最後の確認画面が表示されます。内容を確認し、この内容での返金を実行する場合は OK をクリックします:
2025061411


実行結果が表示されます。画面内に返金理由や paymentId(order id)、返金額などの情報が表示されています:
2025061412


再度、管理画面が表示されます。ここで返金したトランザクションのステータスを再確認してみます。該当トランザクションの "info" ボタンをクリックします:
2025061413


すると(正しく返金が実行されていれば) "REFUNDED" というタイトルのダイアログが表示され、返金理由なども表示されます。無事に返金できていたようでした:
2025061314


ここまでできていれば、利用者の PayPay アプリ側にも返金されています。PayPay アプリの取引履歴を確認すると返金されていることが確認できるはずです:
2025061415


サンプルアプリケーションと PayPay アプリ(とテストユーザー)を使った購入と、購入内容の確認、そして返金対応の手順が確認できました。ここまで確認すると、返金対応するには過去の(取引番号含めた)取引履歴の情報が残っていないと難しいのでデータベースに記録する必要があった、というのもなんとなく理解いただけるのではないかと思います。


管理機能や返金処理まで実装し、更に加盟店登録時に必要な概要ページや特定商取引法に基づく表記ページまで含まれたサンプルアプリは我ながら珍しいと思うので、これを参考に(商品や見た目をカスタマイズすれば)返金機能まで対応した PayPay ショップサイトを比較的容易に作れるのではないかと思っています。よかったら是非カスタマイズして使ってください。


次回はこのシリーズの最終回の予定です。これまでは PayPay for Developers アカウントのテストユーザーを使ったアプリ動作確認を紹介してきましたが、次回は PayPay に加盟店登録を行い、本当に(テストユーザー以外でも)PayPay 決済が可能になるような手続きを紹介する予定です。













【シリーズリンク】
#内容
1PayPay for Developers へサインアップ
2PayPay API について ←今回
3サンプルアプリケーション
4加盟店登録


前回の続きです。今回はウェブアプリに PayPay 決済機能を実装するための API(SDK) と、この API をどう使って(次回紹介予定の)サンプルウェブアプリケーションを実装したか、を紹介します。

前回紹介した PayPay for Developers にアカウント登録をすることで PayPay API を使ったアプリケーション開発の準備ができました。この後、実際に動くサンプルアプリケーションも紹介予定ですが、そのサンプルアプリケーションの中で使っている PayPay 決済機能がどのような API を使ってどのように実装されているか、を紹介します。


【PayPay 公式 API】
まず PayPay が公開している公式 API であるインテグレーション SDK はこちらです:
https://developer.paypay.ne.jp/products/docs

同ページ内で様々な SDK が紹介されていますが、特にウェブアプリケーションの中で決済を実施するためのウェブペイメント SDK についての公式資料はこちらです:
https://developer.paypay.ne.jp/products/docs/webpayment

このブログシリーズの次回でサンプルアプリケーションを紹介しますが、そのサンプルアプリケーションは Node.js を使って実装しています。この Node.js 用 SDK の公式資料はこちらです(本ブログエントリで紹介する内容はこのページで紹介されているものの抜粋です):
https://www.npmjs.com/package/@paypayopa/paypayopa-sdk-node/v/0.5.1


自作サービスで PayPay を有効にするには上記の API(SDK) を使って決済したり、決済状況を確認したり、といった機能をアプリケーション内で実装する必要があります。以下では利用場面別に3つのユースケースと、そのための API(SDK) 実装方法を紹介します。


【データベースの用意】
まず最初にデータベースを用意します。詳しくは後述しますが、PayPay は単に支払いに使うだけなら決済情報を記録する必要はないのですが、実際に運用する場合は決済情報を記録しておかないと(返金リクエストなどの)各種問い合わせに対応できなくなってしまいます。

以下の説明ではこのような定義の transactions テーブルが作成されていることを前提に説明しています。もちろん利用目的によってはユーザーの情報などを加えてもいいと思いますが、最低限このくらいの情報を記録しておく必要がある、と思ってください:
create table if not exists transactions ( id varchar(100) not null primary key, order_id varchar(50) not null, amount int default 0, currency varchar(10) default '', created bigint default 0 );

この transactions テーブル内の各列には以下のような情報を格納します:
列名格納する値
idID(merchantPaymentId)
order_idオーダー ID(利用者からは「取引番号」として見える値)
amount取引額
currency取引通貨
created作成日時のタイムスタンプ



【SDK の初期化】
次に以下で3つ紹介するユースケースの全てで共通しているのですが、Node.js 用 PayPay SDK を使う場合、各処理を実行する前に SDK を初期化しておく必要があり、この初期化の際には以下3つの値が必要です:
・API キー
・API シークレット
・加盟店 ID

これらは PayPay for Developers にログインした直後のダッシュボード画面に表示されているものを使います(他の人から教えてもらったり、教えたりするものではないので注意してください):
2025052910


これらをの値を使って、以下のコードを実行して初期化を実行しておきます:
var PAYPAY = require( "@paypayopa/paypayopa-sdk-node" );
var PAYPAY_API_KEY = '(API キー)';
var PAYPAY_API_SECRET = '(API シークレット)';
var PAYPAY_MERCHANT_ID = '(加盟店 ID)';

PAYPAY.Configure({
  clientId: PAYPAY_API_KEY,
  clientSecret: PAYPAY_API_SECRET,
  merchantId: PAYPAY_MERCHANT_ID,
  productionMode: false  //. テスト環境の場合は false 、本番の場合は true
});

以下3つのユースケース全てはここまで完了している前提で実行してください。


【ユースケース1 ウェブ決済】
ある意味最もシンプルな「PayPay アプリで支払いを行う」場面を想定した機能を作る部分です。支払いを行う利用者の立場で考えると「QR コードを読み取って支払う」という1ステップだけの機能だけのように感じられるかもしれませんが、ここでは以下のような3ステップを実行します:

(1)支払い内容に応じた QR コード(の URL )を作る
(2)(1)で作った URL にユーザーを転送させて QR コード決済してもらう
(3)決済内容を(返金対応ができるように)記録する

(1)ではサーバーサイドで以下のようなコードを実行します(◎◎シャンプーという 1000 円の商品を購入した例での内容です):
var { v4: uuidv4 } = require( 'uuid' );  //. UUID 作成用
  :
  :

    var payload = {
      merchantPaymentId: 'paypayapi-sample' + uuidv4(),  //. ユニークID
      amount: { amount: '1000', currency: 'JPY' },  //. 1000円
      codeType: "ORDER_QR",
      orderDescription: '◎◎シャンプー',
      isAuthorization: false,
      redirectUrl: 'http://localhost:8080/paypay/redirect',  //. リダイレクト先
      redirectType: "WEB_LINK",
      userAgent: 'PayPayAPI Sample App/0.0.1'
    };

    //. 決済用 QR コードページを生成
    PAYPAY.QRCodeCreate( payload, function( response ){
      if( response.STATUS == 201 ){
        //. 決済内容をセッションに記録
        req.session.qr_data = response.BODY.data;

        //. 生成された QR コードページにリダイレクト
        res.redirect( response.BODY.data.url );
      }


ここでは QR コードページを生成するために PAYPAY.QRCodeCreate という関数を実行するのですが、その関数に渡すパラメータオブジェクトである payload という変数を定義します。ここでは merchantPaymentId にユニークな ID を生成して入れておきます。また amount には決済額の情報を数値と通貨単位に分けて入力し、orderDescription に決済内容を示す文字列(商品名など)、そして redirectUrl に(3)での処理を想定した QR コード決済が完了した後に戻ってくるページ(リダイレクト先)を指定します。また codeType には "ORDER_QR" を、redirectType には "WEB_LINK" をそれぞれ指定します。

このようにして作成した payload を引数指定して PAYPAY.QRCodeCreate を実行します。そして生成が成功したこと(response.STATUS が 201 になっていること)を確認後に(決済後のリダイレクト先で再度この時の情報にアクセスできるように)決済内容をセッションに記録した上で生成された QR コードページに利用者をリダイレクトする、という処理を実行しています。

(2)利用者は(1)の最後のリダイレクト先の QR コードを PAYPAY アプリで読み取って決済します。決済が完了すると利用者は(1)の payload.redirectUrl で指定したリダイレクト先に転送されます。

(3)利用者の決済が完了した後に転送された後の処理です。この時点で決済は完了しているので、支払い自体は済んでいるとも言えます。ただここで決済の情報を記録しておかないと、誰がいつどんな決済を行ったのか、という情報は PayPay for Developers のダッシュボード画面を見ないとわからなくなってしまいますし、あるユーザーから(クーリングオフなどの理由で)返金を求められた場合、いつのどの決済に対する返金対応なのかもわからなくなってしまいます。その対応のためにも完了した決済内容はデータベースなどに記録しておくことが必要だと思っています((1)で決済直前に決済内容をセッションに記録していたのはそのためです)。

そのための実装は以下のようになります:
//. 決済完了後のリダイレクト先での処理
app.get( '/paypay/redirect', async function( req, res ){
  //. (1)で記憶させた内容をセッションから取り出し
  var qr_data = req.session.qr_data;

if( qr_data.merchantPaymentId ){ //. merchantPaymentId を使ってオーダー ID を取り出す var order_id = ''; var response = await PAYPAY.GetCodePaymentDetails( Array( qr_data.merchantPaymentId ) ); if( response.STATUS == 201 ){ var body = JSON.parse( response.BODY ); //. body.data.paymentId に格納されたオーダー ID を取り出す if( body && body.data && body.data.paymentId ){ order_id = body.data.paymentId; } } //. qr_data.merchantPaymentId, order_id, qr_data.amount.amount, qr_data.amount.currency をデータベースに記録する : :

まず(1)で指定したリダイレクト先 URL である '/paypay/redirect' での処理内容として以下を記述します。最初に(1)でセッションに記憶させた情報を取り出し、(1)実行時に生成したユニーク ID である merchantPaymentId を引数に PAYPAY.GetCodePaymentDetails 関数を実行して決済結果の状況を取り出します。

データベースに記録しておきたい情報は「利用者側からの決済情報 ID として確認できる オーダー ID 」の値で、利用者の PAYPAY 画面からは取引履歴内の「詳細を見る」という部分を展開した先の「取引番号」として表示されているものです:
2025060901


※もし利用者から返金対応を求められた場合は、利用者にこの画面を出してもらい、「取引番号を教えてください」と伝えて教えてもらうことで、サービス運用側からもどの時の決済に対する返金対応なのか、を特定することができるようになります。そのためにも(3)の処理の一部として、決済情報をデータベースに記録しておくことが必要です。


このオーダー ID の値は PAYPAY.GetCodePaymentDetails 実行後の body.data.paymentId に格納されているので、この値を取り出します。

最終的には
・実行時に生成したユニーク ID (merchantPaymentId)
・利用者側からの決済情報として確認できるオーダー ID(order_id)
・決済額と決済通貨単位(amount, currency)
・その他、日付情報など
を別途データベースに格納しておくことで、ユーザーからの決済に関する問い合わせにも対応ができるようになる、というものです。

ユースケース1においては単なる支払いだけなら(1)と(2)の処理だけ実装すればできますが、実際に運用することまで考慮すると(3)の処理も事実上必須、だと思っています。


【ユースケース2 ウェブ決済状況確認】
「PayPay アプリで支払い」の機能さえあればよいかというと、そうはいきません。そもそも支払いは完了したのかしていないのか、支払いを行った結果どうなったか、返金対応は完了しているのか、といった状況を確認できるようにしておく必要もあります。後述の返金対応をする上でも確実に支払われたと分かっている取引だけに対応する必要があるため、支払い結果を確認することができる機能も必要です。

この機能はユースケース1の(3)でも利用した PAYPAY.GetCodePaymentDetails 関数を使って実装します。状況を確認したい取引の merchantPaymentId を指定して、以下のように実行します:
PAYPAY.GetCodePaymentDetails( Array( merchantPaymentId ), function( response ){
  if( response.STATUS == 201 ){
    //. 取引情報の取得に成功
      :
      :


なお、取引情報のステータスを示す値は response.BODY.data.status に文字列として格納されています。取り得る値とそのステータスは以下のようになります(ウェブペイメントで目にする頻度が高いのは緑のステータスです):
ステータス
CREATED受付済み(QRコード作成済み)
AUTHORIZED残高ブロック済み
REAUTHORIZED増額キャプチャ時のユーザー承認後処理中
COMPLETED取引完了(支払い済み)
REFUNDED返金済み
FAILED取引失敗
CANCELED残高ブロック中止(キャンセル
EXPIRED残高ブロック期限切れ


この関数によって、merchantPaymentId が分かっていればその取引の決済状況を確認することができるようになります。


【ユースケース3 返金対応】
もう1点、上述でも何度か触れていますが、返金にも対応できるようにしておく必要があります。PayPay で決済可能なサービスを作っている以上、クーリングオフなど購入者側の事情による返金を考慮しないわけにはいきません。「返金には対応しない」わけにはいかない以上、返金要望にも対応できるようなアプリケーションにしておく必要がある、というものです。

利用者からの返金リクエストを受ける場合、まず利用者に対象取引の「取引番号」を調べてもらう必要があります。取引番号は PAYPAY アプリの取引履歴から返金対象の決済を選んだあとに「詳細を見る」を選択後に表示されます。まずはこの取引番号を利用者から教えてもらいます:
2025060901


取引番号(データベース上ではオーダー ID)がわかったら、その取引番号をオーダー ID として持つレコードを検索します(上述の transactions テーブルを使い、該当するオーダー ID を持つレコードの id(=merchantPaymentId), amount, currency を検索します。

返金対応したい決済の内容が分かったら、返金理由などと併せて PAYPAY.PaymentRefund 関数を実行して返金処理を実施します(以下のコードはデータベースに PostgreSQL を使う想定で記述されています):
var PG = require( 'pg' );
var database_url = 'posgtres://user:pass@server:5432/db';
var pg = new PG.pool( { connectionString: database_url } );
var conn = await pg.connect();

var order_id = '(返金対応したいレコードの order_id)';

//. order_id に対応する id や返金額をデータベースから取り出す
var sql = "select id, amount, currency from transactions where order_id = $1";
var query = { text: sql, values: [ order_id ] };

var result = await conn.query( query );
var id = result.rows[0].id;  //. 返金対応したいレコードの id
var amount = parseInt( result.rows[0].amount );
var currency = result.rows[0].currency;

//. 該当レコードの決済から返金する
var payload = {
  merchantRefundId: id + '-refund',
  paymentId: order_id,
  amount: { amount: amount, currency: currency },
  reason: 'クーリングオフ'  //. 返金理由
};
PAYPAY.PaymentRefund( payload, function( response ){
  if( resopnse.STATUS == 201 ){
    //. 返金成功
      :
      :


以上、今回は Node.js 用の PAYPAY API(SDK) を使って PayPay での決済や状況確認、返金処理といった実践的な処理を実装するための前提条件や方法をざっと紹介しました。

次回は今回紹介した内容を使って作成したサンプルアプリケーションをテスト環境で動かし、PayPay アプリでの決済や返金処理といった内容を実際に体験する予定です。



【シリーズリンク】
#内容
1PayPay for Developers へサインアップ ←今回
2PayPay API について
3サンプルアプリケーション
4加盟店登録


PayPay 、便利ですよね。具体的な数字根拠があるわけではないのですが、数ある QR コード決済システムの中でも頭一つ抜き出て利用されている印象を持っています。

自分は個人でウェブサービスを開発したり、その中のいくつかはクラウドなどを使って公開していたりするものもあります。そんな自分が長い間悩んでいたものの1つが「有償化」というものです。作ったサービスは基本的には無料で使ってもらうことを想定しているのですが、一部の特定機能については有償化できることならしたい、というものもあります(商用利用とか)。ただその上で大きな壁となるのが「どうやって料金を支払ってもらうか」でした。クレジットカード決済するような機能を個人で作れるわけではなく、PayPal のような仕組みもありましたが日本ではあまり広まっていなかったし、かといって銀行振込は手間がかかりすぎてせっかく興味を持ってくれた人の興味を失ってしまう要因にもなると思っていました。

そんな中、この PayPay は API(SDK) が提供されていて、自作ウェブアプリケーションに組み込むことができます。例えば自作アプリケーションの中で EC 機能を実装してその決済を PayPay で行うことができるようになったり、自作ウェブサービスの有料機能の支払いを PayPay で行わせることもできるようになります。日本国内での利用者も多く、この PayPay API を使うことで技術的にも比較的低い敷居でサービスの有償化を実現できるのではないかと考えています。


実は数年前に同じような内容を自分のブログ内で紹介する機会がありました。当時よりも API そのものが進化していたりすることもあるのですが、当時紹介した内容は「単なるウェブ決済」の話になってしまっていて、(例えば返金対応のことが考えられていなかったりして)非実践的な内容でした。 そんな反省も踏まえ、改めて 2025 年6月時点の情報として Node.js のサンプルも含めた PayPay API 対応ウェブアプリの実装方法を紹介したいと思います。

内容は数回に分けて紹介する予定です。初回である今回は PayPay API を使う上で必要な PayPay for Developers へのアカウント登録方法を紹介します。


【PayPay for Developers へアカウント登録する】
PayPay API を使うにはまず PayPay for Developers にアカウントを登録して、API キーなどの利用情報を取得する必要があります。そのアカウント登録手順を紹介します。 なおアカウントの作成自体は無料ですが、有効なメールアドレスが必要です。加えてテストモードでの動作確認を行うために自分が普段 PayPay アプリを使っているスマホとは異なる、別のスマホが1台あると(面倒なアカウントの切り替えが不要なので)便利です。

では PayPay for Developershttps://developer.paypay.ne.jp/account/signup ) にウェブブラウザでアクセスして、アカウントの ID となるメールアドレスと、アカウント利用時のパスワードを入力して「アカウントを作成する」ボタンをクリックします:
2025052901


すると以下のような画面に切り替わります。この時点で入力したメールアドレスに PayPay からワンタイムパスワードが記載されたメールが送信されています(この画面に戻ってくるので、この画面は消さずに以下の作業を実施してください):
2025052902


送信された対象のメールを探して、その本文内に記載されているワンタイムパスワードを確認します:
2025052903


元の画面に戻り、ワンタイムパスワードを入力して「確認する」ボタンをクリックします:
2025052904


実はアカウントの登録自体はこれだけです。そのまま次に決済時のサービス(利用者の PayPay 支払い時に表示される内容)のサービス名とサービスロゴを登録します。試験的に使うだけなら(どうせ使うのは自分だけなので)適当な名前とロゴ画像でいいと思います。実際に公開してお客様の決済に使う場合はちゃんとした(笑)名前とロゴを指定してください:
2025052905


次は決済方法の指定です。ここで紹介するのは「ウェブペイメント」だけなのですが、後で色んな機能を使いたくなる可能性もあるので、一応全部チェックして、最後に「登録する」ボタンをクリック:
2025052906


このような画面になってアカウントとショップの登録は完了です。「開始する」ボタンをクリックして PayPay for Developers にログインします:
2025052907


なお次回からはこちらの URL( https://developer.paypay.ne.jp/account/signin )でログイン画面を開き、メールアドレスと登録したパスワードを入力することでログインできます:
2025060401



【PayPay for Developers で API 利用情報やテストユーザーを確認する】
PayPay for Developers にログインすると以下のような画面になります。まずは左メニューでダッシュボードを開き、「API キー」タブを選択します。すると API キーAPI シークレット、そして画面上部に加盟店 ID が確認できると思います。PayPay API を利用するにはこれら3つの値が必要になるので、これらの値をメモするなどして、すぐに参照できるようにしておいてください:
2025052910


なお、アクセスするタイミングによってはまだこれらの情報が発行されていないか、画面に反映されていなかったりして、表示されないことがあります(下図参照)。 このような場合は一度ログアウトし、少し待ってから再ログイン後に確認してください:
2025052908


また「テストユーザー」タブを開くと、動作確認用のユーザー IDとパスワード、そして各ユーザー ID にチャージされた額(仮想のお金)が表示されます。チャージ額はこの画面から追加することもできます。またパスワードはこの画面では表示されていませんが、各パスワードの右側の「目に斜め線が引かれたアイコン」をクリックすると実際のパスワード文字列を確認することができます:
2025052909


このテストユーザーの ID とパスワードはサンプルアプリの動作を確認する時に(本当のお金の取引を伴うモードへ移行する前の、テスト環境での動作確認時に)使う予定です。


これで PayPay API を使う上での準備として必須だった PayPay for Developers へのアカウント登録は完了しました。一応触れておくと、この時点でできることは「PayPay API をテスト環境で使う」ことだけで、本当にお金の流れが発生するような実環境決済はできません。そのためには加盟店登録が必要になるのですが、その辺りはまた別の機会に紹介したいと考えています。

次回は今回用意した PayPay for Developers アカウントで PayPay 加盟店に登録する手順を紹介する予定です。










ツイッター(X)が API 制約を含めて色々と不便になってしばらく経過しました。ツイッターでリツイートボットとか作ってた個人のものはほぼ全滅状態ですが、さすがに「しばらく待てばまた使えるようになる、、」などと楽観的には考えない方が良さそうな感じですね。

世の中には使いにくくなったツイッターの後釜を狙う SNS も多く出てきましたが、今のところはまだツイッターを使っている人が圧倒的多数の印象です。まあ開発者的にはツイッターはもう見限ってる人も少なくないんでしょうけど、SNS はあくまで「発信の場」であって、使っているのは開発者ばかりじゃないですからね。メッセージを届ける先の規模含めると、使い勝手が現状維持ならまだしばらくツイッターが使われていくのでしょう。


一方で、とはいえ多くの SNS が新たに生まれてきてはいます。実は自分も「お絵描き SNS」という位置づけの MyDoodles なんていうものを密かにリリースしていたりもするのですが、、、そんな中でツイッターの共同創業者の一人だったジャック・ドーシーさんが新たに立ち上げた分散型 SNS である Bluesky Social (以下 "Bluesky")はツイッターに似たインターフェースを持ち、リリースからしばらくは招待制で運用されていましたが、先ごろ招待制が撤廃されて誰でもアカウントを作れるようになりました。比較的早い段階から API も公開されており、開発者視点では「次に来るのはこれかも」と期待しています。


そんな Bluesky の API を使って、ツイッターでは(個人では事実上)作れなくなってしまったボットを作ってみることにしました。自分が作ろうと思ったのは拙作マンホールマップが持つ機能の1つである「今日のマンホール」を午前零時に自動でつぶやくボットです。実はこれまでは私自身が人間ボットになって(笑)今日のマンホールを手動でつぶやいていたのですが、これを Bluesky 内で自動化する、というものです。ボットとしての基本的な考え方はツイッターの頃と大きく変わるものではないのですが、分散 SNS である Bluesky の、まだ充分に熟しているとは言えない API を使って実装することはチャレンジでもあり、色々面倒な考慮も必要にはなるのですが、とりあえず作れそうだったので、その中身の解説をするのが本ブログエントリの目的です。なお以下で紹介する内容は 2024-02-12 時点の情報であることをご了承ください。


【開発環境】
まず Bluesky API を紹介している本家ページがこちらです:
https://www.docs.bsky.app/docs/get-started

2024021201


SDK としては Node.js と Python 向けに提供されているようですが、Curl からも使える REST API があるようなので REST API でプログラミングするつもりであれば事実上プログラミング言語に制約はないことになります。今回以下で紹介するプログラミングの環境としては自分が普段使っている Node.js を使うことにします。

Node.js の場合、@atproto/api というライブラリを使うことで比較的簡単に Bluesky API を使ったアプリケーションの開発ができるようになります。こんな感じでインストールして使います:
$ npm install @atproto/api


【認証】
Bluesky API を使って試しに自分自身の情報でも取得・・・ するのもいいですが、まずは認証を行う必要があります。ツイッターなどでは開発者向けページからアプリケーションを登録して API キーを発行して OAuth 2.0 で・・・ といった手順で認証を行っていました。Bluesky もいずれはそのような形態になるものと思いますが、現時点では OAuth2.0 はサポートされておらず、ユーザー ID とパスワードを使って直接ログインする形になるようです。ちょうど Bluesky の招待制も終わったことなので、自分はこのボット用(というかマンホールマップ用)のアカウントを1つ新たに作成しました。そして Node.js の場合はこのような形で認証(ログイン)を行います:
var { BskyAgent } = require( '@atproto/api' );

var agent = new BskyAgent({
  service: "https://bsky.social"
});
agent.login({
  identifier: "myname@email.com",
  password: "mypassword",
}).then( async function(){
  // ログイン成功後の処理へ
    :
    :
});

"@atoproto/api" ライブラリから BskyAgent をインポートして、メールアドレス(上では "myname@email.com" の部分)とパスワード(同 "mypassword" 部分)を指定してログインします。このあたりはソースコード内に直接記載するのは危険なので、コードの管理方法には注意が必要です。


【ツイートする】
ボットを作るには「ツイートする」(書き込む)機能が必要です。ログイン後に単にテキストをツイートするだけなら簡単です。特に @atproto/api ライブラリを使っていれば post メソッドを使って以下のようにログイン後の処理を一行追加するだけです:
var { BskyAgent } = require( '@atproto/api' );

var agent = new BskyAgent({
  service: "https://bsky.social"
});
agent.login({
  identifier: "myname@email.com",
  password: "mypassword",
}).then( async function(){
  var res = await agent.post( { text: 'Hello, world.'} );
  console.log( {res} );
});

これでログインしたユーザーの権限で "Hello, world." とつぶやくことができます。簡単ですよね、ここまでは。


【facets 処理(リッチテキスト処理)】
テキストをつぶやくのは簡単でした。ツイッターなどではこのテキスト内に他のユーザーへのメンション(@)が含まれていたり、ハッシュタグ(#)やリンクが含まれていると自動的に解釈してリッチテキスト化してくれて(リンクとかを付けてくれて)いましたが、Bluesky API はそうはいきません(そもそも Bluesky にはまだハッシュタグという概念がありません)。この辺りはプログラミング内でリッチテキスト化(Bluesky では「facets 検知」といいます)する必要があります。今回作ろうとしているボットも必ずあるページへのリンクを含む内容になっているので post 実行前の facets 検知が必須です。この辺から少し面倒になってきます。

具体的にはこのようなコードになります:
var { BskyAgent, RichText } = require( '@atproto/api' );

var agent = new BskyAgent({
  service: "https://bsky.social"
});
agent.login({
  identifier: "myname@email.com",
  password: "mypassword",
}).then( async function(){
  var text = "リンクを含むテキスト https://manholemap.juge.me/";

  var rt = new RichText({ text: text });
  await rt.detectFacets( agent );

  var res = await agent.post({
    $type: 'app.bsky.feed.post',
    text: rt.text,
    facets: rt.facets
  });

  console.log( {res} );
});

まずリッチテキスト化処理を行うために @atproto/api ライブラリから BskyAgent だけでなく RichText もインポートしておきます。そしてリンクなどのリッチテキスト化が必要なテキストを RichText で初期化した結果を変数 rt で受け取り、更に detectFacets() 処理を実行します。するとテキスト部分は rt.text に、facets 情報が rt.facets にそれぞれ格納されます。ツイッターではこの辺りの処理が自動化されていたので楽でしたが、Bluesky でもここまでライブラリが用意されているのでさほど大変ではないですね。

最後に facets 処理した結果を post します。先のプレーンテキストでは text 要素だけを post していましたが、リッチテキストの場合は少し情報を加えてあげる必要がありますが、これでテキスト内の URL 部分はリンクになってポストされます。


【オープングラフ処理(OGP対応)】
ツイッターなど多くの SNS ではリンクを含む情報をポストすると、そのリンク先の内容の一部(テキストや画像)が埋め込まれる形で表示されます。これは OGP と呼ばれる規格で、リンク先が OCP 規格に沿って作られたページであれば、その情報を使って実現できるものです。

Bluesky の場合もリンク先の情報を埋め込むことはできるのですが、API でつぶやく場合は(現状では)この部分を全て手作業で行う必要があります。具体的にはこんな感じです:
var { BskyAgent, RichText } = require( '@atproto/api' );
var { parse } = require( 'node-html-parser' );

var agent = new BskyAgent({
  service: "https://bsky.social"
});
agent.login({
  identifier: "myname@email.com",
  password: "mypassword",
}).then( async function(){
  var text = "リンクを含むテキスト https://manholemap.juge.me/";

  //. OGP
  var url = "https://manholemap.juge.me/";
  var resp = await fetch( url );
  var html = parse( await( resp.text() ) );
  var title = html.querySelector( "meta[property='og:description']" ).getAttribute( "content" );

  //. embed image
  var ogpImg = html.querySelector( "meta[property='og:image']" ).getAttribute( "content" );
  var blob = await fetch( ogpImg );
  var buffer = await blob.arrayBuffer();
  var response = await agent.uploadBlob( new Uint8Array( buffer ), { encoding: "image/jpeg" } );
  var embed_params = {
    $type: "app.bsky.embed.external",
    external: {
      uri: "https://manholemap.juge.me/",
      thumb: {
        $type: "blob",
        ref: {
          $link: response.data.blob.ref.toString()
        },
        mimeType: response.data.blob.mimeType,
        size: response.data.blob.size
      },
      title: title,
      description: title
    }
  };

  var rt = new RichText({ text: text });
  await rt.detectFacets( agent );

  var res = await agent.post({
    $type: 'app.bsky.feed.post',
    text: rt.text,
    facets: rt.facets,
    embed: embed_params
  });

  console.log( {res} );
});

まず URL のリンク先情報を解析するために node-html-parser ライブラリをインポートしておきます。そしてリンク先の URL(上では "https://manholemap.juge.me/")を fetch して HTML を取得します。OGP の規格に沿って作られたページであれば、その画像は HTML 内で <meta property="og:image" content="***" /> の *** 部分に指定されることになっているのでその値を取り出します。そして再度その画像 URL を fetch してバイナリデータを取り出し、agent 変数を使ってアップロードします。そのアップロード結果の情報等を使って OGP の埋め込みデータ(embed_params 変数)を作成します。埋め込みデータを作ることができたら、その値を embed パラメータに加えて post する、という流れになります。これで OGP に対応したポスト処理を Node.js で行うことができるようになりました。


【サンプルソースコード公開】
後はこの実行を自動化することになりますが、今回は自分が使っているサーバーの crontab を使って日本時間の午前零時ちょうどに実行するようにしました。具体的なコードは後述しますが、大まかには、
(1)日本時間午前零時になったら、マンホールマップの「今日のマンホール」取得 API を呼び出し、
(2)その結果からリンク先 URL やポストするテキストを生成し、
(3)リンク先 URL の OGP 情報を使って画像やタイトルなどを取り出して、埋め込み、
(4)facets 処理を加えた上でポストする

という流れを行っています。そしてそのサンプルソースコードを以下で公開しています:
https://github.com/dotnsf/bsky_manhotalk_bot/blob/main/motd.js


上では解説していない部分を1点だけ。上述のように現状の Bluesky API は認証情報を ID とパスワードを直接指定する形で実行する必要があります。上のリンク先を見るとわかるのですが、今回公開したサンプルソースコードには ID やパスワードは含まれておらず、このソースコードを実行する際の環境変数から取得するようにしています。したがってこのソースコードを実行する時に、
$ BSKY_ID=myname@email.com BSKY_PW=mypassword node motd.js

といった具合に BSKY_ID 環境変数と BSKY_PW 環境変数にそれぞれ Bluesky へのログイン ID とパスワードを指定して実行することで正しく動くようにしています。

そうして作ったマンホールマップ・ボットはこちらのアカウントで公開しています:
https://bsky.app/profile/manholemap.bsky.social

2024021200


↑ツイッターとちがって Bluesky のアカウントを持っていない人でも見ることはできますが、可能であればアカウントを作ってフォローしてください。「今日のマンホール」が登録されている日全てで午前零時になると教えてくれます(登録されていない日もあります)。

とりあえず現時点では「今日のマンホール」専用で動くボットですが、いずれハッシュタグが実装されたら #manhotalk ハッシュタグを検索して・・といった挙動や、ちょっとした会話にも挑戦するつもりでいます。

このページのトップヘ