npm package: @pulsora/revenue
Description: Privacy-first revenue tracking for Pulsora analytics - Server-side package
Author: Pulsora.co
Latest version: 1.0.0

# @pulsora/revenue

Privacy-first revenue tracking for Pulsora Analytics. Track revenue, subscriptions, and MRR with full attribution to customer journeys.

**⚠️ Server-Side Only**: This package is designed for server-side use to keep your API token secure.

## Installation

```bash
npm install @pulsora/revenue
```

## Quick Start

```typescript
import { Revenue } from '@pulsora/revenue';

const revenue = new Revenue({
  apiToken: 'your-api-token',
});

// Track a revenue event
await revenue.track({
  visitor_fingerprint: 'fp_from_payment_metadata',
  session_id: 'session_from_payment_metadata',
  customer_id: 'cus_123',
  amount: 99.99,
  currency: 'USD',
  transaction_id: 'tx_abc123',
  payment_processor: 'stripe',
  event_type: 'purchase',
});
```

## Configuration

### Revenue Options

```typescript
interface RevenueConfig {
  apiToken: string; // Required: Your Pulsora API token
  endpoint?: string; // Optional: API endpoint (default: https://api.pulsora.co/api/ingest)
  debug?: boolean; // Optional: Enable debug logging (default: false)
  maxRetries?: number; // Optional: Max retry attempts (default: 3)
  retryBackoff?: number; // Optional: Initial retry delay in ms (default: 1000)
}
```

## Revenue Tracking

### Basic Revenue Event

```typescript
await revenue.track({
  visitor_fingerprint: 'fp_123', // From payment metadata
  session_id: 'session_456', // From payment metadata
  customer_id: 'cus_789', // Your customer ID
  amount: 99.99,
  currency: 'USD',
  transaction_id: 'tx_abc123',
  payment_processor: 'stripe',
  event_type: 'purchase',
});
```

### Subscription Revenue

```typescript
await revenue.track({
  visitor_fingerprint: 'fp_123',
  session_id: 'session_456',
  customer_id: 'cus_789',
  amount: 29.99,
  currency: 'USD',
  transaction_id: 'tx_def456',
  payment_processor: 'stripe',
  event_type: 'subscription',
  customer_subscription_id: 'sub_123',
  mrr_impact: 29.99,
  is_recurring: true,
  metadata: {
    plan: 'pro',
    interval: 'monthly',
  },
});
```

### Event Types

- `purchase`: One-time purchase
- `subscription`: New subscription
- `renewal`: Subscription renewal
- `upgrade`: Subscription upgrade
- `downgrade`: Subscription downgrade
- `churn`: Subscription cancellation
- `refund`: Refund issued

## Payment Processor Integration

To track revenue with attribution, you need to pass `visitor_fingerprint` and `session_id` from your frontend to your payment processor.

### Stripe Example

#### Frontend (collect fingerprint & session)

```typescript
import { Pulsora } from '@pulsora/core';

const pulsora = new Pulsora({
  apiToken: 'your-public-token',
});

pulsora.init();

// When creating checkout session
const fingerprint = await pulsora.getVisitorFingerprint();
const sessionId = pulsora.getSessionId();

// Pass to your backend
const response = await fetch('/api/create-checkout', {
  method: 'POST',
  body: JSON.stringify({
    priceId: 'price_123',
    visitor_fingerprint: fingerprint,
    session_id: sessionId,
  }),
});
```

#### Backend (create Stripe session with metadata)

```typescript
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

app.post('/api/create-checkout', async (req, res) => {
  const { priceId, visitor_fingerprint, session_id } = req.body;

  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [{ price: priceId, quantity: 1 }],
    mode: 'payment',
    success_url: 'https://yoursite.com/success',
    cancel_url: 'https://yoursite.com/cancel',
    metadata: {
      visitor_fingerprint,
      session_id,
    },
  });

  res.json({ sessionId: session.id });
});
```

#### Webhook (track revenue)

