> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metrifox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript / Node.js

> Official **JavaScript SDK** for the Metrifox platform. Build and scale usage-based SaaS applications with comprehensive tools for customer management, usage tracking, access control, and embedded billing experiences.

## Installation

```bash theme={null}
npm install metrifox-js
```

***

## Quick Start

The Metrifox SDK supports a modern client-based architecture for better organization and type safety.

### Configuration

**Node.js:**

```javascript theme={null}
import { init } from "metrifox-js";

const metrifoxClient = init({
  apiKey: process.env.METRIFOX_API_KEY,
});
```

**Vite/React:**

```javascript theme={null}
import { init } from "metrifox-js";

const metrifoxClient = init({
  apiKey: import.meta.env.VITE_METRIFOX_API_KEY,
});
window.metrifoxClient = metrifoxClient;
```

**Alternative - Direct Initialization:**

```javascript theme={null}
import { MetrifoxSDK } from "metrifox-js";

const sdk = new MetrifoxSDK({
  apiKey: "your_api_key_here",
});
```

<Note>
  Get your API key from **Settings → API Keys** in your Metrifox dashboard.
</Note>

***

## Customer Management

### Create a Customer

```javascript theme={null}
// Individual customer
const customer = await client.customers.create({
  customer_key: "user_12345",  // Required: unique identifier
  customer_type: "INDIVIDUAL",  // Required: "INDIVIDUAL" or "BUSINESS"
  primary_email: "john.doe@example.com",  // Required
  first_name: "John",
  last_name: "Doe",
  primary_phone: "+1234567890",
  currency: "USD"
});

// Business customer
const customer = await client.customers.create({
  customer_key: "company_abc123",
  customer_type: "BUSINESS",
  primary_email: "contact@acmecorp.com",
  legal_name: "ACME Corporation LLC",
  display_name: "ACME Corp",
  website_url: "https://acmecorp.com"
});
```

### Update a Customer

```javascript theme={null}
const response = await client.customers.update("user_12345", {
  primary_email: "newemail@example.com",
  first_name: "Jane",
  currency: "EUR"
});
```

<Note>
  The `customer_key` cannot be changed after creation.
</Note>

### Get Customer Data

```javascript theme={null}
// Get basic customer data
const customer = await client.customers.get("customer_123");

// Get detailed customer information
const customerDetails = await client.customers.getDetails("customer_123");

// List customers with pagination
const customerList = await client.customers.list({
  page: 1,
  per_page: 50,
  search_term: "john@example.com",  // Optional
  customer_type: "INDIVIDUAL",  // Optional
  date_created: "2025-09-01"  // Optional
});

// Check active subscription
const isActive = await client.customers.checkActiveSubscription("customer_123");
```

### Delete a Customer

```javascript theme={null}
const response = await client.customers.delete("customer_123");
```

### Archive / Unarchive a Customer

```javascript theme={null}
// Archive a customer (preserves their full history)
const response = await client.customers.archive("customer_123");
console.log(response.data.archived_at);

// Restore an archived customer
await client.customers.unarchive("customer_123");
```

### Bulk CSV Upload

```javascript theme={null}
// File input from your form
const csvFile = document.getElementById("csv-input").files[0];

const response = await client.customers.uploadCsv(csvFile);
console.log(`Processed ${response.data.total_customers} customers`);
console.log(`Successful: ${response.data.successful_upload_count}`);
```

***

## Usage Tracking & Access Control

### Check Feature Access

```javascript theme={null}
const access = await client.usages.checkAccess({
  featureKey: "premium_feature",
  customerKey: "customer_123",
});

if (access.can_access) {
  console.log(`Access granted. Balance: ${access.balance}`);
} else {
  console.log(`Quota exceeded. Used: ${access.used_quantity}/${access.quota}`);
}
```

### Record Usage Events

```javascript theme={null}
// Simple usage (amount = 1)
await client.usages.recordUsage({
  customerKey: "customer_123",
  eventName: "api_call",
});

// Custom amount for bulk operations
await client.usages.recordUsage({
  customerKey: "customer_123",
  eventName: "bulk_upload",
  amount: 50,
});

// Advanced usage with metadata
await client.usages.recordUsage({
  customerKey: "customer_123",
  eventName: "premium_feature_used",
  amount: 1,
  credit_used: 25,  // Optional: credits consumed
  event_id: "evt_abc123",  // Optional: unique identifier
  timestamp: Date.now(),  // Optional: custom timestamp
  metadata: {  // Optional: additional context
    feature_type: "advanced_analytics",
    session_id: "sess_xyz789"
  }
});
```

### List Usage Events

Retrieve usage events with optional filters and pagination:

