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

# Object Storage Blueprint

> Track the bytes customers upload to S3, Google Cloud Storage, Azure Blob Storage, or other object storage, and bill them by upload volume.

The Object Storage Blueprint sends a usage event to Dodo Payments each time a customer uploads a file, with the number of bytes uploaded. A **Sum** meter over `bytes` adds up each customer's upload volume, so you can bill for it. The blueprint ships in the `@dodopayments/ingestion-blueprints` npm package as `trackObjectStorage()`, and it works with S3, Google Cloud Storage, Azure Blob Storage, and other object storage services.

## Use Cases

The Object Storage Blueprint fits these scenarios:

<CardGroup cols={2}>
  <Card title="File Hosting" icon="folder">
    Bill customers for the total volume of files they upload.
  </Card>

  <Card title="Backup Services" icon="shield">
    Track backup data uploads and charge for the amount of data uploaded.
  </Card>

  <Card title="Media CDN" icon="photo-film">
    Monitor media uploads and bill for upload volume. To bill for delivery bandwidth, use the [Stream Blueprint](/developer-resources/ingestion-blueprints/stream).
  </Card>

  <Card title="Document Management" icon="file">
    Track document uploads per customer for usage-based pricing.
  </Card>
</CardGroup>

<Info>
  Use it to bill by upload volume for file hosting, media CDN, and backup services. The blueprint counts bytes uploaded, not bytes stored over time.
</Info>

## Quick Start

To track uploads, install the package, create a meter, and send an event after each successful upload.

<Steps>
  <Step title="Install the SDK">
    Install the Dodo Payments Ingestion Blueprints package:

    ```bash theme={null}
    npm install @dodopayments/ingestion-blueprints
    ```
  </Step>

  <Step title="Get Your API Keys">
    You need two sets of credentials:

    * **Dodo Payments API key**: Create one under **Developer → API Keys** in the [Dodo Payments dashboard](https://app.dodopayments.com/developer/api-keys), and store it in `DODO_PAYMENTS_API_KEY`. Use a test mode key while you build. A test mode key works only with `test_mode`.
    * **Storage provider credentials**: The credentials your storage SDK uses, for AWS S3, Google Cloud Storage, Azure Blob Storage, or another provider.
  </Step>

  <Step title="Create a Meter">
    In the [Dodo Payments dashboard](https://app.dodopayments.com/), go to **Products → Meters** and click **Create Meter**. Set these fields:

    * **Meter Name**: a descriptive name, such as `Storage Uploads`.
    * **Event Name**: `object_storage_upload`, or a name you choose. It must match `eventName` in your code exactly (case-sensitive).
    * **Aggregation Type**: **Sum**, to add up the bytes uploaded.
    * **Over Property**: `bytes`, to bill by upload size.
    * **Measurement Unit**: the unit shown on invoices, such as `bytes`.
  </Step>

  <Step title="Track Storage Usage">
    Send the event after the storage call succeeds. In these examples, a failed upload throws before `trackObjectStorage()` runs, so it isn't billed.

    <CodeGroup>
      ```javascript AWS S3 Upload theme={null}
      import { Ingestion, trackObjectStorage } from '@dodopayments/ingestion-blueprints';
      import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
      import fs from 'fs';

      const ingestion = new Ingestion({
        apiKey: process.env.DODO_PAYMENTS_API_KEY,
        environment: 'test_mode',
        eventName: 'object_storage_upload'
      });

      const s3 = new S3Client({ region: 'us-east-1' });

      // Read the file (example: from disk or request)
      const fileBuffer = fs.readFileSync('./document.pdf');

      // Upload to S3
      const command = new PutObjectCommand({
        Bucket: 'my-bucket',
        Key: 'uploads/document.pdf',
        Body: fileBuffer
      });

      await s3.send(command);

      // Track the upload
      await trackObjectStorage(ingestion, {
        customerId: 'cus_123',
        bytes: fileBuffer.length
      });
      ```

      ```javascript Google Cloud Storage theme={null}
      import { Ingestion, trackObjectStorage } from '@dodopayments/ingestion-blueprints';
      import { Storage } from '@google-cloud/storage';
      import fs from 'fs';

      const ingestion = new Ingestion({
        apiKey: process.env.DODO_PAYMENTS_API_KEY,
        environment: 'test_mode',
        eventName: 'object_storage_upload'
      });

      const storage = new Storage();
      const bucket = storage.bucket('my-bucket');

      // Read the file
      const fileBuffer = fs.readFileSync('./image.png');

      // Upload to GCS
      await bucket.file('uploads/image.png').save(fileBuffer);

      // Track the upload
      await trackObjectStorage(ingestion, {
        customerId: 'cus_456',
        bytes: fileBuffer.length,
        metadata: {
          bucket: 'my-bucket',
          key: 'uploads/image.png'
        }
      });
      ```
    </CodeGroup>
  </Step>
</Steps>

## Configuration

### Ingestion Configuration

Pass these options to `new Ingestion()`:

<ParamField path="apiKey" type="string" required>
  Your Dodo Payments API key from the dashboard.
</ParamField>

<ParamField path="environment" type="string">
  Environment mode: `test_mode` or `live_mode`. Defaults to `test_mode`. The Dodo Payments SDKs default to `live_mode` instead, so set `live_mode` explicitly in production.
</ParamField>

<ParamField path="eventName" type="string" required>
  Event name that matches your meter's **Event Name** (case-sensitive).
</ParamField>

### Track Object Storage Options

Pass these options to `trackObjectStorage()`:

<ParamField path="customerId" type="string" required>
  The Dodo Payments customer ID to bill for the upload, for example `cus_123`.
</ParamField>

<ParamField path="bytes" type="number">
  Number of bytes uploaded. Required for byte-based billing. If you omit it, the event has no `bytes` value, but it still counts toward a **Count** meter.
</ParamField>

<ParamField path="metadata" type="object">
  Optional metadata about the upload, such as bucket name or content type. Each value must be a string, number, or boolean.
</ParamField>

## Best Practices

<Tip>
  **Track Before or After Upload**: You can track the event before or after the actual upload, depending on your error handling strategy.
</Tip>

The API has no endpoint to delete an ingested event. An event sent before an upload that then fails stays in the customer's usage.

<Warning>
  **Handle Upload Failures**: Only track successful uploads, so you don't bill for failed operations.
</Warning>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.