```typescript
import { Revenue } from '@pulsora/revenue';
import Stripe from 'stripe';

const revenue = new Revenue({
  apiToken: process.env.PULSORA_API_TOKEN,
});

app.post('/webhooks/stripe', async (req, res) => {
  const event = req.body;

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;

    await revenue.track({
      visitor_fingerprint: session.metadata.visitor_fingerprint,
      session_id: session.metadata.session_id,
      customer_id: session.customer,
      amount: session.amount_total / 100, // Convert cents to dollars
      currency: session.currency.toUpperCase(),
      transaction_id: session.id,
      payment_processor: 'stripe',
      event_type: 'purchase',
    });
  }

  res.json({ received: true });
});
```

### Paddle Example

```typescript
// Frontend: Pass metadata through Paddle
Paddle.Checkout.open({
  items: [{ priceId: 'pri_123', quantity: 1 }],
  customData: {
    visitor_fingerprint: await pulsora.getVisitorFingerprint(),
    session_id: pulsora.getSessionId(),
  },
});

// Webhook: Track revenue
app.post('/webhooks/paddle', async (req, res) => {
  const event = req.body;

  if (event.event_type === 'transaction.completed') {
    await revenue.track({
      visitor_fingerprint: event.data.custom_data.visitor_fingerprint,
      session_id: event.data.custom_data.session_id,
      customer_id: event.data.customer_id,
      amount: parseFloat(event.data.details.totals.total),
      currency: event.data.currency_code,
      transaction_id: event.data.id,
      payment_processor: 'paddle',
      event_type: 'purchase',
    });
  }

  res.json({ success: true });
});
```

## Attribution

Revenue events are automatically attributed to the visitor's journey:

- **First Touch**: The initial source that brought the visitor (Google, Facebook, etc.)
- **Last Touch**: The most recent source before conversion
- **UTM Parameters**: Campaign tracking from pageviews

This happens automatically on the Pulsora backend using the `visitor_fingerprint` and `session_id`.

## API Reference

### `Revenue` Class

#### Constructor

```typescript
new Revenue(config: RevenueConfig)
```

Creates a new Revenue tracker instance.

#### Methods

##### `track(data: RevenueData): Promise<void>`

Track a revenue event.

**Required fields:**

- `visitor_fingerprint`: Browser fingerprint from frontend
- `session_id`: Session ID from frontend
- `customer_id`: Your unique customer identifier
- `amount`: Revenue amount (positive number)
- `transaction_id`: Unique transaction identifier

**Optional fields:**

- `currency`: Currency code (default: 'USD')
- `payment_processor`: Payment processor name (e.g., 'stripe', 'paddle')
- `event_type`: Type of revenue event
- `customer_subscription_id`: Subscription ID (for subscriptions)
- `mrr_impact`: MRR impact for subscription events
- `is_recurring`: Whether this is a recurring payment
- `metadata`: Additional metadata object

## Error Handling

The package includes automatic retry logic for network failures and rate limiting.

```typescript
try {
  await revenue.track({
    // ... revenue data
  });
} catch (error) {
  console.error('Failed to track revenue:', error);
  // Handle error (e.g., log to your error tracking service)
}
```

## Security

### ⚠️ Never use this package in the browser!

Using this package in the browser exposes your API token and creates serious security risks. Always use it server-side in:

- Node.js applications
- Serverless functions (AWS Lambda, Vercel, Netlify)
- Backend APIs (Express, Fastify, etc.)
- Webhook handlers

### Customer Privacy

The package is GDPR compliant:

- Customer IDs are hashed on Pulsora's backend before storage
- No PII is stored in plaintext
- Attribution is privacy-preserving using fingerprints

## Debug Mode

Enable debug mode to see detailed logging:

```typescript
const revenue = new Revenue({
  apiToken: 'your-api-token',
  debug: true,
});
```

## TypeScript Support

Full TypeScript support with type definitions included.

```typescript
import { Revenue, RevenueData, RevenueConfig } from '@pulsora/revenue';
```

## Bundle Size

- **ESM**: ~3KB (uncompressed)
- **Gzipped**: ~1.5KB

## License

MIT

## Support

- Documentation: https://pulsora.co/docs
- Issues: https://github.com/pulsora/pulsora/issues
- Email: support@pulsora.co