mcpField
F
flutterwave

flutterwave

github.com/devmubarak1開発3150 回インストール2 週間前に更新
リポジトリ

flutterwave について

flutterwaveは、Flutterwave APIを統合する開発者向けのAIエージェントスキルです。v3とv4に対応するTypeScriptクライアントを備え、決済や送金、検証などの操作例とガイドを提供します。

主な機能

  1. 01Flutterwave API v3とv4に対応
  2. 02v4トークンキャッシュ付きTypeScriptクライアント
  3. 03決済・送金の操作例
  4. 04Webhook検証ガイド
  5. 05サンドボックス用テストデータ

活用シーン

  1. 01ホステッドチェックアウト決済の作成
  2. 02注文処理前の取引検証
  3. 03送金の開始と状態確認
  4. 04シークレットハッシュによるWebhook検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/devmubarak1/flutterwave --skill flutterwave

インストール後、Claude Code で/flutterwaveを入力して読み込まれたか確認します。

詳細

flutterwave

Flutterwave APIを統合するための、完全な本番対応 AI エージェントスキルです。**v3(本番環境で安定)とv4(次世代パブリックベータ)**の両方をネイティブにサポートしているため、開発者や AI エージェントは、サードパーティ製の CLI やプロキシに依存せず、バージョンをシームレスに選択して切り替えられます。


アーキテクチャとバージョンの比較

機能v3(本番環境で安定)v4(次世代パブリックベータ)
ステータス世界中で導入され、実績を重ねていますパブリックベータ(高性能、マイクロサービス)
ベース URLhttps://api.flutterwave.com/v3Sandbox:https://developersandbox-api.flutterwave.com
Live:https://f4bexperience.flutterwave.com/
認証固定シークレットキーのベアラー(FLW_SECRET_KEY)OAuth 2.0 OpenID Connect クライアントクレデンシャル(client_id + client_secret)
トークンエンドポイントN/APOST https://idp.flutterwave.com/realms/flutterwave/protocol/openid-connect/token
トレースヘッダー任意X-Trace-Id(12~255 文字の UUID、必須)
冪等性ペイロード内のカスタム tx_refX-Idempotency-Key ヘッダー + ペイロード内の reference
主な入金処理POST /payments または POST /chargescustomer_id と payment_method_id を指定した POST /charges
主な出金処理口座情報を指定した POST /transferspayment_instruction と recipient_id を指定した POST /transfers

ユニバーサルクライアントの実装(TypeScript)

外部 CLI への依存はありません。v3 と v4 の両方での実行、v4 の OAuth 2.0 トークンの自動キャッシュ、リクエストトレースに対応しています。

import crypto from "node:crypto";

export interface FlutterwaveConfig {
  secretKey?: string; // v3 secret key (e.g., FLWSECK_TEST-... or FLWSECK-...)
  encryptionKey?: string; // v3 3DES encryption key for direct card charges
  v4ClientId?: string; // v4 OAuth2 client_id
  v4ClientSecret?: string; // v4 OAuth2 client_secret
  v3BaseUrl?: string; // default: https://api.flutterwave.com/v3
  v4BaseUrl?: string; // sandbox: https://developersandbox-api.flutterwave.com | live: https://f4bexperience.flutterwave.com/
  v4IdpUrl?: string; // default: https://idp.flutterwave.com/realms/flutterwave/protocol/openid-connect/token
}

export interface FlwResponse<T = unknown> {
  status: "success" | "error";
  message: string;
  data: T;
  meta?: Record<string, unknown>;
}

export class FlutterwaveApiError extends Error {
  constructor(
    message: string,
    public readonly statusCode: number,
    public readonly payload?: unknown,
  ) {
    super(message);
    this.name = "FlutterwaveApiError";
  }
}

export class Flutterwave {
  private readonly config: FlutterwaveConfig;
  private v4TokenCache: { token: string; expiresAt: number } | null = null;

