Quickstart
Ship Frag in 10 minutes
Copy every block in order. When you finish, you're accepting any token on any chain and settling in one.
STEP 0· 30 sec
Prerequisites
- Node 18+ (or Bun / Deno / Cloudflare Workers)
- A Frag account — sign in
- A settlement wallet address (EVM or Solana) you control
STEP 1· 2 min
Get your keys
- Open Dashboard → API Keys
- Copy
pk_test_…(publishable) andsk_test_…(secret) - Create a webhook endpoint and copy its signing secret
STEP 2· 1 min
Set environment variables
snippet.tsx
# .env (server)
FRAG_SECRET_KEY=sk_test_xxx
FRAG_WEBHOOK_SECRET=whsec_xxx
FRAG_API_URL=https://frag.cash # optional
# .env (client)
VITE_FRAG_PUBLIC_KEY=pk_test_xxx| Name | Scope | Purpose |
|---|---|---|
| FRAG_SECRET_KEY | server | Auth for REST calls |
| FRAG_WEBHOOK_SECRET | server | Verify inbound webhooks |
| VITE_FRAG_PUBLIC_KEY | client | Mount <FragmentPayCheckout> |
Never expose FRAG_SECRET_KEY to the browser.
STEP 3· 30 sec
Install the SDKs
snippet.tsx
npm install @fragmentpay/server @fragmentpay/react
# or: bun add / pnpm add / yarn addSTEP 4· 2 min
Create a payment intent (server)
snippet.tsx
import { FragmentPay } from "@fragmentpay/server";
const frag = new FragmentPay({ apiKey: process.env.FRAG_SECRET_KEY! });
export async function createCheckout(orderId: string, amountUsd: number) {
return frag.paymentIntents.create(
{
amount: amountUsd,
currency: "USD",
settlement: {
chain: "robinhood",
token: "USDC",
address: process.env.MERCHANT_WALLET!,
},
// Vending-machine by default — any supported token on any supported
// chain is accepted and auto-swapped to your settlement token.
metadata: { orderId },
},
{ idempotencyKey: `order:${orderId}` } // safe to retry
);
}STEP 5· 2 min
Mount the checkout widget (client)
snippet.tsx
import {
FragmentPayProvider,
FragmentPayCheckout,
} from "@fragmentpay/react";
export default function CheckoutPage({ intentId }: { intentId: string }) {
return (
<FragmentPayProvider publicKey={import.meta.env.VITE_FRAG_PUBLIC_KEY}>
<FragmentPayCheckout
intentId={intentId}
onSettled={(i) => {
window.location.href = `/thanks/${i.metadata.orderId}`;
}}
onError={(err) => console.error(err)}
/>
</FragmentPayProvider>
);
}Handles Reown/WalletConnect, multi-token contributions, quotes, retries, and confirmations automatically.
STEP 6· 2 min
Verify webhooks (server)
snippet.tsx
import { verifyWebhook } from "@fragmentpay/server";
export async function POST(req: Request) {
const body = await req.text(); // RAW body, not JSON.stringify
const sig = req.headers.get("frag-signature")!;
const event = await verifyWebhook({
payload: body,
signature: sig,
secret: process.env.FRAG_WEBHOOK_SECRET!,
});
switch (event.type) {
case "payment_intent.settled":
await fulfillOrder(event.data.metadata.orderId);
break;
case "payment_intent.expired":
case "payment_intent.failed":
await releaseInventory(event.data.metadata.orderId);
break;
}
return new Response("ok");
}Test with Developers → Webhooks → Send test event.
STEP 7· 30 sec
Go live
- Swap
pk_test_/sk_test_→pk_live_/sk_live_ - Update
FRAG_WEBHOOK_SECRETto the live endpoint's secret - Toggle Live mode in the dashboard header
Troubleshooting
| Symptom | Fix |
|---|---|
401 Unauthorized | Wrong key, or test-vs-live mismatch |
| Widget stuck loading | publicKey missing or mismatched env |
| Bad signature | Use raw body, verify secret matches endpoint |
429 | SDK auto-retries with Retry-After |