coal
coal

React SDK

The coal-react package provides a <CoalCheckoutButton> component and a useCoalCheckout hook for integrating Coal payments into React applications. The SDK is redirect-based — it navigates users to the Coal-hosted checkout page. Full TypeScript support is included.


Installation

bash
1npm install coal-react
2# or
3yarn add coal-react
4# or
5pnpm add coal-react

Peer dependencies: React 18+ and React DOM 18+.


How it works

Coal uses a redirect-based checkout flow:

  1. Your server creates a checkout session via the Coal API
  2. Your server returns a checkoutUrl to the client
  3. The SDK button redirects the user to that URL
  4. The user pays on the Coal-hosted page
  5. After payment, Coal redirects the user to your redirectUrl

No iframe, no postMessage events — just a clean redirect flow.


<CoalCheckoutButton>

Renders a styled button that redirects to the Coal checkout page.

Props

PropTypeDefaultDescription
checkoutUrlstringFull checkout URL returned by your session endpoint. Preferred.
sessionIdstringAlternative to checkoutUrl — URL is constructed from this.
baseUrlstring'https://usecoal.xyz'Override the Coal base URL (for local dev).
target'_self' | '_blank''_self''_self' redirects in the current tab, '_blank' opens a new tab.
onBeforeRedirect() => voidCallback fired just before the redirect. Use for analytics.
childrenReact.ReactNode"Pay with Coal"Override button content.
classNamestringCSS class names on the button element.
styleReact.CSSPropertiesInline styles on the button element.

Basic usage

tsx
1import { CoalCheckoutButton } from 'coal-react';
2
3export default function BuyButton({ checkoutUrl }: { checkoutUrl: string }) {
4 return (
5 <CoalCheckoutButton
6 checkoutUrl={checkoutUrl}
7 onBeforeRedirect={() => console.log('Redirecting to checkout…')}
8 />
9 );
10}

With session ID

If your backend returns only a sessionId, you can pass that instead:

tsx
1<CoalCheckoutButton
2 sessionId={sessionId}
3 baseUrl="https://usecoal.xyz"
4/>

Open in a new tab

Useful for demo pages or when you want to keep your page visible:

tsx
1<CoalCheckoutButton
2 checkoutUrl={checkoutUrl}
3 target="_blank"
4>
5 Pay with Crypto ↗
6</CoalCheckoutButton>

useCoalCheckout hook

A lower-level hook that gives you the resolved URL and programmatic redirect/open methods.

Signature

typescript
1function useCoalCheckout(options: UseCoalCheckoutOptions): UseCoalCheckoutReturn

UseCoalCheckoutOptions

OptionTypeDescription
checkoutUrlstringFull checkout URL. Preferred.
sessionIdstringAlternative — URL is constructed as {baseUrl}/pay/checkout/{id}.
baseUrlstringOverride the Coal base URL. Defaults to 'https://usecoal.xyz'.

UseCoalCheckoutReturn

PropertyTypeDescription
checkoutUrlstring | nullResolved checkout URL, or null if not ready.
redirectToCheckout() => voidRedirect in the current tab.
openCheckout() => voidOpen checkout in a new tab.

Example

tsx
1'use client';
2
3import { useState } from 'react';
4import { useCoalCheckout } from 'coal-react';
5
6export default function CheckoutButton({ amount, productName }: { amount: number; productName: string }) {
7 const [checkoutUrl, setCheckoutUrl] = useState<string | null>(null);
8 const [loading, setLoading] = useState(false);
9
10 const { redirectToCheckout } = useCoalCheckout({ checkoutUrl: checkoutUrl ?? undefined });
11
12 const handleCheckout = async () => {
13 setLoading(true);
14 const res = await fetch('/api/create-session', {
15 method: 'POST',
16 headers: { 'Content-Type': 'application/json' },
17 body: JSON.stringify({ amount, productName }),
18 });
19 const data = await res.json();
20 setCheckoutUrl(data.checkoutUrl);
21 // Redirect immediately
22 window.location.href = data.checkoutUrl;
23 };
24
25 return (
26 <button onClick={handleCheckout} disabled={loading}>
27 {loading ? 'Creating session…' : `Pay $${amount}`}
28 </button>
29 );
30}

Full Next.js example

1. Create a session on your server

typescript
1// app/api/create-session/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function POST(req: NextRequest) {
5 const { amount, productName } = await req.json();
6
7 const res = await fetch('https://api.usecoal.xyz/api/checkouts', {
8 method: 'POST',
9 headers: {
10 'Content-Type': 'application/json',
11 'x-api-key': process.env.COAL_API_KEY!,
12 },
13 body: JSON.stringify({
14 amount,
15 productName,
16 redirectUrl: `${req.nextUrl.origin}/success`,
17 }),
18 });
19
20 const data = await res.json();
21 const sessionId = data.data?.id ?? data.id;
22 const checkoutUrl = `https://usecoal.xyz/pay/checkout/${sessionId}`;
23
24 return NextResponse.json({ sessionId, checkoutUrl });
25}

2. Render the checkout button

tsx
1// app/checkout/page.tsx
2'use client';
3
4import { useState } from 'react';
5import { CoalCheckoutButton } from 'coal-react';
6
7export default function CheckoutPage() {
8 const [checkoutUrl, setCheckoutUrl] = useState<string | null>(null);
9 const [loading, setLoading] = useState(false);
10
11 const createSession = async () => {
12 setLoading(true);
13 const res = await fetch('/api/create-session', {
14 method: 'POST',
15 headers: { 'Content-Type': 'application/json' },
16 body: JSON.stringify({ amount: 29.99, productName: 'Pro Plan' }),
17 });
18 const data = await res.json();
19 setCheckoutUrl(data.checkoutUrl);
20 setLoading(false);
21 };
22
23 if (!checkoutUrl) {
24 return (
25 <button onClick={createSession} disabled={loading}>
26 {loading ? 'Loading…' : 'Buy Pro Plan – $29.99'}
27 </button>
28 );
29 }
30
31 return (
32 <CoalCheckoutButton
33 checkoutUrl={checkoutUrl}
34 onBeforeRedirect={() => console.log('Checkout started')}
35 />
36 );
37}

3. Handle the success redirect

After payment, Coal redirects the user to your redirectUrl with ?session_id=... appended:

tsx
1// app/success/page.tsx
2import { Suspense } from 'react';
3import { useSearchParams } from 'next/navigation';
4
5function SuccessContent() {
6 const params = useSearchParams();
7 const sessionId = params.get('session_id');
8 return <p>Payment confirmed! Session: {sessionId}</p>;
9}
10
11export default function SuccessPage() {
12 return (
13 <Suspense>
14 <SuccessContent />
15 </Suspense>
16 );
17}

TypeScript types

All types are exported from coal-react:

typescript
1import type {
2 CoalCheckoutButtonProps,
3 UseCoalCheckoutOptions,
4 UseCoalCheckoutReturn,
5} from 'coal-react';

Backwards-compatible aliases

CoalWidget and CoalCheckout are exported as aliases for CoalCheckoutButton for backwards compatibility. They are deprecated — use CoalCheckoutButton in new code.

tsx
1// These still work but are deprecated:
2import { CoalWidget, CoalCheckout } from 'coal-react';

Next steps