Integrations
Stripe Crypto & Stablecoin
Accept stablecoin payments (settling as fiat USD) and pay out merchant balances using Stripe Crypto — powered by the Bridge stablecoin orchestration infrastructure. In Furlpay this is wired through lib/payments/stripe.ts and two API routes.
1. Stablecoin checkout (PaymentIntents)
Create a PaymentIntent on the server. With dynamic payment methods, enable Crypto under Dashboard → Payments → Payment methods; Stripe then handles network selection (Ethereum, Base, Solana, Polygon) and asset support (USDC, USDP) behind the scenes.
// lib/payments/stripe.ts (server)
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function createCryptoPaymentIntent(amountInCents: number) {
const paymentIntent = await stripe.paymentIntents.create({
amount: amountInCents,
currency: 'usd',
automatic_payment_methods: { enabled: true }, // card + crypto
metadata: { integration: 'furlpay_connect_stablecoin' },
});
return { clientSecret: paymentIntent.client_secret };
}Furlpay exposes this at POST /api/payments/stripe/intent, which returns the client secret consumed by Stripe Elements.
Render Stripe Elements (frontend)
Elements renders the wallet connection interface (Phantom, MetaMask, Coinbase Wallet) and handles signing via crypto.stripe.com. See components/StripeCryptoCheckout.tsx.
'use client';
import { loadStripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!stripe || !elements) return;
const { error } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: 'https://furlpay.app/dashboard' },
});
if (error) console.error(error.message);
};
return (
<form onSubmit={onSubmit}>
<PaymentElement />
<button disabled={!stripe}>Pay with Stablecoin</button>
</form>
);
}2. B2B payouts & transfers
Send stablecoins to external vendor wallets or pay out merchant balances via the Transfers API.
export async function transferToMerchantWallet(destination: string, amount: number) {
return stripe.transfers.create({
amount, // amount in cents
currency: 'usd',
destination,
description: 'Furlpay stablecoin settlement payout via Bridge rails',
});
}3. Security best practices
Cryptographic webhook verification
Never trust events over HTTP without verifying the signature. Stripe signs webhooks with HMAC-SHA256; constructEvent validates the stripe-signature header against your endpoint secret and rejects tampered or replayed payloads.
// app/api/webhooks/stripe/route.ts
export async function POST(request: Request) {
const payload = await request.text(); // raw body is required
const sig = request.headers.get('stripe-signature')!;
try {
const event = stripe.webhooks.constructEvent(payload, sig, endpointSecret);
if (event.type === 'payment_intent.succeeded') {
// credit the Furlpay Safe balance / trigger local bank routing
}
return Response.json({ received: true });
} catch (err) {
return Response.json({ error: 'Signature verification failed' }, { status: 400 });
}
}Tokenized compliance (PCI / KYC offloading)
- Zero card custody: with Elements, your servers never touch card details or wallet private keys — keeping Furlpay in the lowest PCI bracket (SAQ-A).
- Travel Rule: for transactions over $1,000, Stripe/Bridge injects sender/receiver identity metadata to satisfy global AML requirements.
Network failover & slippage
- If an Ethereum transaction fails on a gas spike, dynamic routing falls back to high-speed L2s (Base or Solana).
- Slippage limits are set to <0.1% during stablecoin-to-fiat conversion to protect margins.
Idempotency
event.id so a redeliveredpayment_intent.succeeded never double-credits a balance.