  constructor(config: FlutterwaveConfig = {}) {
    this.config = {
      secretKey: config.secretKey ?? process.env.FLW_SECRET_KEY,
      encryptionKey: config.encryptionKey ?? process.env.FLW_ENCRYPTION_KEY,
      v4ClientId: config.v4ClientId ?? process.env.FLW_V4_CLIENT_ID,
      v4ClientSecret: config.v4ClientSecret ?? process.env.FLW_V4_CLIENT_SECRET,
      v3BaseUrl: config.v3BaseUrl ?? process.env.FLW_V3_BASE_URL ?? "https://api.flutterwave.com/v3",
      v4BaseUrl: config.v4BaseUrl ?? process.env.FLW_V4_BASE_URL ?? "https://developersandbox-api.flutterwave.com",
      v4IdpUrl: config.v4IdpUrl ?? "https://idp.flutterwave.com/realms/flutterwave/protocol/openid-connect/token",
    };
  }

  /**
   * Retrieves or refreshes OAuth 2.0 access token for v4 requests.
   */
  private async getV4Token(): Promise<string> {
    const now = Date.now();
    if (this.v4TokenCache && this.v4TokenCache.expiresAt > now + 60_000) {
      return this.v4TokenCache.token;
    }

    if (!this.config.v4ClientId || !this.config.v4ClientSecret) {
      throw new Error("Missing v4 credentials: FLW_V4_CLIENT_ID and FLW_V4_CLIENT_SECRET are required for v4 calls.");
    }

    const res = await fetch(this.config.v4IdpUrl!, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        grant_type: "client_credentials",
        client_id: this.config.v4ClientId,
        client_secret: this.config.v4ClientSecret,
      }).toString(),
    });

    if (!res.ok) {
      throw new FlutterwaveApiError(`Failed to fetch v4 OAuth token: ${res.statusText}`, res.status);
    }

    const data = (await res.json()) as { access_token: string; expires_in: number };
    this.v4TokenCache = {
      token: data.access_token,
      expiresAt: now + data.expires_in * 1000,
    };

    return data.access_token;
  }

  /**
   * Executes a typed API request to either v3 or v4.
   */
  async request<T = unknown>(
    version: "v3" | "v4",
    path: string,
    options: RequestInit & { idempotencyKey?: string } = {},
  ): Promise<FlwResponse<T>> {
    const { idempotencyKey, headers: customHeaders, ...init } = options;
    const headers: Record<string, string> = {
      "Content-Type": "application/json",
      ...(customHeaders as Record<string, string>),
    };

    let baseUrl: string;
    if (version === "v3") {
      if (!this.config.secretKey) {
        throw new Error("Missing FLW_SECRET_KEY for v3 request");
      }
      baseUrl = this.config.v3BaseUrl!;
      headers["Authorization"] = `Bearer ${this.config.secretKey}`;
    } else {
      baseUrl = this.config.v4BaseUrl!;
      const token = await this.getV4Token();
      headers["Authorization"] = `Bearer ${token}`;
      headers["X-Trace-Id"] = crypto.randomUUID();
      if (idempotencyKey) {
        headers["X-Idempotency-Key"] = idempotencyKey;
      }
    }

    const url = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
    const response = await fetch(url, { ...init, headers });
    const body = (await response.json()) as FlwResponse<T>;

    if (!response.ok || body.status === "error") {
      throw new FlutterwaveApiError(
        body.message || `Flutterwave ${version} request failed with status ${response.status}`,
        response.status,
        body,
      );
    }

    return body;
  }
}

よく使われる操作とバージョン対応表

このスキルを使う開発者や AI エージェントは、v3 または v4 のどちらでも任意の操作を実行できます。

