Verwendung
- Installationsbefehl kopieren und das Quellpaket vor der Installation in der eigenen Agentenumgebung prüfen.
- Benötigte Werkzeuge, Zugangsdaten und Hosts im Original prüfen.
- Eingabe und gewünschtes Ergebnis beschreiben und die Ausgabe mit den Quellen abgleichen.
npx skills add https://github.com/devhive1/devhive-cli --skill stripeVor dem Start
- Die Installation umfasst weder Modellabo noch API-Kontingent oder Dateizugriffsrechte.
- Sterne und Installationen zeigen Aktivität, keine unabhängige Qualitäts- oder Sicherheitsprüfung.
Aus dem Quell-Repository gerendert; Überschriften, Beispiele, Code, Tabellen, Links und Bilder bleiben erhalten.
Introduction
Replit offers a native integration with Stripe that allows users to implement payments in their applications
Prerequisites
- These packages must be installed in the workspace root package.json:
stripe- Official Stripe SDK for API operationsstripe-replit-sync- Handles webhook processing and database sync. Documentation: https://www.npmjs.com/package/stripe-replit-sync
Do not install them in any workspace package. If they are not installed, use pnpm to install them via the following command: $ cd /home/runner/workspace && pnpm add -w <packages>
- The Stripe integration must be connected to the repl. You can do this by proposing the integration. Reference the
integrationsskill if necessary.
Once connected, create stripeClient.ts using the template from the code-templates reference -- this file fetches Stripe credentials from the Replit connection API and provides the authenticated client via getUncachableStripeClient().
Create it in both the API server directory and the scripts directory.
- Ensure a PostgreSQL database exists. If you don't have one yet, use the tool to create a PostgreSQL database. Never use memory database for storing Stripe data.
You are required to ensure these requirements are met before setting up or using Stripe.
Project Structure
- Scripts directory: The
@workspace/scriptsmonorepo package (e.g.,src/seed-products.ts) - Run a script:
pnpm --filter @workspace/scripts exec tsx src/<script>.ts - API server directory: Monorepo package defining Express API server code
- Client app directory: The frontend application
Reference files use these terms. Map them to these concrete paths.
Initial Setup: Step-by-Step Implementation
Ensure prerequisites are met. Do not proceed until you have done so.
Follow these steps in order when implementing Stripe integration for the user. Create a task list to track implementation progress.
Read the code-templates reference file for full code file templates to use during these steps.
- Set Up Database
Create the users table with Stripe ID references:
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT,
stripe_customer_id TEXT,
stripe_subscription_id TEXT,
created_at TIMESTAMP DEFAULT NOW()
);Important: stripe-replit-sync creates the stripe schema automatically. Create application tables (users, orders, etc.) in the public schema, not in the stripe schema.
- Create Webhook Handler
In the API server create webhookHandlers.ts - use the template provided in the code-templates reference. It handles webhook processing by calling getStripeSync() from stripeClient.
- Initialize Stripe on Startup
Add this initialization function to the API server's index.ts. Important order:
- Run migrations to create schema
- Get StripeSync instance
- Set up managed webhook (uses StripeSync)
- Sync existing data with syncBackfill()
import { runMigrations } from 'stripe-replit-sync';
import { getStripeSync } from './stripeClient';
async function initStripe() {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) throw new Error('DATABASE_URL required');
// 1. Create stripe schema and tables
await runMigrations({ databaseUrl });
// 2. Get StripeSync instance (needed for webhook setup and backfill)
const stripeSync = await getStripeSync();
// 3. Set up managed webhook
const webhookBaseUrl = `https://${process.env.REPLIT_DOMAINS?.split(',')[0]}`;
const { webhook } = await stripeSync.findOrCreateManagedWebhook(
`${webhookBaseUrl}/api/stripe/webhook`
);
// 4. Sync all existing Stripe data
await stripeSync.syncBackfill();
}
await initStripe();- Register Webhook Route in index.ts
Critical: Register the webhook route BEFORE express.json() middleware. See the indexTemplate for the correct pattern:
- Route path is
/api/stripe/webhook - Webhook route uses
express.raw()to get Buffer inreq.body - Webhook route is registered BEFORE
app.use(express.json()) - Other routes registered after get parsed JSON automatically
app.post(
'/api/stripe/webhook',
express.raw({ type: 'application/json' }),
async (req, res) => {
const signature = req.headers['stripe-signature'];
if (!signature) return res.status(400).json({ error: 'Missing signature' });
const sig = Array.isArray(signature) ? signature[0] : signature;
await WebhookHandlers.processWebhook(req.body as Buffer, sig);
res.status(200).json({ received: true });
}
);
app.use(express.json()); // Now apply to other routes- Create Storage Layer
Create storage.ts - use the template provided in the code-templates reference. Query Stripe data from PostgreSQL stripe schema using standard SQL queries.
- Set Up Other Routes
Create routes.ts - use the template provided in the code-templates reference for products, prices, checkout, etc. These routes are registered AFTER express.json() so they get parsed JSON.
- Create Products Script (Recommended)
Create seed-products.ts - a script to add products and prices to Stripe via the API. This is the recommended way to create products. Run it manually when creating products.
Use the seed-products template from the code-templates reference as a starting point:
- Modify the script to create the specific products needed
- Run it manually when adding products:
node seed-products.js - Webhooks automatically sync created products to the database
- Stripe handles test vs live mode based on API keys
import { getUncachableStripeClient } from './stripeClient';
async function createProducts() {
const stripe = await getUncachableStripeClient();
// Create product
const product = await stripe.products.create({
name: 'Pro Plan',
description: 'Professional subscription',
});
// Create prices for the product
const monthlyPrice = await stripe.prices.create({
product: product.id,
unit_amount: 2900, // $29.00
currency: 'usd',
recurring: { interval: 'month' },
});
console.log('Created:', product.id, monthlyPrice.id);
}
createProducts();Usage: Run this script in development when you need to create or add products.
Optional idempotency: To make the script safe to run multiple times, check if specific products exist first:
const products = await stripe.products.search({ query: "name:'Pro Plan'" });
if (products.data.length > 0) {
console.log('Pro Plan already exists');
return;
}Database Architecture
- stripe-replit-sync creates and manages the `stripe` schema automatically - DO NOT create any tables in the stripe schema
- The stripe schema contains tables for: products, prices, customers, subscriptions, payment_intents, etc.
- Application tables are created in the public schema (or other schemas) - e.g., users, orders, etc.
- Application tables store Stripe IDs as TEXT columns (e.g.,
stripe_customer_id TEXT,stripe_subscription_id TEXT) - Replit automatically handles deployment and Stripe data migration moving from sandbox to live.
Synchronization Flow
- Stripe credentials are fetched from Replit connection API
- `runMigrations()` creates the stripe schema and all Stripe tables (idempotent, safe to run on every startup)
- `syncBackfill()` syncs ALL existing Stripe data from Stripe API to the local PostgreSQL database on startup
- Managed webhooks are automatically configured by
stripe-replit-sync - Webhooks keep data up-to-date when changes occur in Stripe after startup
- Application queries Stripe data from PostgreSQL
stripeschema (fast, no API calls needed)
Storing Data
Do NOT Create Product Tables or Maintain Any Other Source of Truth for Stripe Data
Bad -- creates duplicate product storage:
export const products = pgTable("products", {
id: varchar("id").primaryKey(),
name: text("name"),
price: integer("price"),
// ... custom fields
});Correct Approach:
- NO product tables needed!
- Query directly from
stripe.productsandstripe.prices - Use Stripe's metadata field for ALL custom attributes
Creating Products and Prices
NEVER insert data directly into the stripe schema tables. Instead:
- Create products via Stripe API (using scripts)
- Stripe webhooks managed by stripe-replit-sync automatically sync the data to the stripe schema in the local database
- Query the synced data from the
stripeschema tables using standard SQL queries
Create products in Stripe with metadata (use API or script):
await stripe.products.create({
name: "Product Name",
description: "...",
images: ["https://..."],
metadata: {
category: "electronics",
customField1: "value1",
featured: "true",
}
});
await stripe.prices.create({
product: product.id,
unit_amount: 9999,
currency: 'usd',
});Query from synced stripe tables:
const result = await db.execute(sql`
SELECT
p.id,
p.name,
p.metadata,
pr.id as price_id,
pr.unit_amount
FROM stripe.products p
JOIN stripe.prices pr ON pr.product = p.id
WHERE p.active = true
`);Use real Stripe price IDs in checkout:
// CORRECT
{ price: "price_1ABC...", quantity: 1 }
// WRONG - Never use price_data
{
price_data: {
unit_amount: 9999,
currency: 'usd',
product_data: { name: "..." }
}
}Decision Tree: When to Create Tables
- Products/Prices? -- NO, use
stripe.products/stripe.prices - Customers? -- NO, use
stripe.customers - Subscriptions? -- NO, use
stripe.subscriptions - Orders/Cart/User preferences? -- YES, these aren't in Stripe
- Relationships to Stripe data? -- YES, store Stripe IDs as foreign keys
Key Principle: "If it exists in Stripe, it belongs in Stripe"
- Don't duplicate Stripe data in your own tables
- Don't create parallel storage systems
- Stripe + metadata = your complete product catalog
- Your tables should only store data that Stripe doesn't manage
Creating products: Write a seed script that calls Stripe API (stripe.products.create(), stripe.prices.create()). Run this script in development to create your products. Webhooks automatically sync them to the database. Replit handles deployment automatically.
Workflow:
# Development:
# - Run seed script to create products in Stripe (test mode)
# - syncBackfill() syncs them to local database
# Deployment (handled by Replit):
# - Replit copies products/prices from dev Stripe to prod Stripe
# - Your code runs unchanged, syncBackfill() syncs prod database
# Production:
# - Modify products via Stripe Dashboard (scripts can't run in deployments)
# - Webhooks automatically sync changes to databasePublishing with Stripe
To publish the app with working Stripe payments:
- Go to the Stripe Dashboard (https://dashboard.stripe.com/apikeys)
- Get live API keys (starts with
pk_live_andsk_live_) - Open the Publish pane in the Workspace
- Enter the live Publishable Key and Secret Key
- Publish the app
Placeholder Keys (User-Requested Only):
Only offer placeholder keys if the user explicitly asks to publish without live Stripe keys and understands the consequences. Do NOT use these for any other purpose.
If the user confirms they want to proceed without live keys, suggest the following values to them:
- Publishable Key:
pk_live_abcdef - Secret Key:
sk_live_abcdef
Consequences the user must understand:
- Placeholder keys will NOT process real payments
- The product catalog and checkout will not function on the published URL
- Real Stripe keys must be added later for payments to work
Deleting Stripe Integration
To remove the Stripe integration from the project:
- In the project, open the "Integrations" tab
- Go to "Stripe" and click "Manage"
- Select "Edit" then "Delete"
Secrets and Environment Variables
NEVER write secrets or environment variables directly to the `.replit` file. This includes Stripe API keys, webhook signing secrets, database URLs, and any other sensitive configuration. Instead, reference the environment-secrets skill for the correct way to manage secrets and environment variables.
Key Rules
DO:
- Create products via Stripe API using scripts (never with SQL INSERT)
- Query Stripe data from PostgreSQL
stripeschema tables (products, prices, customers, subscriptions, etc.) - Store Stripe IDs in application tables as TEXT (e.g.,
stripe_customer_id TEXT) - Keep webhook handler minimal (just call
processWebhookwith payload and signature) - Let
syncBackfill()sync existing Stripe data on startup - Let managed webhooks handle webhook configuration automatically
- Register webhook route BEFORE
express.json()middleware
ABSOLUTELY DO NOT:
- Create any tables in the
stripeschema - stripe-replit-sync manages this automatically - Insert, update, or delete data in
stripeschema tables - only query from them - Use SQL INSERT for products, prices, customers, subscriptions - use Stripe API instead
- Manually copy database data between environments - Replit handles Stripe product/price copying during deployment
- Add custom logic in webhook handler beyond calling
processWebhook - Skip running
runMigrations()orsyncBackfill() - Create StripeSync instance before calling
runMigrations()
Common Mistakes
Database - DO NOT create Stripe tables:
-- WRONG - Creating Stripe tables manually
CREATE TABLE products (
id TEXT PRIMARY KEY,
name TEXT,
price INTEGER
);
-- CORRECT - Create application tables, store Stripe IDs
CREATE TABLE users (
id TEXT PRIMARY KEY,
stripe_customer_id TEXT
);
-- stripe-replit-sync creates stripe.products, stripe.prices, etc. automaticallyData Creation - Use Stripe API Scripts, NOT SQL:
-- WRONG - Inserting Stripe data with SQL
INSERT INTO stripe.products (id, name, description)
VALUES ('prod_123', 'Pro Plan', 'Professional subscription');// CORRECT - Use Stripe API in a script
const stripe = await getUncachableStripeClient();
const product = await stripe.products.create({
name: 'Pro Plan',
description: 'Professional subscription',
});
// Webhook syncs this to stripe.products automaticallyInitialization Order:
// WRONG - Creating StripeSync before migrations
const stripeSync = await getStripeSync();
await runMigrations({ databaseUrl });
// CORRECT - Migrations first, then StripeSync
await runMigrations({ databaseUrl });
const stripeSync = await getStripeSync();
await stripeSync.findOrCreateManagedWebhook(...);
await stripeSync.syncBackfill();Frontend - Must parse JSON responses:
// WRONG - returns Response object
const response = await apiRequest('POST', '/api/checkout', { priceId });
return response;
// CORRECT - parse to get data
const response = await apiRequest('POST', '/api/checkout', { priceId });
return await response.json();Backend - Webhook route ordering:
// WRONG - Webhook after express.json()
app.use(express.json());
app.post('/api/stripe/webhook', ...); // Too late! Body already parsed
// CORRECT - Webhook BEFORE express.json()
app.post('/api/stripe/webhook', express.raw({ type: 'application/json' }),
async (req, res) => {
await WebhookHandlers.processWebhook(req.body, sig);
}
);
app.use(express.json()); // Now apply to other routesReferences
- ./references/code-templates.md -- Code file templates for initial Stripe setup. ONLY read this reference when performing initial setup of Stripe in a project that does not already have it configured. Do not read for subsequent modifications, queries, or other Stripe operations.





