Complete Stripe billing and payments integration for nself. Syncs all Stripe data to PostgreSQL with real-time webhook support.
The Stripe plugin provides complete synchronization of your Stripe account data to a local PostgreSQL database. It supports:
# Install the plugin
nself plugin install stripe
# Configure environment
echo "STRIPE_API_KEY=sk_live_xxx" >> .env
echo "STRIPE_WEBHOOK_SECRET=whsec_xxx" >> .env
# Rebuild and restart to apply
nself build && nself restart
# Verify the plugin is running
nself plugin status stripe| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | - | PostgreSQL connection string |
STRIPE_API_KEY | Yes | - | Stripe secret API key (sk_live_xxx or sk_test_xxx) |
STRIPE_WEBHOOK_SECRET | No | - | Webhook endpoint signing secret (whsec_xxx) |
STRIPE_API_VERSION | No | 2024-12-18 | Stripe API version to use |
PORT | No | 3001 | HTTP server port |
LOG_LEVEL | No | info | Logging level (debug, info, warn, error) |
Your Stripe API key needs read access to all resources you want to sync. Write access is not required (plugin is read-only). For production, use a restricted key with only read permissions.
# Install the stripe plugin
nself plugin install stripe
# Check plugin health and sync status
nself plugin status stripe
# Update to latest version
nself plugin update stripe
# Remove plugin (keeps tables by default)
nself plugin remove stripe
# Remove plugin and drop all stripe_* tables
nself plugin remove stripe --delete-dataStripe data syncs automatically via webhook handlers the plugin registers at install time. For a historical backfill after initial setup, use the Stripe Dashboard export or the Stripe CLI — the nself plugin does not expose per-resource sync subcommands.
Query synced data directly via Hasura GraphQL (all tables are auto-tracked):
# List customers
query {
stripe_customers(limit: 50) {
id
email
name
created
}
}
# List active subscriptions
query {
stripe_subscriptions(where: { status: { _eq: "active" } }) {
id
customer_id
status
current_period_end
}
}
# List recent invoices
query {
stripe_invoices(order_by: { created: desc }, limit: 20) {
id
customer_id
status
amount_due
amount_paid
}
}The plugin registers a webhook endpoint at /webhooks/stripe on your nself backend. Configure it in the Stripe Dashboard to start receiving real-time events — see the Webhook Setup section below.
# Check that the plugin container is healthy
nself plugin status stripe
# Tail plugin logs for webhook delivery errors
nself plugin logs stripe
# Re-enable a disabled plugin
nself plugin enable stripehttps://your-domain.com/webhooks/stripecustomer.created, customer.updatedsubscription.created, subscription.updated, subscription.deletedinvoice.paid, invoice.payment_failedpayment_intent.succeeded, payment_intent.payment_failedSTRIPE_WEBHOOK_SECRETstripe listen --forward-to localhost/webhooks/stripeThe Stripe CLI is the easiest way to test webhooks locally. It automatically provides a webhook secret and forwards events to your local server.
| Resource | Description | Table |
|---|---|---|
| Customers | Customer profiles with metadata | stripe_customers |
| Products | Product catalog | stripe_products |
| Prices | Pricing information | stripe_prices |
| Subscriptions | Active and past subscriptions | stripe_subscriptions |
| Subscription Items | Individual subscription line items | stripe_subscription_items |
| Invoices | All invoices | stripe_invoices |
| Invoice Items | Individual invoice line items | stripe_invoice_items |
| Payment Intents | Payment attempts | stripe_payment_intents |
| Payment Methods | Saved payment methods | stripe_payment_methods |
| Charges | Completed charges | stripe_charges |
| Refunds | Refund records | stripe_refunds |
| Disputes | Chargebacks and disputes | stripe_disputes |
| Balance Transactions | Account balance history | stripe_balance_transactions |
| Payouts | Payout records | stripe_payouts |
| Coupons | Discount coupons | stripe_coupons |
| Promotion Codes | Promo codes | stripe_promotion_codes |
| Tax Rates | Tax rate definitions | stripe_tax_rates |
| Setup Intents | Payment method setup attempts | stripe_setup_intents |
| Checkout Sessions | Checkout session records | stripe_checkout_sessions |
| Events | Stripe event log | stripe_events |
| Webhook Events | Received webhook events | stripe_webhook_events |
| View | Description |
|---|---|
stripe_active_subscriptions | Active subscriptions with customer details |
stripe_mrr | Monthly recurring revenue calculation |
stripe_failed_payments | Recent failed payment attempts |
stripe_revenue_by_month | Revenue aggregated by month |
stripe_customer_lifetime_value | Customer lifetime value calculation |
stripe_subscription_churn | Subscription churn metrics |
-- Monthly recurring revenue from Stripe
SELECT
DATE_TRUNC('month', created_at) AS month,
SUM(amount / 100.0) AS mrr
FROM stripe_subscriptions
WHERE status = 'active'
GROUP BY month
ORDER BY month DESC;
-- Find customers at risk of churn
SELECT
c.email,
c.name,
s.current_period_end,
s.cancel_at_period_end,
i.amount / 100.0 AS last_invoice_amount,
i.status AS last_invoice_status
FROM stripe_customers c
JOIN stripe_subscriptions s ON c.id = s.customer_id
LEFT JOIN stripe_invoices i ON s.latest_invoice = i.id
WHERE s.status = 'active'
AND (
s.cancel_at_period_end = TRUE
OR i.status IN ('open', 'uncollectible')
OR s.current_period_end < NOW() + INTERVAL '7 days'
)
ORDER BY s.current_period_end;
-- Revenue report by product
SELECT
pr.name AS product_name,
p.nickname AS price_name,
p.unit_amount / 100.0 AS price,
p.currency,
COUNT(DISTINCT s.id) AS active_subscriptions,
SUM(p.unit_amount) / 100.0 AS total_mrr
FROM stripe_products pr
JOIN stripe_prices p ON pr.id = p.product_id
JOIN stripe_subscription_items si ON p.id = si.price_id
JOIN stripe_subscriptions s ON si.subscription_id = s.id
WHERE s.status = 'active'
GROUP BY pr.name, p.nickname, p.unit_amount, p.currency
ORDER BY total_mrr DESC;All Stripe tables are automatically tracked in Hasura:
query GetCustomerSubscriptions {
stripe_customers(limit: 10) {
id
email
name
stripe_subscriptions {
id
status
current_period_end
stripe_price {
unit_amount
stripe_product {
name
}
}
}
}
}ENV=dev
STRIPE_API_KEY=sk_test_xxxxxUses test customers, no real charges.
ENV=prod
STRIPE_API_KEY=sk_live_xxxxxReal customer data and charges.
Never use live API keys in development. Always use test keys (sk_test_*) for local development and staging environments.
# Remove plugin and data
nself plugin remove stripe
# Keep database tables
nself plugin remove stripe --keep-dataError: Invalid API Key providedCheck that STRIPE_API_KEY is set correctly. Ensure you are using the correct key for your environment (test vs live).
# Verify key format
echo $STRIPE_API_KEY | head -c 10
# Should show: sk_live_xx or sk_test_xxError: Webhook signature verification failedSolutions:
STRIPE_WEBHOOK_SECRET matches the endpoint in Stripe DashboardError: Rate limit exceededThe plugin has built-in rate limiting, but if you are hitting limits:
Error: Connection refusedSolutions:
DATABASE_URL format# Test connection
psql $DATABASE_URL -c "SELECT 1"Enable debug logging for detailed troubleshooting:
# Tail live plugin logs (shows webhook delivery details)
nself plugin logs stripe
# Check plugin status and container health
nself plugin status stripe# Check plugin status
nself plugin status stripe
# Check plugin container health via HTTP (port exposed by plugin service)
curl http://localhost:3001/health-- Create a view to join app users with Stripe customers
CREATE VIEW user_billing AS
SELECT
u.id AS user_id,
u.email,
sc.id AS stripe_customer_id,
sc.created AS customer_since,
(SELECT COUNT(*) FROM stripe_subscriptions ss
WHERE ss.customer_id = sc.id AND ss.status = 'active') AS active_subscriptions
FROM users u
LEFT JOIN stripe_customers sc ON u.email = sc.email;// Check if user has active subscription
async function hasActiveSubscription(userEmail: string): Promise<boolean> {
const result = await hasura.query({
query: `
query CheckSubscription($email: String!) {
stripe_customers(where: { email: { _eq: $email } }) {
stripe_subscriptions(where: { status: { _eq: "active" } }) {
id
}
}
}
`,
variables: { email: userEmail }
});
return result.stripe_customers[0]?.stripe_subscriptions?.length > 0;
}Last Updated: April 2026 | Plugin Version 1.0.12 | Stripe API Version 2024-12-18