npm package: @redbroomsoftware/payments
Description: Unified payment client for RBS ecosystem apps
Author: RBS
Latest version: 1.0.0

# @rbs/payments

Unified payment client for the RBS ecosystem. Provides a standardized interface for interacting with Colectiva payment gateway across all ecosystem applications.

## Installation

```bash
npm install @rbs/payments
# or
pnpm add @rbs/payments
```

## Quick Start

### Creating Payments

```typescript
import { ColectivaClient } from '@rbs/payments';

const client = new ColectivaClient({
  apiKey: process.env.COLECTIVA_API_KEY!,
  appId: 'caracol' // Your app identifier
});

// Create a payment (auto-selects CoDi or MercadoPago)
const payment = await client.createPayment({
  amount: 150.00,
  concept: 'Order #123',
  referenceId: 'order_123',
  referenceType: 'order',
  customerInfo: {
    name: 'John Doe',
    email: 'john@example.com'
  }
});

if (payment.qrString) {
  // CoDi payment - display QR code
  console.log('Scan QR:', payment.qrString);
} else if (payment.checkoutUrl) {
  // MercadoPago - redirect user
  window.location.href = payment.checkoutUrl;
}
```

### Handling Webhooks

```typescript
// src/routes/api/webhooks/payment/+server.ts
import { createSvelteKitHandler } from '@rbs/payments';
import { adminDb } from '$lib/server/firebase-admin';
import { env } from '$env/dynamic/private';

export const POST = createSvelteKitHandler({
  secret: env.COLECTIVA_WEBHOOK_SECRET,

  async updateEntity(referenceId, updates) {
    await adminDb.collection('orders').doc(referenceId).update(updates);
  },

  async onPaymentCompleted(payload) {
    console.log('Payment completed:', payload.paymentId);
    // Send confirmation email, update inventory, etc.
  },

  async onPaymentFailed(payload) {
    console.log('Payment failed:', payload.paymentId);
    // Notify user, retry logic, etc.
  }
});
```

## Payment Methods

The client automatically selects the optimal payment method:

| Amount | Default Method | Cost |
|--------|---------------|------|
| ≤ $8,000 MXN | CoDi (QR) | 0% |
| > $8,000 MXN | MercadoPago | 2.5-3.5% |

You can also force a specific method:

```typescript
// Force CoDi
const codiPayment = await client.createCodiPayment({
  amount: 500,
  concept: 'Coffee order',
  referenceId: 'order_456',
  referenceType: 'order'
});

// Force card (MercadoPago)
const cardPayment = await client.createCardPayment({
  amount: 15000,
  concept: 'Monthly subscription',
  referenceId: 'sub_789',
  referenceType: 'subscription'
});

// OXXO payment
const oxxoPayment = await client.createOxxoPayment({
  amount: 300,
  concept: 'Product purchase',
  referenceId: 'order_101',
  referenceType: 'order'
});
```

## Wallet Operations

```typescript
// Check wallet balance
const balance = await client.getWalletBalance('org_123');
console.log('Available:', balance.available);

// Deduct from wallet (for service charges)
const result = await client.deductFromWallet('org_123', {
  amount: 5.0,
  description: 'AI classification service',
  referenceId: 'txn_123',
  service: 'AI_CLASSIFICATION'
});
```

## Polling for Payment Completion

```typescript
const status = await client.waitForPayment(payment.paymentId, {
  maxAttempts: 60, // 5 minutes at 5s intervals
  intervalMs: 5000,
  onStatusChange: (status) => {
    console.log('Status changed:', status.status);
  }
});

if (status.status === 'completed') {
  console.log('Payment successful!');
}
```

## Invoice Generation

```typescript
const payment = await client.createPayment({
  amount: 1500,
  concept: 'Professional services',
  referenceId: 'inv_123',
  referenceType: 'invoice',
  customerInfo: {
    name: 'Acme Corp',
    rfc: 'ACM123456789',
    email: 'billing@acme.com'
  },
  createInvoice: true,
  invoiceData: {
    cfdiUse: 'G03',
    taxRegime: '601',
    items: [
      {
        description: 'Consulting services',
        quantity: 1,
        unitPrice: 1500,
        total: 1500
      }
    ]
  }
});

if (payment.invoice) {
  console.log('Invoice UUID:', payment.invoice.uuid);
  console.log('PDF:', payment.invoice.pdfUrl);
}
```

## Webhook Verification

If you need manual webhook handling:

```typescript
import { verifyWebhookSignature, parseColectivaWebhook } from '@rbs/payments';

// Verify signature manually
const isValid = await verifyWebhookSignature(
  rawBody,
  request.headers.get('x-webhook-signature'),
  request.headers.get('x-webhook-timestamp'),
  WEBHOOK_SECRET
);

// Parse and validate webhook
const result = await parseColectivaWebhook(request, {
  secret: WEBHOOK_SECRET,
  allowUnsigned: process.env.NODE_ENV === 'development'
});

if (result.valid && result.payload) {
  // Process webhook
}
```

## Configuration

| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| `apiKey` | string | Yes | - | Colectiva API key |
| `appId` | string | Yes | - | Your app identifier |
| `baseUrl` | string | No | `https://colectiva.redbroomsoftware.com` | API base URL |
| `ecosystemOrgId` | string | No | - | Organization ID for wallet ops |
| `timeout` | number | No | 30000 | Request timeout (ms) |
| `debug` | boolean | No | false | Enable debug logging |

## Types

```typescript
import type {
  PaymentMethod,
  PaymentStatus,
  CreatePaymentRequest,
  PaymentResponse,
  WebhookPayload
} from '@rbs/payments';
```

## License

MIT