npm package: @keychain-pay/stripe
Description: Keychain payment integration for Stripe - includes Payment Element customPaymentMethods support
Author: Keychain
Latest version: 1.4.0

# @keychain-pay/stripe

Add Keychain payments to your Stripe checkout. Multi-currency support with locale-aware formatting.

## Installation

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

## Quick Start

### 1. Get Your API Key

Register at [developers.trykeychain.com](https://developers.trykeychain.com) to get your `sk_test_...` API key.

### 2. Add the Button (React)

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

function Checkout() {
  return (
    <KeychainPayButton
      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"** with correct locale formatting.

## Multi-Currency Support

### Supported Currencies

| Currency | Code | Symbol | Locale | Example |
|----------|------|--------|--------|---------|
| US Dollar | USD | $ | en-US | $100.00 |
| Indian Rupee | INR | ₹ | en-IN | ₹1,000.00 |
| Euro | EUR | € | de-DE | 100,00 € |
| British Pound | GBP | £ | en-GB | £100.00 |
| Canadian Dollar | CAD | C$ | en-CA | C$100.00 |
| Australian Dollar | AUD | A$ | en-AU | A$100.00 |
| Mexican Peso | MXN | $ | es-MX | $100.00 |
| Philippine Peso | PHP | ₱ | en-PH | ₱100.00 |

### Cross-Currency Experience

When a US customer pays an Indian merchant:
- Merchant prices in INR
- Customer sees: "₹1,000.00 (≈ $12.00 USD)"
- Exchange rate locked at payment time
- Zero FX markup

## KeychainPayButton 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 to attach |
| `onSuccess` | function | No | Called on successful payment |
| `onError` | function | No | Called on payment error |
| `onCancel` | function | No | Called when user cancels |
| `buttonText` | string | No | Custom button text (default shows amount) |
| `showCashback` | boolean | No | Show cashback amount (default: true) |
| `variant` | string | No | `'primary'` or `'outline'` |
| `disabled` | boolean | No | Disable the button |

## Stripe Payment Element Integration

For full integration with Stripe's Payment Element using `customPaymentMethods`:

```tsx
import { useKeychainStripe } from '@keychain-pay/stripe/react';
import { PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';

function CheckoutForm({ amount, orderId }) {
  const stripe = useStripe();
  const elements = useElements();

  const {
    customPaymentMethods,
    isKeychainPayment,
    processKeychainPayment,
    calculateReward,
  } = useKeychainStripe({
    apiKey: 'sk_test_xxx',
    customPaymentMethodId: 'cpmt_keychain', // From Stripe Dashboard
    onSuccess: (result) => {
      console.log('Paid!', result.transactionId);
      window.location.href = '/success';
    },
    onError: (error) => console.error(error),
  });

  const handleSubmit = async (e) => {
    e.preventDefault();

    const { error, paymentMethod } = await elements.submit();
    if (error) return;

    // Check if Keychain was selected
    if (isKeychainPayment(paymentMethod)) {
      await processKeychainPayment({
        amount,
        orderId,
        currency: 'INR',  // Merchant's currency
      });
      return;
    }

    // Handle regular Stripe payment
    await stripe.confirmPayment({
      elements,
      confirmParams: { return_url: `${window.location.origin}/success` },
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <PaymentElement />
      <p>Earn {formatCurrency(calculateReward(amount), 'INR')} cashback with Keychain</p>
      <button type="submit">Pay</button>
    </form>
  );
}
```

### Hook Return Values

| Property | Type | Description |
|----------|------|-------------|
| `keychainElement` | `KeychainStripeElement` | The underlying element instance |
| `customPaymentMethods` | array | Config for Stripe Elements |
| `isKeychainPayment` | function | Check if payment method is Keychain |
| `processKeychainPayment` | function | Process payment through Keychain |
| `calculateReward` | function | Calculate cashback for an amount |

## Vanilla JavaScript / CDN

```html
<button id="keychain-pay-btn">Pay with Keychain</button>

<script src="https://unpkg.com/@keychain-pay/stripe@latest/dist/keychain-stripe.global.js"></script>
<script>
  const keychain = new KeychainStripeElement({
    apiKey: 'sk_test_xxx',
    onSuccess: (result) => {
      console.log('Paid!', result.transactionId);
      window.location.href = '/success';
    },
    onError: (error) => console.error(error),
    onCancel: () => console.log('Cancelled'),
  });

  document.getElementById('keychain-pay-btn').addEventListener('click', () => {
    keychain.processPayment({
      amount: 100000,      // ₹1,000.00
      currency: 'INR',
      orderId: 'order_123',
    });
  });
</script>
```

### KeychainStripeElement Methods

| Method | Description |
|--------|-------------|
| `processPayment({ amount, orderId, currency?, metadata? })` | Open checkout modal |
| `createSession({ amount, orderId, currency?, metadata? })` | Create session only |
| `getStripeConfig()` | Get Stripe customPaymentMethods config |
| `isKeychainPaymentMethod(pm)` | Check if payment method is Keychain |
| `calculateReward(amountCents)` | Calculate expected cashback |
| `destroy()` | Clean up event listeners |

## PaymentResult Type

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

## Subscriptions

### KeychainSubscribeButton

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

<KeychainSubscribeButton
  apiKey="sk_test_xxx"
  amount={499900}           // ₹4,999.00/month
  currency="INR"
  interval="month"
  orderId="sub_123"
  planName="Pro Plan"
  onSubscribed={(result) => {
    console.log('Subscribed!', result.subscriptionId);
  }}
/>
// Shows: "Subscribe with Keychain" + "₹4,999.00 monthly"
```

### useKeychainSubscription Hook

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

const { processSubscription, formatInterval } = useKeychainSubscription({
  apiKey: 'sk_test_xxx',
  onSuccess: (result) => console.log('Subscribed!', result),
});

await processSubscription({
  amount: 499900,
  currency: 'INR',
  orderId: 'sub_123',
  interval: 'month',
  planName: 'Pro Plan',
});
```

## Send Money / Remittance

### KeychainSendButton

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

<KeychainSendButton
  buttonText="Send Money"
  country="IN"              // Default recipient country
  onSuccess={(result) => {
    console.log('Link created!', result.linkUrl);
  }}
/>
```

### useKeychainSend Hook

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

const { openSendWidget, isOpen, close } = useKeychainSend({
  onSuccess: (result) => console.log('Link created!', result),
});

// Open send widget with pre-filled values
await openSendWidget({
  amount: 500000,           // ₹5,000.00
  memo: 'Birthday gift',
  country: 'IN',
});
```

## Currency Examples

### India (INR)

```tsx
<KeychainPayButton
  apiKey="sk_test_xxx"
  amount={100000}        // ₹1,000.00 (in paise)
  currency="INR"
  orderId="order_123"
  onSuccess={(result) => router.push('/success')}
/>
// Button: "Pay ₹1,000.00 with Keychain"
// Cashback: "Earn ₹50.00 cashback on this purchase"
```

### Europe (EUR)

```tsx
<KeychainPayButton
  apiKey="sk_test_xxx"
  amount={5000}          // €50.00 (in cents)
  currency="EUR"
  orderId="order_456"
  onSuccess={(result) => router.push('/success')}
/>
// Button: "Pay 50,00 € with Keychain"
// Cashback: "Earn 2,50 € cashback on this purchase"
```

### USA (USD)

```tsx
<KeychainPayButton
  apiKey="sk_test_xxx"
  amount={2500}          // $25.00 (in cents)
  currency="USD"
  orderId="order_789"
  onSuccess={(result) => router.push('/success')}
/>
// Button: "Pay $25.00 with Keychain"
// Cashback: "Earn $1.25 cashback on this purchase"
```

## Testing

Use test mode API keys (prefix `sk_test_`) for development:

- Use any phone number
- OTP code is logged to console (or use `123456`)
- No real money moves
- Payments are simulated

## Support

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

## License

MIT