> ## 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.

# Sync with Your Database

> Automatically sync your Dodo Payments data to your own database for analytics, reporting, and integrations.

Sync your Dodo Payments data to your own database for analytics, reporting, and integrations. The sync engine automatically replicates **payments**, **customers**, **subscriptions**, and **licenses** to MongoDB, PostgreSQL, MySQL, or ClickHouse.

<Info>
  **Package**: [dodo-sync on npm](https://www.npmjs.com/package/dodo-sync) | **Source**: [GitHub](https://github.com/dodopayments/dodo-sync)
</Info>

## What Can You Sync?

Choose any combination of these entities:

<CardGroup cols={2}>
  <Card title="Payments" icon="credit-card">
    All payment transactions, including one-time payments, refunds, and status updates.
  </Card>

  <Card title="Customers" icon="users">
    Customer profiles, contact information, and metadata.
  </Card>

  <Card title="Subscriptions" icon="repeat">
    Subscription data, billing cycles, and status changes.
  </Card>

  <Card title="Licenses" icon="key">
    License keys, activations, and status updates.
  </Card>
</CardGroup>

Specify which entities to sync using the `scopes` parameter. Each run fetches every record in the selected scopes and writes it by ID, so existing rows are updated in place instead of duplicated. Each page of records is written to your database in a single batch.

## Database Support

Dodo Sync supports **MongoDB**, **PostgreSQL**, **MySQL** 8.0.20 or later, and **ClickHouse**. Support for Snowflake and other databases, ETL pipelines, and realtime sync is in development.

To contribute a new database integration, submit a pull request to the [GitHub repository](https://github.com/dodopayments/dodo-sync).

## Getting Started

Use Dodo Sync via the **CLI** for quick setup or programmatically in your code for integration into your application. Both methods provide the same functionality.

### Using the CLI

Install the CLI globally to run it from anywhere:

<CodeGroup>
  ```bash npm theme={null}
  npm install -g dodo-sync
  ```

  ```bash bun theme={null}
  bun add -g dodo-sync
  ```
</CodeGroup>

#### Running the CLI

The CLI supports two modes: **interactive** for guided setup, and **manual** for direct configuration.

**Interactive mode**: Run without arguments to start the setup wizard.

```bash theme={null}
dodo-sync
```

**Manual mode**: Pass arguments directly to skip the wizard.

```bash theme={null}
dodo-sync -i [interval] -d [database] -u [database_uri] --scopes [scopes] --api-key [api_key] --env [environment]
```

Examples:

```bash theme={null}
# MongoDB
dodo-sync -i 600 -d mongodb -u mongodb://mymongodb.url --scopes "licences,payments,customers,subscriptions" --api-key YOUR_API_KEY --env test_mode

# PostgreSQL
dodo-sync -i 600 -d postgres -u postgresql://user:password@localhost:5432/mydb --scopes "licences,payments,customers,subscriptions" --api-key YOUR_API_KEY --env test_mode

# MySQL
dodo-sync -i 600 -d mysql -u mysql://user:password@localhost:3306/mydb --scopes "licences,payments,customers,subscriptions" --api-key YOUR_API_KEY --env test_mode

# ClickHouse
dodo-sync -i 600 -d clickhouse -u http://localhost:8123 --scopes "licences,payments,customers,subscriptions" --api-key YOUR_API_KEY --env test_mode
```

#### CLI Arguments

<ParamField path="--interval" type="number" alias="-i" required>
  Sync interval in seconds. The CLI runs continuously at this interval. For a one-time sync, use [`.run()` in your code](#manual-sync).
</ParamField>

<ParamField path="--database" type="string" alias="-d" required>
  Database type: `"mongodb"`, `"postgres"`, `"mysql"`, or `"clickhouse"`.
</ParamField>

<ParamField path="--database-uri" type="string" alias="-u" required>
  Connection URI for your database:

  * **MongoDB**: `mongodb://localhost:27017` or `mongodb+srv://user:pass@cluster.mongodb.net/`
  * **PostgreSQL**: `postgresql://user:password@localhost:5432/mydb`
  * **MySQL**: `mysql://user:password@localhost:3306/mydb`
  * **ClickHouse**: `http://localhost:8123`
</ParamField>

<ParamField path="--scopes" type="string" required>
  Comma-separated list of entities to sync: `licences`, `payments`, `customers`, `subscriptions`. Example: `"payments,customers"`.
</ParamField>

<ParamField path="--api-key" type="string" required>
  Your Dodo Payments API key from **Developer → API Keys**. Use a key from the same mode as `--env`.
</ParamField>

<ParamField path="--env" type="string" required>
  Environment: `"live_mode"` or `"test_mode"`.
</ParamField>

<ParamField path="--rate-limit" type="number" alias="--rl">
  Rate limit in requests per second. Controls how fast the sync engine makes API requests. Defaults to `10`; values of `100` or more turn off throttling.
</ParamField>

### Using in Your Code

Integrate the sync feature directly into your application. Install it as a dependency:

<CodeGroup>
  ```bash npm theme={null}
  npm install dodo-sync
  ```

  ```bash bun theme={null}
  bun add dodo-sync
  ```
</CodeGroup>

#### Automatic Sync (Interval-based)

Run the sync continuously at regular intervals:

```typescript theme={null}
import { DodoSync } from 'dodo-sync';

const syncDodoPayments = new DodoSync({
  interval: 60, // Sync every 60 seconds
  database: 'mongodb',
  databaseURI: process.env.MONGODB_URI, // e.g., 'mongodb://localhost:27017'
  scopes: ['licences', 'payments', 'customers', 'subscriptions'],
  dodoPaymentsOptions: {
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'test_mode' // or 'live_mode'
  }
});

// Initialize connection
await syncDodoPayments.init();

// Start the sync loop
syncDodoPayments.start();
```

<Tip>
  The `interval` option is required when using `.start()`. The sync runs continuously at the specified interval until the process stops.
</Tip>

#### Manual Sync

Trigger sync operations on-demand, such as from a cron job, an API endpoint, or a serverless function:

```typescript expandable theme={null}
import { DodoSync } from 'dodo-sync';

const syncDodoPayments = new DodoSync({
  database: 'mongodb',
  databaseURI: process.env.MONGODB_URI,
  scopes: ['licences', 'payments', 'customers', 'subscriptions'],
  dodoPaymentsOptions: {
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'test_mode'
  }
});

try {
  // Initialize connection
  await syncDodoPayments.init();

  // Trigger a single sync operation
  await syncDodoPayments.run();
} finally {
  // Close the database connection
  await syncDodoPayments.disconnect();
}
```

<Tip>
  The `interval` option is not required for manual sync. Call `.run()` whenever you need to sync. `.run()` resolves only after every database write has finished. `.close()` is an alias for `.disconnect()`.
</Tip>

#### Running on Serverless

On Vercel, AWS Lambda, or similar platforms:

* Call `.disconnect()` in a `finally` block, as in the example above, so connections don't stay open between invocations.
* Use the Node.js runtime. Edge runtimes can't open database connections.
* Raise the function timeout. A large sync can take longer than the default limit. On Vercel, set `export const maxDuration = 60;`.
* Sync fewer scopes per invocation, such as `scopes: ['payments']`, to keep each run short.

#### PostgreSQL Example

```typescript theme={null}
import { DodoSync } from 'dodo-sync';

const syncDodoPayments = new DodoSync({
  interval: 60,
  database: 'postgres',
  databaseURI: process.env.POSTGRES_URI, // e.g., 'postgresql://user:password@localhost:5432/mydb'
  scopes: ['licences', 'payments', 'customers', 'subscriptions'],
  dodoPaymentsOptions: {
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'test_mode'
  }
});

await syncDodoPayments.init();
syncDodoPayments.start();
```

#### MySQL Example

```typescript theme={null}
import { DodoSync } from 'dodo-sync';

const syncDodoPayments = new DodoSync({
  interval: 60,
  database: 'mysql',
  databaseURI: process.env.MYSQL_URI, // e.g., 'mysql://user:password@localhost:3306/mydb'
  scopes: ['licences', 'payments', 'customers', 'subscriptions'],
  dodoPaymentsOptions: {
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'test_mode'
  }
});

await syncDodoPayments.init();
syncDodoPayments.start();
```

#### ClickHouse Example

```typescript theme={null}
import { DodoSync } from 'dodo-sync';

const syncDodoPayments = new DodoSync({
  interval: 60,
  database: 'clickhouse',
  databaseURI: process.env.CLICKHOUSE_URI, // e.g., 'http://localhost:8123'
  scopes: ['licences', 'payments', 'customers', 'subscriptions'],
  dodoPaymentsOptions: {
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'test_mode'
  }
});

await syncDodoPayments.init();
syncDodoPayments.start();
```

#### Constructor Options

<ParamField body="database" type="string" required>
  Database type: `"mongodb"`, `"postgres"`, `"mysql"`, or `"clickhouse"`.
</ParamField>

<ParamField body="databaseURI" type="string" required>
  Connection string for your database:

  * **MongoDB**: `mongodb://localhost:27017` or `mongodb+srv://...`
  * **PostgreSQL**: `postgresql://user:password@localhost:5432/mydb`
  * **MySQL**: `mysql://user:password@localhost:3306/mydb`
  * **ClickHouse**: `http://localhost:8123`
</ParamField>

<ParamField body="scopes" type="string[]" required>
  Array of entities to sync: `"licences"`, `"payments"`, `"customers"`, `"subscriptions"`. Include any combination.
</ParamField>

<ParamField body="dodoPaymentsOptions" type="object" required>
  Dodo Payments API configuration. See the [TypeScript SDK types](https://github.com/dodopayments/dodopayments-typescript/blob/main/src/client.ts) for complete options.

  **Required properties:**

  * `bearerToken`: Your Dodo Payments API key
  * `environment`: `"test_mode"` or `"live_mode"`
</ParamField>

<ParamField body="interval" type="number">
  Time in seconds between automatic syncs. Required for `.start()`, optional for `.run()`.
</ParamField>

<ParamField body="rateLimit" type="number">
  Rate limit in requests per second. Defaults to `10`; values of `100` or more turn off throttling.
</ParamField>

## Important Information

<Warning>
  **MongoDB**: Collections (`subscriptions`, `payments`, `licences`, `customers`) are created in the database named in your connection URI, such as `mongodb://localhost:27017/my_database`. If the URI names no database, Dodo Sync uses `dodopayments_sync`.

  **PostgreSQL**: Tables (`Subscriptions`, `Payments`, `Licenses`, `Customers`) are created in the database specified in your connection URI. Data is stored as JSONB.

  **MySQL**: Requires MySQL 8.0.20 or later. Tables (`Subscriptions`, `Payments`, `Licenses`, `Customers`) are created in the database specified in your connection URI. Data is stored as JSON.

  **ClickHouse**: Tables (`Subscriptions`, `Payments`, `Licenses`, `Customers`) are created using the ReplacingMergeTree engine. When querying, use the `FINAL` keyword to ensure deduplicated results.
</Warning>

## Upgrading from 0.x

Version 1.0 changes how MongoDB data is stored and raises the MySQL requirement. Before upgrading:

* **MongoDB**: Drop your existing `licences` collection. License documents are now stored by license `id` instead of `subscription_id`, and the next sync repopulates the collection.
* **MongoDB**: Check your connection URI. Data is now written to the database the URI names, not always `dodopayments_sync`. To keep using your existing data, put `dodopayments_sync` in the URI or leave the database out.
* **MySQL**: Upgrade to MySQL 8.0.20 or later.

## Additional Resources

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/dodopayments/dodo-sync">
    View source code, report issues, or contribute improvements
  </Card>

  <Card title="npm Package" icon="box-open" href="https://www.npmjs.com/package/dodo-sync">
    View package details and installation instructions
  </Card>
</CardGroup>


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