npm package: @fyber.one/sdk-js
Description: Official JavaScript SDK for Fyber payment processing
Author: Fyber
Latest version: 1.0.2

# Fyber JavaScript SDK

Official JavaScript SDK for Fyber payment processing.

## Installation

```bash
npm install @fyber.one/sdk-js
# or
pnpm add @fyber.one/sdk-js
```

## Quick Start

```javascript
import { Fyber } from '@fyber.one/sdk-js';

// Initialize the client
const fyber = new Fyber({
  apiKey: process.env.FYBER_SECRET_KEY,
  environment: 'test' // or 'live'
});

// Create a checkout session (recommended)
const session = await fyber.checkout.sessions.create({
  mode: 'payment',
  amount: 5000, // $50.00 in cents
  currency: 'JMD',
  successUrl: 'https://yoursite.com/success?session_id={SESSION_ID}',
  cancelUrl: 'https://yoursite.com/cancel',
  lineItems: [
    { name: 'Pro Plan', quantity: 1, unitAmount: 5000 }
  ],
  customerEmail: 'customer@example.com'
});

// Redirect customer to hosted checkout
console.log(session.url);
```

## Features

- 🛒 **Hosted Checkout** - Redirect customers to Fyber-hosted checkout (recommended)
- 💳 **Process Payments** - Accept credit/debit card payments
- 💰 **Manage Refunds** - Issue full or partial refunds
- 👥 **Customer Management** - Store and retrieve customer data
- 🔐 **Secure Authentication** - HMAC signature verification
- 🪝 **Webhook Verification** - Validate webhook signatures
- 📝 **TypeScript Support** - Full type definitions included

## Authentication

