Get icon
Request icon
Script icon
Set icon
SlackIncomingWebhook icon
Schedule icon

Sync Stripe Payments and Customer Data to a PostgreSQL CRM Database Daily

Sync Stripe payments and customers into a PostgreSQL CRM table daily with Kestra. Enriched records, upserts with deduplication, Slack alerts.

Categories
BusinessData

Pull Stripe charges and customer profiles, merge them into enriched payment records, and upsert the result into a PostgreSQL CRM table every day. This blueprint replaces manual Stripe CSV exports and ad hoc scripts with a scheduled, idempotent pipeline that builds a queryable payment history for sales reporting, MRR and churn analytics, customer LTV models, and downstream CRM automation. It combines the Stripe REST API, Kestra KV store for incremental state, a Python enrichment step, a PostgreSQL upsert, and a Slack confirmation message into a single declarative YAML flow.

How it works

  1. io.kestra.plugin.core.kv.Get reads the stripe_crm_last_sync_ts key from the KV store so the run knows when the previous sync finished.
  2. io.kestra.plugin.core.http.Request calls https://api.stripe.com/v1/charges with a created[gte] filter derived from the lookback_hours input, authenticated with the STRIPE_SECRET_KEY secret.
  3. A second io.kestra.plugin.core.http.Request fetches https://api.stripe.com/v1/customers for the same window.
  4. io.kestra.plugin.scripts.python.Script (merge_and_enrich) builds a customer lookup map, joins each charge to its customer, and emits enriched records with payment_id, customer_email, amount, currency, status, and metadata.
  5. io.kestra.plugin.scripts.python.Script (upsert_to_postgres) creates the crm_payments table if missing and runs INSERT ... ON CONFLICT (payment_id) DO UPDATE via psycopg2 so reruns stay idempotent.
  6. io.kestra.plugin.core.kv.Set writes the new stripe_crm_last_sync_ts value.
  7. io.kestra.plugin.slack.notifications.SlackIncomingWebhook posts the record count to Slack.
  8. io.kestra.plugin.core.trigger.Schedule (daily_sync) runs the whole flow at 0 6 * * * (06:00 UTC).

What you get

  • A crm_payments PostgreSQL table with one row per Stripe charge, kept fresh with upserts.
  • Configurable lookback_hours input for backfills or catch up runs.
  • Incremental sync state stored in KV so reruns do not double process.
  • Slack notifications confirming each successful sync with a record count.
  • A single YAML file you can version, review, and reuse across environments.

Who it's for

  • SaaS finance and RevOps teams who need Stripe data inside a Postgres warehouse.
  • Analytics engineers building MRR, churn, retention, and LTV models on raw Stripe data.
  • Sales operations teams joining Stripe revenue to product usage and CRM accounts.
  • Platform teams replacing fragile cron scripts and CSV exports with an orchestrated pipeline.

Why orchestrate this with Kestra

Stripe does not ship a scheduler, an enrichment runtime, or a Postgres loader. Kestra fills that gap with a declarative YAML flow, native KV state, retries, alerting, full execution lineage, and event or schedule triggers. The same flow can be promoted across dev, staging, and prod without rewriting glue code, and every run produces auditable logs and outputs you can replay.

Prerequisites

  • A running Kestra instance (cloud or self hosted).
  • A Stripe account with a restricted API key that can read charges and customers.
  • A reachable PostgreSQL database with permission to create and write to crm_payments.
  • A Slack incoming webhook for the notification step.

Secrets

Configure these as Kestra secrets before the first run:

  • STRIPE_SECRET_KEY (Stripe REST API bearer token)
  • POSTGRES_HOST
  • POSTGRES_DB
  • POSTGRES_USER
  • POSTGRES_PASSWORD
  • SLACK_WEBHOOK_URL

Quick start

  1. Copy this blueprint into your Kestra instance and adjust namespace if needed.
  2. Add the six secrets listed above.
  3. Pre create the target Postgres database (the flow creates the crm_payments table on first run).
  4. Trigger the flow manually with lookback_hours: 168 to backfill the last week, then let the daily schedule take over.
  5. Inspect the Slack message and query SELECT count(*) FROM crm_payments; to confirm.

How to extend

  • Pull Stripe line items, products, or invoices and enrich rows with SKU and plan metadata.
  • Push new customers into HubSpot or Salesforce via their REST APIs in a parallel branch.
  • Add refund and dispute tables and join them back to charges for net revenue reporting.
  • Replace the schedule with a webhook trigger so each successful charge syncs in near real time.
  • Fan out to BigQuery or Snowflake by adding a parallel load task using their Kestra plugins.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.