アクションメソッドv3 ルートv4 ベータルート主なパラメーター/説明
標準ホスト型チェックアウトPOST/payments/chargestx_ref、amount、currency、redirect_url、customer: { email, name }。チェックアウト URL を返します。
取引を ID で確認GET/transactions/{id}/verify/charges/{id}最終的な支払いステータス、決済済み金額、カードトークンを確認します。注文の履行前に必ず実行してください。
取引を参照で確認GET/transactions/verify_by_reference?tx_ref=.../charges?reference=...加盟店独自の注文/取引参照を使用して支払いを照会します。
取引一覧GET/transactions/chargesfrom、to、status、currency、ページネーションのpageで絞り込みます。
カードへの直接請求POST/charges?type=card/chargesv3 では 3DES 暗号化ペイロードを使用し、v4 ではauthorizationとともにpayment_method_idを使用します。
請求の検証(OTP)POST/validate-charge/charges/{id}/validate顧客の OTP チャレンジコード(flw_ref、otp)を送信します。
銀行振込による入金POST/charges?type=bank_transfer/virtual-accounts有効期限タイマー付きの、ナイジェリアの NIP 専用銀行口座を動的に生成します。
モバイルマネー(M-Pesa)POST/charges?type=mpesa/chargesケニアの顧客のモバイル端末に即時 STK プッシュプロンプトを表示します(KES)。
モバイルマネー(ガーナ)POST/charges?type=mobile_money_ghana/chargesMTN、Telecel(Vodafone バウチャー)、または AirtelTigo のウォレットに請求します(GHS)。
USSD 決済POST/charges?type=ussd/chargesオフライン決済用に、銀行固有の対話型ダイヤルコード(GTBank の場合は*737*...#など)を返します。
トークン化された請求POST/tokenized-charges/charges(recurring: true)保存済みのcard.tokenを使い、カード情報の入力なしでワンクリックチェックアウトやサブスクリプションの再請求を行います。
送金を開始(支払い)POST/transfers/transfers銀行口座またはモバイルウォレットに資金を支払います。v4 ではpayment_instructionとactionを使用します。
送金ステータスを取得GET/transfers/{id}/transfers/{id}支払いステータス(SUCCESSFUL、FAILED、PENDING)を確認します。
送金を再試行POST/transfers/{id}/retries/transfers/{id}/retry失敗した送金を再処理のために再送信します。
受取人一覧GET/beneficiaries/transfer-recipients保存済みの銀行口座やモバイルウォレットの支払い先を一覧表示します。
受取人を作成POST/beneficiaries/transfer-recipients受取人(account_number、account_bank、beneficiary_name、currency)を保存します。
バーチャル口座を作成POST/virtual-account-numbers/virtual-accounts顧客のウォレットに直接入金するための、恒久または動的なバーチャル銀行口座を発行します。
バーチャル口座を一括作成POST/bulk-virtual-account-numbers/virtual-accountsフィンテックプラットフォーム向けの専用バーチャル口座を一括作成します。
サブアカウントを作成(分割)POST/subaccounts分割設定マーケットプレイスの売上分割用にベンダーのサブアカウントを設定します(split_type: "percentage" | "flat")。
支払いプランを作成POST/payment-plansサブスクリプションプランサブスクリプションの自動請求間隔(daily、weekly、monthly、yearly)を設定します。
バーチャルカードを作成POST/virtual-cardsカード発行請求先住所を設定した、デジタルドル(USD)または現地通貨のデビットカードを発行します。
銀行口座を照合POST/accounts/resolve/accounts/lookupナイジェリアの銀行口座番号を検証し、登録されている正式な口座名義人の氏名を取得します。
BVN を検証POST/bvn/matchKYC 検証Bank Verification Number が顧客の法的な本人情報と一致することを確認し、コンプライアンス要件を満たします。
返金を発行POST/transactions/{id}/refund/refunds顧客の支払い元口座へ全額または一部を直接返金します。
チャージバックを管理GET / PUT/chargebacks/chargebacks未解決の異議申し立てを照会し、期限前に反証資料を提出します。
入金一覧GET/settlements/settlement銀行預金、総取引額、決済処理手数料の控除を照合します。
請求書の支払いと通話料金のチャージPOST/bills公共料金の請求書通話料金、モバイルデータバンドル、電力トークンを購入し、ケーブルテレビのサブスクリプションを更新します。

アクションコードのレシピ

1. 標準的なチェックアウト決済リンクを作成する(v3)
const flw = new Flutterwave();

const session = await flw.request<{ link: string }>("v3", "/payments", {
  method: "POST",
  body: JSON.stringify({
    tx_ref: `ORD-${Date.now()}`,
    amount: "7500.00",
    currency: "NGN",
    redirect_url: "https://yourdomain.com/checkout/callback",
    customer: {
      email: "[email protected]",
      name: "Amina Bello",
      phonenumber: "+2348012345678",
    },
    customizations: {
      title: "Store Checkout",
      description: "Payment for order #1082",
    },
  }),
});

console.log("Customer Payment URL:", session.data.link);
2. 必須のサーバー側取引検証(v3 と v4)
const flw = new Flutterwave();

// v3 verification by Transaction ID
const v3Tx = await flw.request<{
  status: string;
  amount: number;
  currency: string;
  tx_ref: string;
  card?: { token: string };
}>("v3", `/transactions/${transactionId}/verify`, { method: "GET" });

if (v3Tx.data.status === "successful" && v3Tx.data.amount >= orderAmount) {
  // Safe to credit account or ship goods
  const savedCardToken = v3Tx.data.card?.token;
}

// v4 Next-Gen verification by Charge ID
const v4Charge = await flw.request<{
  status: string;
  amount: number;
  currency: string;
  reference: string;
}>("v4", `/charges/${chargeId}`, { method: "GET" });
3. 即時銀行振込/出金を開始する(v3 と v4)
const flw = new Flutterwave();

// v3 Payout
const v3Payout = await flw.request("v3", "/transfers", {
  method: "POST",
  body: JSON.stringify({
    account_bank: "058", // GTBank
    account_number: "0123456789",
    amount: 50000,
    currency: "NGN",
    reference: `PAYOUT-${Date.now()}`,
    narration: "Vendor disbursement",
  }),
});

// v4 Next-Gen Transfer Orchestrator
const v4Payout = await flw.request("v4", "/transfers", {
  method: "POST",
  idempotencyKey: `IDEMP-${Date.now()}`,
  body: JSON.stringify({
    action: "instant",
    reference: `V4-PAYOUT-${Date.now()}`,
    narration: "Vendor payment",
    payment_instruction: {
      amount: 50000,
      currency: "NGN",
      recipient_id: "rcb_B9aAgsdzzl",
    },
  }),
});

Webhook の取り込みとセキュリティ標準

Flutterwave は、Flutterwave ダッシュボード(Settings > Webhooks)で設定し、verif-hash HTTP ヘッダーで渡されるシークレットハッシュを使用して Webhook を検証します。

import crypto from "node:crypto";

export function handleFlutterwaveWebhook(req: Request) {
  const incomingHash = req.headers.get("verif-hash");
  const secretHash = process.env.FLW_WEBHOOK_HASH;

  if (!incomingHash || !secretHash) {
    return new Response("Unauthorized", { status: 401 });
  }

  // Timing-safe constant-time comparison to prevent side-channel leaks
  const a = Buffer.from(incomingHash, "utf8");
  const b = Buffer.from(secretHash, "utf8");
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return new Response("Forbidden", { status: 403 });
  }

  // Respond HTTP 200 immediately to meet Flutterwave's 60-second SLA
  // Process the event asynchronously in the background
  return new Response(JSON.stringify({ status: "success" }), { status: 200 });
}

