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

# Autumn Billing

> OpenTelemetry instrumentation for Autumn billing operations

## Overview

`@kubiks/otel-autumn` provides comprehensive OpenTelemetry instrumentation for the [Autumn](https://useautumn.com) billing SDK. Capture spans for every billing operation including feature checks, usage tracking, checkout flows, product attachments, and cancellations with detailed metadata.

<Frame>
  <img src="https://mintcdn.com/kubiks-fb8cce26/aWqkpsvTx2hc17v8/images/otel/otel-autumn-trace.png?fit=max&auto=format&n=aWqkpsvTx2hc17v8&q=85&s=d6a024f7a050df2a509d4d00ea3d81e3" alt="Autumn Trace Visualization" width="3379" height="2386" data-path="images/otel/otel-autumn-trace.png" />
</Frame>

<Note>
  Visualize your billing operations with detailed span information including operation type, customer IDs, feature IDs, and billing metadata.
</Note>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @kubiks/otel-autumn
  ```

  ```bash pnpm theme={null}
  pnpm add @kubiks/otel-autumn
  ```

  ```bash yarn theme={null}
  yarn add @kubiks/otel-autumn
  ```
</CodeGroup>

<Warning>
  **Peer Dependencies:** `@opentelemetry/api` >= 1.9.0, `autumn-js` >= 0.1.0
</Warning>

## Quick Start

```typescript theme={null}
import { Autumn } from "autumn-js";
import { instrumentAutumn } from "@kubiks/otel-autumn";

const autumn = instrumentAutumn(
  new Autumn({
    secretKey: process.env.AUTUMN_SECRET_KEY!,
  }),
);

// All operations are now automatically traced
const checkResult = await autumn.check({
  customer_id: "user_123",
  feature_id: "messages",
});

await autumn.track({
  customer_id: "user_123",
  feature_id: "messages",
  value: 1,
});
```

<Tip>
  `instrumentAutumn` wraps your Autumn client instance—no configuration changes needed. Every SDK call creates a client span with detailed billing attributes.
</Tip>

## Traced Operations

This instrumentation wraps the core Autumn billing methods:

<CardGroup cols={2}>
  <Card title="check" icon="circle-check">
    Feature access and product status checks
  </Card>

  <Card title="track" icon="chart-line">
    Usage event tracking
  </Card>

  <Card title="checkout" icon="cart-shopping">
    Checkout session creation
  </Card>

  <Card title="attach" icon="link">
    Product attachment to customers
  </Card>

  <Card title="cancel" icon="xmark">
    Product cancellation
  </Card>
</CardGroup>

Each operation creates a dedicated span with operation-specific attributes.

## Span Attributes

### Common Attributes (All Operations)

| Attribute            | Description               | Example                |
| -------------------- | ------------------------- | ---------------------- |
| `billing.system`     | Constant value `autumn`   | `autumn`               |
| `billing.operation`  | Operation type            | `check`, `track`       |
| `autumn.resource`    | Resource being accessed   | `features`, `products` |
| `autumn.target`      | Full operation target     | `features.check`       |
| `autumn.customer_id` | Customer ID               | `user_123`             |
| `autumn.entity_id`   | Entity ID (if applicable) | `org_456`              |

### Check Operation

<AccordionGroup>
  <Accordion title="Feature Access Attributes">
    | Attribute                 | Description                    | Example    |
    | ------------------------- | ------------------------------ | ---------- |
    | `autumn.feature_id`       | Feature being checked          | `messages` |
    | `autumn.allowed`          | Whether access is allowed      | `true`     |
    | `autumn.balance`          | Current balance/remaining uses | `42`       |
    | `autumn.usage`            | Current usage                  | `8`        |
    | `autumn.unlimited`        | Whether usage is unlimited     | `false`    |
    | `autumn.required_balance` | Required balance for operation | `1`        |
  </Accordion>

  <Accordion title="Product Status Attributes">
    | Attribute               | Description            | Example |
    | ----------------------- | ---------------------- | ------- |
    | `autumn.product_id`     | Product being checked  | `pro`   |
    | `autumn.included_usage` | Included usage in plan | `50`    |
  </Accordion>
</AccordionGroup>

### Track Operation

| Attribute                | Description               | Example        |
| ------------------------ | ------------------------- | -------------- |
| `autumn.feature_id`      | Feature being tracked     | `messages`     |
| `autumn.event_name`      | Custom event name         | `message_sent` |
| `autumn.value`           | Usage value tracked       | `1`            |
| `autumn.event_id`        | Generated event ID        | `evt_123`      |
| `autumn.idempotency_key` | Idempotency key for dedup | `msg_456`      |

### Checkout Operation

| Attribute               | Description                         | Example                           |
| ----------------------- | ----------------------------------- | --------------------------------- |
| `autumn.product_id`     | Product being purchased             | `pro`                             |
| `autumn.product_ids`    | Multiple products (comma-separated) | `pro, addon_analytics`            |
| `autumn.checkout_url`   | Stripe checkout URL                 | `https://checkout.stripe.com/...` |
| `autumn.has_prorations` | Whether prorations apply            | `true`                            |
| `autumn.total_amount`   | Total checkout amount               | `2000` (cents)                    |
| `autumn.currency`       | Currency code                       | `usd`                             |
| `autumn.force_checkout` | Whether to force Stripe checkout    | `false`                           |
| `autumn.invoice`        | Whether to create invoice           | `true`                            |

### Attach Operation

| Attribute             | Description                    | Example                           |
| --------------------- | ------------------------------ | --------------------------------- |
| `autumn.product_id`   | Product being attached         | `pro`                             |
| `autumn.success`      | Whether attachment succeeded   | `true`                            |
| `autumn.checkout_url` | Checkout URL if payment needed | `https://checkout.stripe.com/...` |

### Cancel Operation

| Attribute           | Description                    | Example |
| ------------------- | ------------------------------ | ------- |
| `autumn.product_id` | Product being cancelled        | `pro`   |
| `autumn.success`    | Whether cancellation succeeded | `true`  |

## Configuration

You can optionally configure the instrumentation:

```typescript theme={null}
import { instrumentAutumn } from "@kubiks/otel-autumn";

const autumn = instrumentAutumn(client, {
  // Capture customer data in spans (default: false)
  captureCustomerData: true,

  // Capture product options/configuration (default: false)
  captureOptions: true,
});
```

<Info>
  By default, sensitive customer data is not captured. Enable `captureCustomerData` only if your observability platform is secure and compliant.
</Info>

## Usage Examples

### Feature Access Control

<CodeGroup>
  ```typescript Feature Check theme={null}
  const autumn = instrumentAutumn(
    new Autumn({ secretKey: process.env.AUTUMN_SECRET_KEY! }),
  );

  // Check if user can access a feature
  const result = await autumn.check({
    customer_id: "user_123",
    feature_id: "messages",
    required_balance: 1,
  });

  if (result.data?.allowed) {
    // User has access
    console.log(`Remaining: ${result.data.balance}`);
  }
  ```

  ```typescript Product Check theme={null}
  // Check product status
  const result = await autumn.check({
    customer_id: "user_123",
    product_id: "pro",
  });

  if (result.data?.allowed) {
    console.log("User has Pro subscription");
  }
  ```
</CodeGroup>

### Usage Tracking

<CodeGroup>
  ```typescript Simple Tracking theme={null}
  // Track feature usage
  await autumn.track({
    customer_id: "user_123",
    feature_id: "messages",
    value: 1,
  });
  ```

  ```typescript With Idempotency theme={null}
  // Track with idempotency key to prevent double-counting
  await autumn.track({
    customer_id: "user_123",
    feature_id: "messages",
    value: 1,
    idempotency_key: `msg_${messageId}`,
  });
  ```

  ```typescript Custom Event theme={null}
  // Track custom event
  await autumn.track({
    customer_id: "user_123",
    event_name: "video_upload",
    value: 1,
  });
  ```
</CodeGroup>

### Checkout Flow

<CodeGroup>
  ```typescript Single Product theme={null}
  // Create a checkout session for a product
  const result = await autumn.checkout({
    customer_id: "user_123",
    product_id: "pro",
    force_checkout: false, // Use billing portal if payment method exists
  });

  if (result.data?.url) {
    // Redirect to Stripe checkout
    console.log(`Checkout URL: ${result.data.url}`);
  }
  ```

  ```typescript Multiple Products theme={null}
  // Checkout with multiple products
  const result = await autumn.checkout({
    customer_id: "user_123",
    product_ids: ["pro", "addon_analytics"],
  });
  ```

  ```typescript Force Checkout theme={null}
  // Always use Stripe checkout (even if payment method exists)
  const result = await autumn.checkout({
    customer_id: "user_123",
    product_id: "enterprise",
    force_checkout: true,
  });
  ```
</CodeGroup>

### Product Management

<CodeGroup>
  ```typescript Attach Product theme={null}
  // Attach a free product
  const attachResult = await autumn.attach({
    customer_id: "user_123",
    product_id: "free",
  });

  if (attachResult.data?.success) {
    console.log("Product attached successfully");
  }
  ```

  ```typescript Cancel Product theme={null}
  // Cancel a subscription
  const cancelResult = await autumn.cancel({
    customer_id: "user_123",
    product_id: "pro",
  });

  if (cancelResult.data?.success) {
    console.log("Subscription cancelled");
  }
  ```
</CodeGroup>

## Complete Integration Example

Here's a complete example integrating Autumn with a Next.js application:

```typescript lib/autumn.ts theme={null}
import { Autumn } from "autumn-js";
import { instrumentAutumn } from "@kubiks/otel-autumn";

export const autumn = instrumentAutumn(
  new Autumn({
    secretKey: process.env.AUTUMN_SECRET_KEY!,
  }),
  {
    captureCustomerData: true,
    captureOptions: true,
  }
);
```

```typescript app/api/features/check/route.ts theme={null}
import { autumn } from "@/lib/autumn";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const { customerId, featureId } = await request.json();

  const result = await autumn.check({
    customer_id: customerId,
    feature_id: featureId,
    required_balance: 1,
  });

  return NextResponse.json(result.data);
}
```

```typescript app/api/usage/track/route.ts theme={null}
import { autumn } from "@/lib/autumn";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const { customerId, featureId, value, idempotencyKey } = await request.json();

  await autumn.track({
    customer_id: customerId,
    feature_id: featureId,
    value,
    idempotency_key: idempotencyKey,
  });

  return NextResponse.json({ success: true });
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use Idempotency Keys">
    Always use idempotency keys when tracking usage to prevent double-counting:

    ```typescript theme={null}
    await autumn.track({
      customer_id: "user_123",
      feature_id: "messages",
      value: 1,
      idempotency_key: `msg_${messageId}`,
    });
    ```
  </Accordion>

  <Accordion title="Check Before Usage">
    Check feature access before performing operations:

    ```typescript theme={null}
    const check = await autumn.check({
      customer_id: "user_123",
      feature_id: "messages",
      required_balance: 1,
    });

    if (!check.data?.allowed) {
      throw new Error("Insufficient balance");
    }

    // Proceed with operation
    await sendMessage();

    // Track usage
    await autumn.track({
      customer_id: "user_123",
      feature_id: "messages",
      value: 1,
    });
    ```
  </Accordion>

  <Accordion title="Handle Checkout Redirects">
    Handle both checkout URLs and direct product attachments:

    ```typescript theme={null}
    const result = await autumn.checkout({
      customer_id: "user_123",
      product_id: "pro",
    });

    if (result.data?.url) {
      // Redirect to Stripe checkout
      return redirect(result.data.url);
    } else {
      // Product attached directly (e.g., free plan)
      return redirect("/dashboard");
    }
    ```
  </Accordion>

  <Accordion title="Configure Data Capture Carefully">
    Only enable additional data capture in secure environments:

    ```typescript theme={null}
    const autumn = instrumentAutumn(client, {
      captureCustomerData: process.env.NODE_ENV === "development",
      captureOptions: true,
    });
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Spans Not Appearing">
    Make sure OpenTelemetry is properly configured in your application:

    ```typescript theme={null}
    import { NodeSDK } from "@opentelemetry/sdk-node";
    import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";

    const sdk = new NodeSDK({
      instrumentations: [getNodeAutoInstrumentations()],
    });

    sdk.start();
    ```
  </Accordion>

  <Accordion title="Missing Attributes">
    Ensure you're using the latest version of the package:

    ```bash theme={null}
    npm update @kubiks/otel-autumn
    ```
  </Accordion>

  <Accordion title="Performance Impact">
    The instrumentation adds minimal overhead. If you experience issues:

    * Verify your OpenTelemetry exporter is configured correctly
    * Check if you're using sampling to reduce data volume
    * Consider using batch span processors
  </Accordion>
</AccordionGroup>

## Resources

<CardGroup cols={2}>
  <Card title="Autumn Documentation" icon="book" href="https://useautumn.com/docs">
    Learn more about Autumn billing
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/kubiks-inc/otel/tree/main/packages/otel-autumn">
    View source code and examples
  </Card>

  <Card title="npm Package" icon="box" href="https://www.npmjs.com/package/@kubiks/otel-autumn">
    View package on npm
  </Card>

  <Card title="Report Issues" icon="circle-exclamation" href="https://github.com/kubiks-inc/otel/issues">
    Found a bug? Let us know!
  </Card>
</CardGroup>

## License

MIT
