npm.io
0.3.4 • Published 15h ago

@fragmentpay/react

Licence
MIT
Version
0.3.4
Deps
0
Size
32 kB
Vulns
0
Weekly
0

@fragmentpay/react

React components for the Frag hosted checkout. Zero runtime deps.

Install

npm install @fragmentpay/react
# or: bun add @fragmentpay/react

Required environment variables

Name Where Example
NEXT_PUBLIC_FRAG_PUBLIC_KEY browser (public) pk_live_… or pk_test_…
FRAG_SECRET_KEY your backend only sk_live_… (used by @fragmentpay/server)

The React SDK never touches sk_…. Intent creation happens on your server and the client uses the returned intent.id.

End-to-end example (copy-paste)

1. Wrap your app once

// app/providers.tsx
"use client";
import { FragmentPayProvider } from "@fragmentpay/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <FragmentPayProvider publicKey={process.env.NEXT_PUBLIC_FRAG_PUBLIC_KEY!}>
      {children}
    </FragmentPayProvider>
  );
}

2. Create a server endpoint that starts the intent

// app/api/frag/route.ts
import { Frag } from "@fragmentpay/server";

const frag = new Frag({ secretKey: process.env.FRAG_SECRET_KEY! });

export async function POST(req: Request) {
  const { amount, email } = await req.json();
  const intent = await frag.paymentIntents.create({
    amount,
    currency: "USD",
    customerEmail: email,
    settlement: { chain: "base", token: "USDC", address: process.env.MERCHANT_USDC_ADDRESS! },
  });
  return Response.json(intent);
}

3. Drop the button in any page — that's it

// app/checkout/page.tsx
"use client";
import { FragmentPayButton } from "@fragmentpay/react";

export default function Checkout() {
  return (
    <FragmentPayButton
      endpoint="/api/frag"
      input={{ amount: 25, email: "buyer@example.com" }}
      label="Pay $25 with Frag"
      onSettled={(intent) => console.log("paid!", intent.id)}
      onError={(intent) => console.error("payment failed", intent.status)}
    />
  );
}

Behind the scenes: click → POST to your /api/frag → returns intent → embed Frag checkout iframe → live-poll status → invoke onSettled when status === "settled".

Embed vs redirect

// Embed (default) — hosted checkout iframe with post-message events
<FragmentPayCheckout intentId={id} onSettled={onDone} onError={onErr} />

// Redirect — full-page navigation to hosted checkout
<FragmentPayCheckout intentId={id} mode="redirect" />

// Or just point the user at the hosted URL manually:
window.location.href = intent.checkout_url;

Polling with useFragmentIntent

const { data, status } = useFragmentIntent(intentId, { intervalMs: 3000 });
// data.status: created → quoted → executing → settled | failed | expired

Polling uses exponential backoff on 5xx / network errors and honors any Retry-After header the API returns; on the terminal states (settled, failed, expired, cancelled, refunded) polling stops automatically.

Validation

Wrong props fail immediately with a clear message:

<FragmentPayProvider publicKey="oops">…
// Error: [fragmentpay] publicKey must match pk_test_… or pk_live_…

API

  • <FragmentPayProvider publicKey baseUrl?>
  • <FragmentPayButton endpoint input label onSettled onError>
  • <FragmentPayCheckout intentId onSettled onError mode="iframe" | "redirect">
  • useFragmentIntent(intentId, { intervalMs })
  • useFragmentTokens({ chain })
  • useCreateIntent({ endpoint, transform, headers })
  • fetchWithRetry(url, init) — exported for advanced integrators

License

MIT

Keywords