テストベクターとサンドボックステスト

決済手段テスト入力想定される動作
3DS Mastercardカード:5531881111111111、CVV:123、有効期限:09/32OTP が必要 -> 12345 を入力 -> 成功
Verve Card(PIN)カード:5060666666666666、CVV:111、有効期限:05/29PIN 1234 が必要。その後 OTP 12345 を入力 -> 成功
拒否シミュレーションカード:5531882222222222、CVV:123、有効期限:09/32直接拒否(Insufficient funds)
Kenya M-Pesa電話番号:2540700000000サンドボックスでシミュレーションされた STK プッシュを自動承認
銀行口座照会口座番号:0690000031、銀行:044(Access Bank)名前を照会:FLW TEST ACCOUNT

開発者と AI エージェントのベストプラクティス

  1. バージョンの分離: v3 のリクエストフィールド(例:customer.email を直接埋め込む)と v4 の構造(payment_instruction、customer_id)を混在させないでください。
  2. リダイレクト URL を決して信用しない: 顧客が redirect_url?status=successful に到達したというだけで、注文を処理してはいけません。必ずサーバー側で検証してください。
  3. 一意な参照の使用: すべての決済と出金で一意の tx_ref または reference を指定し、衝突を避けて冪等性を保証してください。
  4. 認証情報のセキュリティ: FLW_SECRET_KEY、FLW_V4_CLIENT_ID、FLW_V4_CLIENT_SECRET、FLW_WEBHOOK_HASH は安全な環境変数に保存してください。認証情報を git にコミットしてはいけません。

コメント