```javascript theme={null}
const events = await client.usages.listEvents({
  customerKey: "customer_123",
  featureKey: "premium_feature",
  page: 1,
  perPage: 25,
});

events.data.forEach((event) => {
  console.log(`${event.feature_key}: qty=${event.quantity} at ${event.timestamp}`);
});

console.log(`Page ${events.meta.current_page} of ${events.meta.total_pages}`);
```

### Compute Quantity Price

Compute the price for a given quantity of a feature for a customer, based on their plan. Useful for previewing upgrade costs or showing customers the cost of additional usage before they commit.

```javascript theme={null}
const price = await client.usages.quantityPrice({
  customerKey: "customer_123",
  featureKey: "feature_interview_booking",
  quantity: 500,
});

console.log(`${price.data.price} ${price.data.unit}`);

// For tiered pricing, inspect the per-tier breakdown
price.data.applied_tiers.forEach((tier) => {
  console.log(
    `  Tier ${tier.first_unit}-${tier.last_unit}: ` +
    `${tier.units_consumed} units -> ${tier.tier_price}`
  );
});
```

<Note>
  Only available to tenants whose plan includes the finance API feature.
</Note>

### Complete Usage Example

```javascript theme={null}
async function useFeature(metrifoxClient, customerKey, featureKey, eventName) {
  try {
    // 1. Check if customer has access
    const access = await metrifoxClient.usages.checkAccess({
      featureKey,
      customerKey,
    });

    if (access.can_access) {
      // 2. Perform the actual feature logic
      const result = performFeatureLogic();

      // 3. Record usage after successful completion
      await metrifoxClient.usages.recordUsage({
        customerKey,
        eventName,
        amount: result.unitsUsed || 1,
        event_id: result.transactionId,
        metadata: {
          execution_time_ms: result.duration
        }
      });

      return { success: true, data: result };
    } else {
      return {
        success: false,
        error: "Quota exceeded",
        balance: access.balance,
      };
    }
  } catch (error) {
    return { success: false, error: error.message };
  }
}
```

***

## Checkout & Billing

### Embed Checkout Pages

```javascript theme={null}
// Embed checkout pages within your application
await client.checkout.embed({
  productKey: "your_product_key",
  container: "#checkout-container",  // CSS selector or DOM element
});
```

### Generate Checkout URL

```javascript theme={null}
// Basic checkout URL
const url = await client.checkout.url({
  offeringKey: "premium_plan"
});

// With billing interval
const url = await client.checkout.url({
  offeringKey: "premium_plan",
  billingInterval: "monthly"
});

// With customer key for pre-filled checkout
const url = await client.checkout.url({
  offeringKey: "premium_plan",
  billingInterval: "monthly",
  customerKey: "customer_123"
});
```

### Card Collection URL

Generate a hosted URL for collecting a payment method against an existing subscription or order. Useful for trial-to-paid conversions and re-collecting card details after expiry.

```javascript theme={null}
// For a subscription
const url = await client.checkout.cardCollectionUrl({
  subscriptionId: "sub_uuid_123",
});

// For an order
const url = await client.checkout.cardCollectionUrl({
  orderId: "order_uuid_456",
});
```

***

## Wallets & Credit Allocations

```javascript theme={null}
// List a customer's credit wallets
const wallets = await client.wallets.list("customer_123");
wallets.data.forEach((w) =>
  console.log(`${w.name}: ${w.balance} ${w.credit_unit_plural}`)
);

// List allocations for a wallet (optionally filter by status)
const allocations = await client.wallets.listCreditAllocations("wallet_uuid_123");
const active = await client.wallets.listCreditAllocations("wallet_uuid_123", {
  status: "active",
});

// Get a single allocation with its transaction history
const allocation = await client.wallets.getCreditAllocation("alloc_uuid_123");
allocation.data.transactions.forEach((t) =>
  console.log(`  ${t.amount} at ${t.created_at}`)
);
```

***

## Framework Integration

### React/Vite

**Setup in main.jsx:**

```javascript theme={null}
import { init } from "metrifox-js";

const metrifoxClient = init({
  apiKey: import.meta.env.VITE_METRIFOX_API_KEY,
});
window.metrifoxClient = metrifoxClient;
```

**Use in components:**

```javascript theme={null}
function FeatureButton({ customerKey }) {
  const handleClick = async () => {
    const client = window.metrifoxClient;
    const access = await client.usages.checkAccess({
      featureKey: "premium_feature",
      customerKey,
    });

    if (access.can_access) {
      await client.usages.recordUsage({
        customerKey,
        eventName: "button_clicked",
      });
    }
  };

  return <button onClick={handleClick}>Use Feature</button>;
}
```

### Next.js

**Setup in \_app.js:**

```javascript theme={null}
import { init } from "metrifox-js";

const metrifoxClient = init({
  apiKey: process.env.METRIFOX_API_KEY,
});

export { metrifoxClient };
```

