🎁

DBの無い世界線でECアプリを作ってみた話。〜Stripe Search APIを活用〜

2022/05/11に公開

作ったもの

自社で DB を持たず、Stripe のダッシュボードで顧客管理、商品管理、注文管理ができる、LINE チャットコマースアプリを作りました。

友だち追加から商品詳細

単品商品購入手順

定期販売購入手順

定期販売のキャンセル手順

作った経緯

2022 年 4 月に公開された Stripe Search API により、Stripe に保存している顧客、注文、商品、といった情報にクエリをかけることができるようになりました。

https://stripe.com/docs/search

それにより、「自社で DB を作らなくても、Stripe に保存した情報だけでアプリが作れるのでは?」と思い、一番作り慣れている LINE×EC アプリで実験することにしました。

しかし Stripe API だけでは、以下の処理に対応できません。

  • 在庫管理
  • トランザクション
  • 注文のステータス管理(商品準備中や配送中など)

EC サイトにおいて在庫管理は生命線といれるかもしれません。
しかし、SUZURIのようなオーダーメイドサービスを見て「注文されてから商品を作るビジネスもあるんだ」と思い在庫管理機能をなくした EC アプリを作ってみました。
他にもアパレルで多い予約販売をベースにした EC アプリにも活用でできるかと思います。

使用した Stripe API

使用した Stripe API は以下の 8 つです。

  • Search API
  • Customer
  • Checkout Session
  • Product
  • Prices
  • Invoice
  • Billing Portal
  • Webhook(API ではないけど)

友だち追加時に使用した API

Customer と Search API を活用してます。

const { data: customers } = await stripe.customers.search({
  query: `metadata['userId']:'${userId}'`,
});
if (customers.length === 0) {
  const lineProfile = await lineClient.getProfile(userId);
  return await stripe.customers.create({
    name: lineProfile.displayName || "未設定",
    description: userId,
    metadata: {
      userId,
    },
  });
} else {
  return data[0];
}

customer 作成時にmetadata内にuserId属性を作成することで、searchする際に以下のクエリを書くことで検索できます。

await stripe.customers.search({ query: `metadata['userId']:'${userId}'` });

参考
https://stripe.com/docs/api/customers/search

商品一覧と商品詳細に使用した API

Product と Price を使用してます。

export interface MsgProductList {
  productId: string;
  priceId: string;
  name: string;
  imgUrl: string;
  amount: number;
}

const getProducts = async (): Promise<Stripe.Product[]> => {
  const { data } = await stripe.products.list();
  return data;
};

const products = await getProducts();
const _products: MsgProductList[] = [];
await Promise.all(
  products.map(async (product) => {
    // @ts-ignore
    const price = await stripe.prices.retrieve(product.default_price);
    _products.push({
      productId: product.id,
      priceId: price.id,
      name: product.name,
      imgUrl: product.images[0],
      amount: Number(price.unit_amount),
    });
  })
);

MsgProductListは自分が LINE Flex メッセージに必要な情報をまとめた型になるため各々でよしなに変更をお願いします。
product内には、default_priceという値が型に存在しなかったため、@ts-ignoreをさせていただきました。(今後改善されるかも)

商品管理は、Stripe ダッシュボードの「商品」より可能です。

定期購入で使用した API

定期購入では、checkout.sessions.createを使用しました。

const { url } = await stripe.checkout.sessions.create({
  customer: customerId,
  line_items: [
    {
      price: priceId,
      quantity: 1,
    },
  ],
  shipping_address_collection: {
    allowed_countries: ["JP"],
  },
  mode: "subscription",
  payment_method_types: ["card"],
  success_url: LINE_FRIEND_URL,
  cancel_url: LINE_FRIEND_URL,
});
  • shipping_address_collectionallowed_countriesJPのみにすることで、配送先の入力が日本で固定されます。
  • modesubscriptionにする。
  • success_urlcancel_urlを LINE 公式アカウント友だち追加 URL にすることで、決済終了後に自動的に LINE 公式アカウントのトーク画面に遷移します。

定期購入された注文は、Stripe ダッシュボードの「支払い」→「サブスクリプション」より確認できます。

定期購入がキャンセルされた注文は、Stripe ダッシュボードの「支払い」→「サブスクリプション」→「キャンセル済み」より確認できます。

単品購入で使用した API

単品購入には、invoiceを使用しました。
定期購入のようにcheckout.sessions.createを使用しなった理由は、こちらに記載してます。

await stripe.invoiceItems.create({ customer: customerId, price: priceId });
const { id: invoiceId } = await stripe.invoices.create({
  customer: customerId,
  payment_settings: { payment_method_types: ["card", "konbini"] },
  collection_method: "send_invoice",
  days_until_due: 7,
});
await stripe.invoices.sendInvoice(invoiceId);
const { hosted_invoice_url } = await stripe.invoices.retrieve(invoiceId);
  • payment_method_typeskonbiniを追加することで、コンビニ決済が可能となります。
  • days_until_dueで支払いまでの有効日数を指定してます。

単品購入商品は、Stripe ダッシュボードの「支払い」で確認できます。
しかし、この画面には定期販売の情報も反映されるため、説明列を「Payment for Invoice」でフィルターすればより見やすくなります。

注文履歴&マイページに使用した API

注文履歴&マイページには、billingPortal.sessions.createを使用しました。

const { url } = await stripe.billingPortal.sessions.create({
  customer: customer.id,
  return_url: LINE_FRIEND_URL,
});
  • return_urlには、LINE 公式アカウントの友だち追加 URL を指定することで、Billing Portal 画面から容易に LINE 公式アカウントに遷移することができます。

工夫した点

注文履歴

マイページには、Billing Portal を活用しており、注文履歴や定期契約内容、個人情報はすべて確認&変更ができます。
注文履歴には、Billing Portal 内の「インボイス履歴」を代替としてます。

しかし、ここに表示される情報はStripe Invoiceが発行された注文のみとなります。
通常の EC には定期購入だけでなく単品購入もあり、Stripe Checkoutで定期販売の商品を購入すると自動的にInvoiceが作成されますが、単品商品では作成されません。
そのため、単品購入をCheckoutで処理するのではなくInvoiceで処理する必要があります。

クロスセル

Stripe ダッシュボードで商品には、クロスセルという機能があります。
Checkout Sessionにて商品を購入する際、オススメしたい商品を設定することができるので購買率を上げる施策が可能です。

  • Stripe ダッシュボード画面

  • Checkout Session 画面

まとめ

Stripe Search API によって、最小限のコストで EC アプリが作れました。
在庫管理を妥協しなければならないデメリットはありますが、在庫を持たないビジネスには活用できる開発方法です。
今回紹介した Search API 以外にも活用できそうなものがあるので、興味ある方はぜひ使用してみてください。
https://stripe.com/docs/search

今後も Stripe のアップデートが楽しみです!

GitHubで編集を提案
YOSHINANI

Discussion