stripe-sync-backfill

Stripe Sync Engine Backfill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stripe-sync-backfill" with this command: npx skills add ashutoshpw/stripe-sync-engine/ashutoshpw-stripe-sync-engine-stripe-sync-backfill

Stripe Sync Engine Backfill

You are an expert in backfilling historical Stripe data using stripe-sync-engine. Your goal is to help users import their existing Stripe data into PostgreSQL.

Initial Assessment

Before proceeding, verify:

  • Is stripe-sync-engine set up? (see setup skill)

  • Are migrations completed? (see migrations skill)

  • How much historical data do you need? (all time, last year, last 30 days?)

  • How large is your Stripe account? (affects backfill strategy)

Basic Backfill

Method 1: Backfill Script (Recommended)

Create scripts/backfill-stripe.ts :

import { StripeSync } from "stripe-sync-engine";

const stripeSync = new StripeSync({ poolConfig: { connectionString: process.env.DATABASE_URL!, max: 10, }, stripeSecretKey: process.env.STRIPE_SECRET_KEY!, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, schema: "stripe", autoExpandLists: true, backfillRelatedEntities: true, });

async function main() { const startDateArg = process.argv[2];

if (!startDateArg) { console.error("Usage: npm run stripe:backfill <start-date-unix-timestamp>"); console.error("Example: npm run stripe:backfill 1704067200"); process.exit(1); }

const timestamp = parseInt(startDateArg, 10); console.log(Backfilling Stripe data from ${new Date(timestamp * 1000).toISOString()}...);

await stripeSync.syncBackfill({ object: "all", created: { gte: timestamp }, });

console.log("Backfill completed successfully"); }

main().catch((error) => { console.error("Backfill failed:", error); process.exit(1); });

Add to package.json :

{ "scripts": { "stripe:backfill": "tsx scripts/backfill-stripe.ts" } }

Run:

Backfill from January 1, 2024 (Unix timestamp)

npm run stripe:backfill 1704067200

Get Unix timestamp for a date (macOS/Linux)

date -d "2024-01-01" +%s

Method 2: API Endpoint

Create app/api/sync/backfill/route.ts :

import { NextResponse } from "next/server"; import { stripeSync } from "@/lib/stripeSync";

export async function POST(request: Request) { const { object = "all", startDate } = await request.json();

try { const result = await stripeSync.syncBackfill({ object, created: startDate ? { gte: startDate } : undefined, });

return NextResponse.json({ status: "completed", result });

} catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return NextResponse.json({ error: message }, { status: 500 }); } }

Backfill Options

Object Types

The object parameter accepts:

Value Description

all

All supported object types

customer

Customer records

product

Product catalog

price

Price objects

plan

Legacy plan objects

subscription

Subscription records

invoice

Invoice records

charge

Charge records

payment_intent

Payment intents

payment_method

Payment methods

setup_intent

Setup intents

dispute

Dispute records

Date Filters

The created parameter supports Stripe's RangeQueryParam:

// All objects created after a date created: { gte: 1704067200 }

// Objects created before a date created: { lte: 1735689599 }

// Objects in a date range created: { gte: 1704067200, lte: 1735689599 }

// Exclusive comparisons created: { gt: 1704067200 } // strictly after created: { lt: 1735689599 } // strictly before

Backfilling Large Accounts (10,000+ Objects)

For large Stripe accounts, backfill in smaller chunks to avoid timeouts:

Day-by-Day Backfill

import { StripeSync } from "stripe-sync-engine";

const stripeSync = new StripeSync({ poolConfig: { connectionString: process.env.DATABASE_URL! }, stripeSecretKey: process.env.STRIPE_SECRET_KEY!, stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, });

async function backfillByDay(startDate: Date, endDate: Date) { const currentDate = new Date(startDate);

while (currentDate <= endDate) { const dayStart = Math.floor(currentDate.getTime() / 1000); const dayEnd = dayStart + 86400 - 1; // End of day

console.log(`Syncing ${currentDate.toISOString().split('T')[0]}...`);

await stripeSync.syncBackfill({
  object: "all",
  created: { gte: dayStart, lte: dayEnd },
});

console.log(`Completed ${currentDate.toISOString().split('T')[0]}`);

currentDate.setDate(currentDate.getDate() + 1);

} }

// Backfill all of 2024 backfillByDay(new Date("2024-01-01"), new Date("2024-12-31"));

Object-by-Object Backfill

const objects = [ "product", "price", "customer", "subscription", "invoice", "payment_intent", "charge", ];

for (const object of objects) { console.log(Backfilling ${object}s...); await stripeSync.syncBackfill({ object, created: { gte: 1704067200 }, }); console.log(Completed ${object}s); }

Syncing Single Entities

To sync or refresh a single Stripe object:

// Sync by Stripe ID (type is auto-detected from prefix) await stripeSync.syncSingleEntity("cus_1234567890"); await stripeSync.syncSingleEntity("prod_1234567890"); await stripeSync.syncSingleEntity("sub_1234567890"); await stripeSync.syncSingleEntity("in_1234567890"); await stripeSync.syncSingleEntity("pi_1234567890");

API Endpoint for Single Entity Sync

Create app/api/sync/entity/[id]/route.ts :

import { NextResponse } from "next/server"; import { stripeSync } from "@/lib/stripeSync";

export async function POST( request: Request, { params }: { params: { id: string } } ) { try { await stripeSync.syncSingleEntity(params.id); return NextResponse.json({ status: "synced", id: params.id }); } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; return NextResponse.json({ error: message }, { status: 500 }); } }

Revalidation on Sync

For critical objects, always fetch fresh data from Stripe API instead of trusting webhook payloads:

const stripeSync = new StripeSync({ // ... other config revalidateObjectsViaStripeApi: [ "customer", "subscription", "invoice", "payment_intent", ], });

Verifying Backfill Results

After backfill completes, verify data in your database:

-- Count synced objects SELECT 'customers' as type, COUNT() as count FROM stripe.customers UNION ALL SELECT 'products', COUNT() FROM stripe.products UNION ALL SELECT 'subscriptions', COUNT() FROM stripe.subscriptions UNION ALL SELECT 'invoices', COUNT() FROM stripe.invoices;

-- Check date range of synced data SELECT MIN(to_timestamp(created)) as earliest, MAX(to_timestamp(created)) as latest FROM stripe.customers;

Troubleshooting

Timeout Errors

  • Backfill in smaller date ranges (daily or weekly)

  • Backfill specific object types separately

  • Increase function timeout if using serverless

Rate Limits

  • stripe-sync-engine respects Stripe rate limits automatically

  • For very large backfills, run during off-peak hours

Missing Related Data

  • Enable backfillRelatedEntities: true in configuration

  • This ensures foreign key relationships are maintained

Related Skills

  • setup: Install and configure stripe-sync-engine

  • migrations: Create database schema before backfill

  • query: Query the backfilled data

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

stripe-sync-webhook

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-setup

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-migrations

No summary provided by upstream source.

Repository SourceNeeds Review
General

stripe-sync-minimal

No summary provided by upstream source.

Repository SourceNeeds Review