Alt description missing in image
Beta: Plugins coming soon!
@payments/driverresolverssyncPaymentData
Alt description missing in image

syncPaymentData()

import { syncPaymentData } from '@payments/driver'

Synchronizes payment provider data into your DB entitlements: Customer, Subscriptions, and Purchases. This universal function delegates to all installed payment driver implementations to keep entitlements in sync across providers.

When calling the driver version, it actually executes syncPaymentData() methods on every installed payment driver implementation. This is why we pass the user (to resolve all customer IDs across providers) instead of a provider-specific customerId.

const { customers, subscriptions, purchases } = await syncPaymentData({ user })

This ensures that if a user has customers in multiple providers (e.g. Stripe for web, RevenueCat for mobile), all their entitlements stay in sync.

Implementation details

The @payments/driver entrypoint calls syncPaymentData() on all installed payment drivers:

packages/@payments-driver/index.ts
/** --- syncCustomerData() ------------------------ */
/** -i- Populates user related Customer, Subscriptions and Purchases records */
export const syncCustomerData = createResolver(async ({ args, parseArgs, withDefaults }) => {
 
    // Args
    const { userId } = parseArgs(args)
 
    // Retrieve all related customers for this user
    const customers = await Customers.find({ userId })
 
    // For each customer / provider, call the relevant syncPaymentData() driver method
    const paymentDriversData = await Promise.all(customers.map(async (customer) => {
        const paymentDriver = paymentsDrivers[customer.provider]
        return paymentDriver.syncPaymentData({ customerId: customer.customerId })
    }))
 
    // Combine and return all payment provider sync results
    return withDefaults({ ... })
 
}, syncCustomerDataBridge)

Where syncCustomerData is a resolver that:

  • Resolves all customer IDs for the given user across all payment providers
  • Calls each provider’s syncPaymentData() implementation with the appropriate customerId
  • Each implementation fetches current state from its payment provider
  • Each implementation upserts normalized Customer, Subscriptions, and Purchases records to your DB

Provider-specific implementations (like Stripe’s) will handle:

  • Fetching provider state (customers, subscriptions, payment intents, checkouts, charges, invoices, etc.)
  • Normalizing provider data to the universal Customer, Subscriptions, and Purchases schemas
  • Upserting records to your database

SyncPaymentDataInput

The underlying driver implementations will follow the driver signature SyncPaymentDataInput schema:

import { SyncPaymentDataInput } from '@payments/driver/driver.signature'
export const SyncPaymentDataInput = schema('SyncPaymentDataInput', {
    customerId: Customer.shape.customerId,
    user: User.nullish(),
})

Note: When calling through @payments/driver, you typically pass { user } to sync across all providers. When calling a provider-specific implementation directly (e.g. syncStripeData), you pass { customerId }.

SyncPaymentDataOutput

The underlying driver implementations will follow the driver signature SyncPaymentDataOutput schema:

import { SyncPaymentDataOutput } from '@payments/driver/driver.signature'
export const SyncPaymentDataOutput = schema('SyncPaymentDataOutput', {
    provider: PaymentProvidable.shape.provider,
    user: User.nullish(),
    customer: Customer.nullish(),
    subscriptions: Subscription.array().nullish(),
    purchases: Purchase.array().nullish(),
})

When to use

💡

Call syncPaymentData() on: webhooks (subscription changes, refunds, successful charges, invoice finalization), and after checkout/portal returns to keep entitlements consistent.

Most payment driver implementations (like Stripe) set up webhook handlers that call syncPaymentData() automatically on relevant payment events.

Custom post portal / checkout redirect URLs where syncPaymentData() is called manually are still advised to ensure immediate data consistency, regardless of webhook processing speed.