### Express

```javascript theme={null}
import { init } from "metrifox-js";
import express from "express";

const app = express();
const metrifoxClient = init({
  apiKey: process.env.METRIFOX_API_KEY,
});

app.get("/api/premium/:customerId", async (req, res) => {
  const access = await metrifoxClient.usages.checkAccess({
    featureKey: "premium_api",
    customerKey: req.params.customerId,
  });

  if (!access.can_access) {
    return res.status(403).json({ error: "Access denied" });
  }

  await metrifoxClient.usages.recordUsage({
    customerKey: req.params.customerId,
    eventName: "premium_api_call",
  });

  res.json({ data: "premium content" });
});
```

***

## API Reference

### Client Architecture

```javascript theme={null}
const client = init(config);

// Available modules:
client.usages;        // Usage tracking and access control
client.customers;     // Customer management
client.checkout;      // Embedded checkout
client.subscriptions; // Subscription management
client.wallets;       // Credit wallets and allocations
```

### Functions

**Initialization:**

* `init(config?)` - Initialize and return the SDK client. `config` accepts `apiKey`, `baseUrl`, `webAppBaseUrl`, and `meterServiceBaseUrl`.

**Usage Module (`client.usages`):**

* `checkAccess(request)` - Check feature access for a customer
* `recordUsage(request)` - Record a usage event
* `listEvents(params?)` - List recorded usage events with optional filters and pagination
* `quantityPrice(request)` - Compute the price of a usage quantity (requires finance API feature)

**Customers Module (`client.customers`):**

* `create(request)` - Add a customer
* `update(customerKey, request)` - Update a customer
* `list(params?)` - Get a paginated list of customers
* `get(customerKey)` - Get a customer
* `delete(customerKey)` - Delete a customer
* `archive(customerKey)` - Archive a customer
* `unarchive(customerKey)` - Restore an archived customer
* `getDetails(customerKey)` - Get detailed customer information
* `uploadCsv(file)` - Upload a CSV list of customers
* `bulkCreate(request)` - Create multiple customers in one call
* `checkActiveSubscription(customerKey)` - Check for active subscription

**Checkout Module (`client.checkout`):**

* `embed(config)` - Embed checkout pages in your application
* `url(config)` - Generate a checkout URL
* `cardCollectionUrl(config)` - Generate a hosted card-collection URL

**Wallets Module (`client.wallets`):**

* `list(customerKey)` - List a customer's credit wallets
* `listCreditAllocations(walletId, options?)` - List credit allocations for a wallet (optionally filtered by status)
* `getCreditAllocation(allocationId)` - Get a single allocation with transaction history

***

## TypeScript Support

All TypeScript types are available for import:

```typescript theme={null}
import {
  AccessCheckRequest,
  UsageEventRequest,
  AccessResponse,
  CustomerCreateRequest,
  CustomerUpdateRequest,
  CustomerListRequest,
  APIResponse,
} from "metrifox-js";
```

***

## Error Handling

```javascript theme={null}
try {
  const access = await client.usages.checkAccess({ featureKey, customerKey });
} catch (error) {
  // Handle network errors, invalid API key, etc.
  console.error("Metrifox API error:", error.message);
}
```

***

## Configuration

### Environment Variables

**Node.js:**

```bash theme={null}
METRIFOX_API_KEY=your_api_key_here
```

**Vite:**

```bash theme={null}
VITE_METRIFOX_API_KEY=your_api_key_here
```

**Create React App:**

```bash theme={null}
REACT_APP_METRIFOX_API_KEY=your_api_key_here
```

### Custom URLs

```javascript theme={null}
const client = init({
  apiKey: "your_api_key",
  baseUrl: "https://custom-api.metrifox.com/api/v1/",
  webAppBaseUrl: "https://custom-app.metrifox.com",
  meterServiceBaseUrl: "https://custom-meter.metrifox.com/",
});
```

The meter service URL can also be overridden via the `METRIFOX_METER_SERVICE_BASE_URL` environment variable.

### Default URLs

* **Production API:** `https://api.metrifox.com/api/v1/`
* **Meter Service:** `https://api-meter.metrifox.com/`
* **Web App:** `https://app.metrifox.com`

***

## Support

* **Email:** [support@metrifox.com](mailto:support@metrifox.com)
* **Documentation:** [https://docs.metrifox.com](https://docs.metrifox.com)
* **GitHub:** [https://github.com/metrifox/metrifox-js](https://github.com/metrifox/metrifox-js)
* **Discord** [https://discord.gg/GGMHDDBdw](https://discord.gg/GGMHDDBdw)

<Note>
  The JavaScript SDK works seamlessly across all modern JavaScript environments including Node.js, React, Next.js, Vue, and more.
</Note>
