npm package: @keychain-pay/react
Description: React hooks and components for Keychain Pay - Accept payments in React apps
Author: Keychain
Latest version: 1.2.0

# @keychain-pay/react

Accept USDC payments in React with a single hook or drop-in button. Multi-currency support included.

## Installation

```bash
npm install @keychain-pay/react
```

## Two Options

### Option 1: Drop-in Button (Easiest)

```tsx
import { KeychainCheckoutButton } from '@keychain-pay/react';

function Checkout() {
  return (
    <KeychainCheckoutButton
      apiKey="sk_test_xxx"
      amount={100000}           // ₹1,000.00 in paise
      currency="INR"            // Supports: USD, INR, EUR, GBP, CAD, AUD, MXN, PHP
      orderId="order_123"
      onSuccess={(result) => {
        console.log('Paid!', result.transactionId);
        window.location.href = '/success';
      }}
      onError={(error) => console.error(error)}
      onCancel={() => console.log('Cancelled')}
    />
  );
}
```

The button shows: **"Pay ₹1,000.00 with Keychain"** (formatted with correct locale).

### Option 2: Hook (More Control)

For custom UI with secure session-based checkout.

**Security First:** Your API key never touches the frontend. The hook only needs a `sessionId`.

```tsx
'use client';

import { useKeychainCheckout } from '@keychain-pay/react';

function CheckoutPage() {
  const { open } = useKeychainCheckout();

  const handlePay = async () => {
    // Get sessionId from your backend
    const res = await fetch('/api/create-checkout', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        amount: 100000,      // ₹1,000.00 in paise
        currency: 'INR',
        orderId: 'order_123'
      }),
    });
    const { sessionId } = await res.json();

    // Open checkout modal
    open({
      sessionId,
      onSuccess: (result) => {
        console.log('Paid!', result.transactionId);
        window.location.href = '/success';
      },
      onCancel: () => console.log('Cancelled'),
      onError: (error) => console.error(error.message),
    });
  };

  return <button onClick={handlePay}>Pay ₹1,000.00</button>;
}
```

## Backend: Create Session

```typescript
// app/api/create-checkout/route.ts (Next.js)
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const { amount, currency, orderId } = await request.json();

  const response = await fetch('https://api.trykeychain.com/api/v1/checkout/sessions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.KEYCHAIN_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount,
      currency,       // 'INR', 'USD', 'EUR', etc.
      orderId,
      returnUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/success`,
    }),
  });

  const { session } = await response.json();
  return NextResponse.json({ sessionId: session.id });
}
```

## Multi-Currency Support

### Supported Currencies

| Currency | Code | Symbol | Amount Unit |
|----------|------|--------|-------------|
| US Dollar | USD | $ | Cents (2500 = $25.00) |
| Indian Rupee | INR | ₹ | Paise (100000 = ₹1,000.00) |
| Euro | EUR | € | Cents (2500 = €25.00) |
| British Pound | GBP | £ | Pence (2500 = £25.00) |
| Canadian Dollar | CAD | C$ | Cents |
| Australian Dollar | AUD | A$ | Cents |
| Mexican Peso | MXN | $ | Centavos |
| Philippine Peso | PHP | ₱ | Centavos |

### Cross-Currency Payments

When merchant and customer currencies differ, the checkout shows both:

```
Primary:   ₹1,000.00
Secondary: ≈ $12.00 USD at 1 USD = 83.50 INR
```

Exchange rates are locked at payment time - no surprises for either party.

## KeychainCheckoutButton Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `apiKey` | string | Yes | Your Keychain API key |
| `amount` | number | Yes | Amount in smallest unit (cents/paise) |
| `orderId` | string | Yes | Your order ID |
| `currency` | string | No | Currency code (default: `'usd'`) |
| `metadata` | object | No | Custom metadata |
| `fullWidth` | boolean | No | Make button full width |
| `disabled` | boolean | No | Disable the button |
| `onSuccess` | function | No | Called on successful payment |
| `onError` | function | No | Called on payment error |
| `onCancel` | function | No | Called when user cancels |

## Hook API

### `useKeychainCheckout()`

Returns `{ open, close }` functions.

```typescript
const { open, close } = useKeychainCheckout();

// Open checkout
open({
  sessionId: 'cs_xxx',
  onSuccess: (result) => { /* handle success */ },
  onCancel: () => { /* handle cancel */ },
  onError: (error) => { /* handle error */ },
});

// Programmatically close
close();
```

### Hook Options

| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `sessionId` | string | Yes | Session ID from your backend |
| `onSuccess` | function | No | Called when payment succeeds |
| `onCancel` | function | No | Called when user cancels |
| `onError` | function | No | Called on error |
| `checkoutUrl` | string | No | Custom checkout URL (for testing) |

## PaymentResult Type

```typescript
interface PaymentResult {
  transactionId?: string;
  subscriptionId?: string;
  sessionId?: string;
  reward?: {
    amountCents: number;
  };
  // Multi-currency info
  merchantCurrency?: string;
  merchantAmountSmallestUnit?: number;
  customerCurrency?: string;
  customerAmountSmallestUnit?: number;
  exchangeRate?: number;
}
```

## Modal Behavior

- **Desktop**: Centered modal (420px wide)
- **Mobile**: Bottom sheet (full width)
- **Animations**: Smooth open/close transitions
- **Backdrop**: Click outside to cancel

## TypeScript Support

Full TypeScript definitions included:

```typescript
import {
  useKeychainCheckout,
  KeychainCheckoutButton,
  CheckoutOptions,
  PaymentResult,
  KeychainCheckoutButtonProps,
} from '@keychain-pay/react';
```

## Next.js Usage

Make sure you're in a client component:

```tsx
'use client';  // Required for Next.js App Router

import { useKeychainCheckout } from '@keychain-pay/react';
// or
import { KeychainCheckoutButton } from '@keychain-pay/react';
```

## Test Mode

Use test API keys (`sk_test_...`) for development:

- No real money is transferred
- OTP code is always `123456`
- Session IDs start with `cs_test_`

## Examples

### INR Checkout (India)

```tsx
<KeychainCheckoutButton
  apiKey="sk_test_xxx"
  amount={100000}      // ₹1,000.00
  currency="INR"
  orderId="order_123"
  onSuccess={(result) => router.push('/success')}
/>
// Button shows: "Pay ₹1,000.00 with Keychain"
```

### USD Checkout (US)

```tsx
<KeychainCheckoutButton
  apiKey="sk_test_xxx"
  amount={2500}        // $25.00
  currency="USD"
  orderId="order_456"
  onSuccess={(result) => router.push('/success')}
/>
// Button shows: "Pay $25.00 with Keychain"
```

### EUR Checkout (Europe)

```tsx
<KeychainCheckoutButton
  apiKey="sk_test_xxx"
  amount={5000}        // €50.00
  currency="EUR"
  orderId="order_789"
  onSuccess={(result) => router.push('/success')}
/>
// Button shows: "Pay 50,00 € with Keychain"
```

## Support

- Email: hello@trykeychain.com
- Docs: [developers.trykeychain.com](https://developers.trykeychain.com)