Get your API keys from the [Fyber Dashboard](https://console.fyber.one/api-keys).

```javascript
const fyber = new Fyber({
  apiKey: 'test_sk_...', // Test key for development
  environment: 'test'
});
```

**Important:** Never expose your API keys in client-side code. Always make API calls from your server.

## Usage

### Hosted Checkout (Recommended)

The easiest way to accept payments. Redirect customers to a Fyber-hosted checkout page that handles card input, validation, and 3DS authentication.

```javascript
// Create a checkout session
const session = await fyber.checkout.sessions.create({
  mode: 'payment',
  amount: 5000, // $50.00 in cents
  currency: 'JMD',
  successUrl: 'https://yoursite.com/success?session_id={SESSION_ID}',
  cancelUrl: 'https://yoursite.com/cancel',
  lineItems: [
    { name: 'Pro Plan', quantity: 1, unitAmount: 5000 }
  ],
  customerEmail: 'customer@example.com', // Optional: pre-fill email
  metadata: {
    orderId: '1234'
  }
});

// Redirect customer to checkout
res.redirect(session.url);
```

After payment, the customer is redirected to your `successUrl`. Use webhooks to confirm payment:

```javascript
// Retrieve the session to verify payment
const session = await fyber.checkout.sessions.getBySessionId('cs_test_...');

if (session.status === 'complete') {
  // Payment successful, fulfill the order
  console.log('Payment ID:', session.paymentId);
}
```

**Checkout modes:**
- `payment` - One-time payment (default)
- `setup` - Save card for future use without charging
- `subscription` - Start a recurring subscription

**Payment intents:**
- `sale` - Charge immediately (default)
- `authorize` - Authorize only, capture later
- `verify` - Validate card with $0 auth

```javascript
// Expire a session manually
await fyber.checkout.sessions.expire(session.id);

// List all sessions
const sessions = await fyber.checkout.sessions.list({
  status: 'complete',
  limit: 20
});
```

### Payments

```javascript
// Create a payment
const payment = await fyber.payments.create({
  amount: 5000,
  currency: 'JMD',
  source: {
    type: 'card',
    number: '4242424242424242',
    expMonth: 12,
    expYear: 2025,
    cvv: '123'
  },
  customer: {
    email: 'customer@example.com'
  },
  metadata: {
    orderId: '1234'
  }
});

// Retrieve a payment
const payment = await fyber.payments.get('pay_123');

// List payments
const payments = await fyber.payments.list({
  limit: 10,
  status: 'succeeded'
});

// Capture an authorized payment
const captured = await fyber.payments.capture('pay_123', {
  amount: 5000 // Optional: capture partial amount
});
```

### Refunds

```javascript
// Create a refund
const refund = await fyber.refunds.create({
  paymentId: 'pay_123',
  amount: 2500, // Optional: partial refund
  reason: 'requested_by_customer'
});

// Get a refund
const refund = await fyber.refunds.get('ref_123');

// List refunds
const refunds = await fyber.refunds.list({
  paymentId: 'pay_123'
});
```

### Customers

```javascript
// Create a customer
const customer = await fyber.customers.create({
  email: 'customer@example.com',
  name: 'John Doe',
  phone: '+1876-555-0123',
  metadata: {
    userId: 'user_123'
  }
});

// Get a customer
const customer = await fyber.customers.get('cus_123');

// Update a customer
const updated = await fyber.customers.update('cus_123', {
  name: 'Jane Doe'
});

// List customers
const customers = await fyber.customers.list({
  limit: 20
});
```

### Tokens (Saved Cards)

Save cards for future payments using hosted checkout with `mode: 'setup'`:

```javascript
// Create a setup session to save a card
const session = await fyber.checkout.sessions.create({
  mode: 'setup',
  customerId: 'cus_123',
  successUrl: 'https://yoursite.com/card-saved?session_id={SESSION_ID}',
  cancelUrl: 'https://yoursite.com/cancel',
});

// After checkout completes, the token is available via webhook
// or by retrieving the session
const completedSession = await fyber.checkout.sessions.getBySessionId('cs_test_...');
const tokenId = completedSession.tokenId;
```

```javascript
// List customer's saved cards
const tokens = await fyber.tokens.list({
  customerId: 'cus_123'
});

// Get a specific token
const token = await fyber.tokens.get('tok_123');

// Set as default payment method
await fyber.tokens.setDefault('tok_123');

// Delete a saved card
await fyber.tokens.delete('tok_123');

// Use a saved card for payment
const payment = await fyber.payments.create({
  amount: 5000,
  currency: 'JMD',
  tokenId: 'tok_123',
});
```

### Subscriptions

Create recurring billing subscriptions:

```javascript
// First, save a card using hosted checkout (mode: 'setup')
// Then create a subscription with the token

const subscription = await fyber.subscriptions.create({
  customerId: 'cus_123',
  tokenId: 'tok_123', // From saved card
  amount: 999, // $9.99/month
  currency: 'JMD',
  interval: 'month', // 'day', 'week', 'month', 'year'
  trialDays: 14, // Optional trial period
  metadata: {
    plan: 'pro'
  }
});

// Get subscription
const sub = await fyber.subscriptions.get('sub_123');

// List subscriptions
const subs = await fyber.subscriptions.list({
  customerId: 'cus_123',
  status: 'active'
});

// Pause a subscription
await fyber.subscriptions.pause('sub_123');

// Resume a paused subscription
await fyber.subscriptions.resume('sub_123');

// Cancel subscription
await fyber.subscriptions.cancel('sub_123', {
  cancelAtPeriodEnd: true, // Cancel at end of billing period
  reason: 'Customer requested'
});

// Get subscription stats
const stats = await fyber.subscriptions.stats();
console.log(`Active: ${stats.activeCount}, MRR: $${stats.mrr / 100}`);
```

**Subscription webhook events:**
- `subscription.created` - Subscription activated
- `subscription.payment_succeeded` - Recurring payment successful
- `subscription.payment_failed` - Recurring payment failed
- `subscription.trial_ending` - Trial ends in 3 days
- `subscription.canceled` - Subscription canceled

### Installments (BNPL)

Split payments into installment plans:

```javascript
// Check customer eligibility
const eligibility = await fyber.installments.checkEligibility({
  customerId: 'cus_123',
  amount: 50000, // $500.00
});

if (eligibility.eligible) {
  console.log(`Available options: ${eligibility.availableOptions} installments`);
  console.log(`Available credit: $${eligibility.availableCredit / 100}`);
}

// Create an installment plan (requires saved card)
const plan = await fyber.installments.create({
  customerId: 'cus_123',
  tokenId: 'tok_123',
  totalAmount: 50000, // $500.00 total
  installmentCount: 4, // 4 payments
  frequency: 'biweekly', // 'weekly', 'biweekly', 'monthly'
  metadata: {
    orderId: '1234'
  }
});

// Get installment plan
const plan = await fyber.installments.get('inst_123');

// List installment plans
const plans = await fyber.installments.list({
  customerId: 'cus_123',
  status: 'active'
});

// Cancel an installment plan
await fyber.installments.cancel('inst_123');

// Get installment stats
const stats = await fyber.installments.stats();
console.log(`Active plans: ${stats.activeCount}`);
console.log(`Default rate: ${stats.defaultRate * 100}%`);
```

**Installment webhook events:**
- `installment.plan_created` - Plan activated, first payment charged
- `installment.payment_succeeded` - Scheduled payment completed
- `installment.payment_failed` - Payment failed (may retry)
- `installment.plan_completed` - All payments completed
- `installment.plan_defaulted` - Customer defaulted

## Webhooks

Verify webhook signatures to ensure requests come from Fyber:

```javascript
import { Fyber } from '@fyber.one/sdk-js';

// Your webhook endpoint
app.post('/webhooks/fyber', (req, res) => {
  const signature = req.headers['fyber-signature'];
  const payload = req.body;
  
  try {
    // Verify the webhook signature
    const event = Fyber.webhooks.verify(
      payload,
      signature,
      process.env.FYBER_WEBHOOK_SECRET
    );
    
    // Handle the event
    switch (event.type) {
      case 'checkout.session.completed':
        // Checkout payment successful - fulfill order
        handleCheckoutComplete(event.data);
        break;
      case 'payment.succeeded':
        handlePaymentSucceeded(event.data);
        break;
      case 'payment.failed':
        handlePaymentFailed(event.data);
        break;
      case 'refund.created':
        handleRefundCreated(event.data);
        break;
    }
    
    res.status(200).json({ received: true });
  } catch (err) {
    console.error('Invalid webhook signature');
    res.status(400).json({ error: 'Invalid signature' });
  }
});
```

## Test Mode

Use test mode during development. Test API keys are prefixed with `test_`.

### Test Cards

| Card Number | Scenario |
|-------------|----------|
| `4242 4242 4242 4242` | Payment succeeds |
| `4000 0000 0000 0002` | Card declined |
| `4000 0000 0000 9995` | Insufficient funds |

Any future expiration date and any 3-digit CVV work with test cards.

## Error Handling

```javascript
try {
  const payment = await fyber.payments.create({...});
} catch (error) {
  if (error.type === 'card_error') {
    console.error('Card declined:', error.message);
  } else if (error.type === 'validation_error') {
    console.error('Invalid request:', error.message);
  } else {
    console.error('Unexpected error:', error.message);
  }
}
```

## TypeScript

The SDK is written in TypeScript and includes full type definitions:

```typescript
import { Fyber, Payment, Customer, Refund } from '@fyber.one/sdk-js';

const fyber = new Fyber({
  apiKey: process.env.FYBER_SECRET_KEY!,
  environment: 'test'
});

const payment: Payment = await fyber.payments.create({
  amount: 5000,
  currency: 'JMD',
  // ... TypeScript will validate your parameters
});
```

## API Reference

For detailed API documentation, visit [docs.fyber.one](https://docs.fyber.one).

## Support

- **Email:** support@fyber.one
- **Documentation:** https://docs.fyber.one
- **GitHub:** https://github.com/fyber-payments/sdk-js

## License

MIT