マーケットプレイスを提供している決済処理業者が多くないことを考えると、マーケットプレイスを作成するのはおそらく難しすぎるか不可能でしょう。もしマーケットプレイスが提供しなければ、その情報を知った瞬間にプラットフォームから強制終了される可能性が高く、それがなかったとしてもプラットフォームを使用して販売者への支払い、返金、支払いを処理するための強固な基盤がないマーケットプレイスを作成するのは危険です。
Stripe Connect はこれらの問題に対処し、販売者としてサインアップできる基本的なマーケットプレイスを作成し、顧客がこれらの販売者から商品を簡単に購入できるようにします。プラットフォーム所有者はサービス手数料を設定することもできるため、ユーザー X がストア Y から購入すると、その取引の X% が取り扱われますが、それについては後ほど説明します。
データベース接続の処理には Prisma を使用し、認証は remix-auth によって処理されます。この部分については、マーケットプレイスの販売者側のみを処理します。
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
これは schema.prisma ファイルの外観です。販売者モデルとそれに関連する店舗モデルがあります。「id」フィールドはサブドメインとして機能するため、購入者の側に到達すると、次のことが可能になります。 store.localhost.com にアクセスし、そこの販売者から製品を購入します。
また、販売者の Connect アカウントに関するデータを保存する Stripe モデルも追加します。
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
これでユーザーのオンボーディングを処理できるようになったので、.env ファイルに別の変数を定義しましょう。
STRIPE_SK=your stripe secret key here
Stripe の開発ページで生成することで Stripe 秘密キーを取得できます。現時点では Stripe Connect の使用のみを許可する制限付きキーを作成することをお勧めします。
次に、Stripe クライアントをエクスポートしてルートで使用できるようにする新しいファイルを作成する必要があります
// app/libs/stripe.server.ts import Stripe from 'stripe'; export const stripe = new Stripe(process.env.STRIPE_SK)
「/onboarding」に新しいルートを作成します
// app/routes/onboarding.tsx export default function Onboarding() { const {stripe} = useLoaderData(); return <div className={'text-center pt-[6%]'}> <h1 className={'text-xl'}>Account onboarded: {stripe?.is_onboarded ? stripe?.account_id : '? Not connected'}</h1> <div className={'flex items-center text-white text-sm mt-5 justify-center gap-3'}> {!stripe ? <> <Form method={'post'}> <button type={'submit'} className={'bg-blue-600 hover:cursor-pointer rounded-[6px] px-4 py-1.5'}>Setup your seller account </button> </Form> </> : <> <div className={'bg-blue-600 rounded-[6px] px-4 py-1.5'}>Seller dashboard</div> </>} </div> </div> }
販売者のオンボーディングステータスに関するデータを渡すローダー関数を追加します
export async function loader({request}: LoaderFunctionArgs) { const user = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: user.id }, include: { stripe: true } }) return { stripe: seller?.stripe } }
ここで、/onboarding にアクセスすると、接続されていないことが表示され、ボタンを押してサインアップできるようになります。ここでアクション関数が登場します。
export async function action({request}: ActionFunctionArgs) { const authenticated = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: authenticated.id }, include: { stripe: true } }) if (seller && seller.stripe?.is_onboarded) { return json({ message: 'User is onboarded already', error: true }, { status: 400 }) } const account = seller?.stripe?.account_id ? { id: seller.stripe?.account_id } : await stripe.accounts.create({ email: seller?.email, controller: { fees: { payer: 'application', }, losses: { payments: 'application', }, stripe_dashboard: { type: 'express', }, }, }); if (!seller?.stripe?.account_id) { await prisma.seller.update({ where: { id: authenticated.id }, data: { stripe: { create: { account_id: account.id } } }, include: { stripe: true } }) } const accountLink = await stripe.accountLinks.create({ account: account.id, refresh_url: 'http://localhost:5173/onboarding', return_url: 'http://localhost:5173/onboarding', type: 'account_onboarding', collection_options: { fields: 'eventually_due', }, }); console.debug(`[ACCOUNT ID = ${account.id}] CREATED ACCOUNT ONBOARDING LINK, REDIRECTING...`) return redirect(accountLink.url) }
販売者がボタンを押すと、登録に使用したメールアドレスでアカウントが作成され、販売者が既に Stripe アカウントを関連付けている場合は、オンボーディング ページにリダイレクトするアカウント リンクが作成されます。がオンボーディングされていない場合は、オンボーディング リンクにリダイレクトします。
そこから販売者はメール/電話番号を入力し、オンボーディングプロセスが始まります。通常、Stripe は販売者にビジネスの場所、ビジネスの詳細、銀行口座などを尋ねます...
Stripe Connect イベントの Webhook をリッスンできるようになりました。そのため、販売者が正常にオンボーディングしたら、それらの属性をデータベース内の販売者のレコードに追加します。
テストの場合は、Stripe CLI をダウンロードするだけで、そこからイベントをこれから作成する新しいルート /api/notifications に転送できます
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
そのコマンドを実行すると、Webhook 署名が与えられます。これにより、Stripe から送信された各 Webhook の整合性を検証できるようになります。Stripe の開発者ポータルで Webhook を作成した場合も同様に、シークレットが得られます。 .
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
.env ファイルに新しい変数も追加します
STRIPE_SK=your stripe secret key here
これで、Stripe から送信されるこれらのイベントを処理するコードを作成できます
// app/libs/stripe.server.ts import Stripe from 'stripe'; export const stripe = new Stripe(process.env.STRIPE_SK)
Stripe がリクエストを送信していることを確認します。Stripe である場合は次に進みます。注目したいイベントは account.updated です。そのイベントは、販売者をリダイレクトする前に作成したアカウントに関連しています。
販売者がオンボーディング プロセスを開始したり、電話番号を追加したり、電子メールを入力したり、最終的にオンボーディング プロセスを完了すると、「account.updated」イベントが取得され、この配列が一緒に送信されます
アカウント.requirements.currently_due
'currently_due' 配列の長さが 0 の場合、ユーザーが完全にオンボーディングされ、支払いを受け入れることができることがわかります。そのため、データベースを更新してユーザーが商品を作成できるようにすることができますが、その前に以下を追加しましょう「/api/notifications」アクション内のこのロジック
// app/routes/onboarding.tsx export default function Onboarding() { const {stripe} = useLoaderData(); return <div className={'text-center pt-[6%]'}> <h1 className={'text-xl'}>Account onboarded: {stripe?.is_onboarded ? stripe?.account_id : '? Not connected'}</h1> <div className={'flex items-center text-white text-sm mt-5 justify-center gap-3'}> {!stripe ? <> <Form method={'post'}> <button type={'submit'} className={'bg-blue-600 hover:cursor-pointer rounded-[6px] px-4 py-1.5'}>Setup your seller account </button> </Form> </> : <> <div className={'bg-blue-600 rounded-[6px] px-4 py-1.5'}>Seller dashboard</div> </>} </div> </div> }
それが整ったら、オンボーディングを試して、それが機能するかどうかを確認できます。たとえばアドレスを入力するとすぐに、プロジェクトのコンソールに
のようなメッセージが表示されます。
export async function loader({request}: LoaderFunctionArgs) { const user = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: user.id }, include: { stripe: true } }) return { stripe: seller?.stripe } }
これは、本文が検証され、Stripe からイベントを正常に受信していることを意味しますが、オンボーディングが機能するかどうかを見てみましょう。
最後のステップに到達すると、おそらくアカウントの詳細が不完全であることが表示されます。最後のステップは ID 確認です。これはテストモードなので、それをシミュレートできます
それが完了したら、前のページに戻り、送信を押し、送信を押して、コンソールに入ります
export async function action({request}: ActionFunctionArgs) { const authenticated = await authenticator.isAuthenticated(request, { failureRedirect: '/login' }) const seller = await prisma.seller.findFirst({ where: { id: authenticated.id }, include: { stripe: true } }) if (seller && seller.stripe?.is_onboarded) { return json({ message: 'User is onboarded already', error: true }, { status: 400 }) } const account = seller?.stripe?.account_id ? { id: seller.stripe?.account_id } : await stripe.accounts.create({ email: seller?.email, controller: { fees: { payer: 'application', }, losses: { payments: 'application', }, stripe_dashboard: { type: 'express', }, }, }); if (!seller?.stripe?.account_id) { await prisma.seller.update({ where: { id: authenticated.id }, data: { stripe: { create: { account_id: account.id } } }, include: { stripe: true } }) } const accountLink = await stripe.accountLinks.create({ account: account.id, refresh_url: 'http://localhost:5173/onboarding', return_url: 'http://localhost:5173/onboarding', type: 'account_onboarding', collection_options: { fields: 'eventually_due', }, }); console.debug(`[ACCOUNT ID = ${account.id}] CREATED ACCOUNT ONBOARDING LINK, REDIRECTING...`) return redirect(accountLink.url) }
これでうまくいきました。Stripe はオンボーディング ページに戻り、アカウント ID が表示されます。これはオンボーディングが成功し、製品の作成を開始できることを意味します。
それでは、商品に進む前に販売者ダッシュボード ボタンを機能させて、/portal に新しいルートを作成しましょう
// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model Store { id String @id // This will be the store's subdomain name String updated_at DateTime @default(now()) @updatedAt seller Seller? } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique }
非常に基本的な機能なので、オンボーディングしている場合に /portal にアクセスすると、Stripe アカウント用に生成された 1 回限りのリンクにリダイレクトされます。
オンボーディング ルートで、販売者ダッシュボード div をリンクでラップします。
model Stripe { account_id String @id is_onboarded Boolean @default(false) user Users @relation(fields: [user_id], references: [discord_id]) user_id String @unique created_at DateTime @default(now()) updated_at DateTime @updatedAt } model Seller { id Int @id @default(autoincrement()) email String password String store Store @relation(fields: [store_id], references: [id]) date_created DateTime @default(now()) date_updated DateTime @updatedAt store_id String @unique stripe Stripe? }
/portal にアクセスするかボタンを押すと、Stripe の Connect アカウント用ポータルにリダイレクトされ、ユーザーはそこで分析や支払いなどを確認できます...
これで、Stripe Connect を使用してマーケットプレイスを作成するパート 1 が終了します。パート 2 は製品、支払い、支払いを扱います。パート 3 が最後で、そこでプロジェクトの顧客側の側面を扱います。 .
プロジェクトのソース コードは、https://github.com/ddm50/ Stripe-connect-howto-seller でご覧いただけます
以上がStripe Connect を使用したマーケットプレイスの作成: オンボードプロセスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。