#Stripe payments
CoDuck integrates with Stripe Connect so your apps can accept payments. Money goes directly to your Stripe account — CoDuck never touches it. Available on Pro and Studio plans. This is BYOS ("Bring Your Own Stripe"): sign in once, your app gets credentials, Stripe handles the rest. CoDuck takes 0% of your revenue.
#Connect your Stripe account
- Open your project at
https://app.coduck.ai/project/<projectId>. - Switch to the Cloud panel and select the Payments tab.
- Click Connect Stripe. A Stripe OAuth window opens.
- Sign in to Stripe (or create an account) and approve the connection.
- CoDuck stores the connection. On the next deploy, the keys are injected into your container.
#What gets injected
When a Stripe account is connected, the next deploy injects these env vars into your container:
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY | Restricted API key for the connected account (auto-rotated on refresh) |
STRIPE_PUBLISHABLE_KEY | Public key for the connected account |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Same publishable key, prefixed for client-side access in Next.js |
These are reserved — you can't override them in the Env sub-tab.
#Charging in your code
Two patterns work — pick whichever you prefer.
#CoDuck SDK (recommended)
The SDK reads STRIPE_SECRET_KEY from the environment automatically:
import { stripe } from "@coduckai/sdk/payments";
const session = await stripe.checkout.sessions.create({
line_items: [{ price: "price_xxx", quantity: 1 }],
mode: "payment",
success_url: "https://example.com/success",
cancel_url: "https://example.com/cancel",
});import { stripe } from "@coduckai/sdk/payments";
const session = await stripe.checkout.sessions.create({
line_items: [{ price: "price_xxx", quantity: 1 }],
mode: "payment",
success_url: "https://example.com/success",
cancel_url: "https://example.com/cancel",
});#Raw stripe npm package
Works the same way — instantiate with process.env.STRIPE_SECRET_KEY. Useful if you want full TypeScript types for every Stripe API surface.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const session = await stripe.checkout.sessions.create({
line_items: [{ price: "price_xxx", quantity: 1 }],
mode: "payment",
success_url: "https://example.com/success",
cancel_url: "https://example.com/cancel",
});import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const session = await stripe.checkout.sessions.create({
line_items: [{ price: "price_xxx", quantity: 1 }],
mode: "payment",
success_url: "https://example.com/success",
cancel_url: "https://example.com/cancel",
});#Webhooks to your app
Stripe webhooks (charge.succeeded, customer.subscription.updated, etc.) go directly to your app via the webhook endpoint you configure in your Stripe dashboard.
- In the Stripe dashboard, add an endpoint pointing at your deployed app — e.g.
https://<project>.coduck.app/api/stripe/webhook. - Copy the signing secret Stripe gives you.
- In CoDuck, set it under Cloud panel → Hosting → Env as
STRIPE_WEBHOOK_SECRET. (This one is user-set, not auto-injected.)
A minimal Next.js Route Handler that verifies the signature with the raw body and the stripe-signature header:
// app/api/stripe/webhook/route.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature")!;
const body = await req.text(); // raw body required for verification
const event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!,
);
switch (event.type) {
case "charge.succeeded":
// ...
break;
}
return new Response("ok");
}// app/api/stripe/webhook/route.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature")!;
const body = await req.text(); // raw body required for verification
const event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!,
);
switch (event.type) {
case "charge.succeeded":
// ...
break;
}
return new Response("ok");
}Note: CoDuck handles connection-level events (e.g. account deauthorized) on its own platform webhook — you don't have to set those up.
#Analytics
View stats, transactions, a revenue chart, and connection health under Cloud panel → Payments.
#Status
The connection has three states, shown in the Payments tab:
connected— working normally.needs_reconnect— Stripe returned 401 on a recent call. Re-run the OAuth flow to refresh the token.revoked— you or Stripe deauthorized the connection. Reconnect to restore.
#Disconnect
In Cloud panel → Payments, click Disconnect Stripe. This revokes CoDuck's OAuth access and removes the injected env vars on the next deploy. Your Stripe account itself is untouched.
#Notes
- One Stripe account per CoDuck project. Different projects can connect to different accounts.
- Refunds, subscriptions, and disputes are handled through the standard Stripe API using the injected key. CoDuck doesn't proxy them.
#Common failures
- "Connect Stripe" returns
upgrade_required— you're on the Free plan. Upgrade to Pro or Studio first, then retry the OAuth flow. - "No Stripe account connected" when calling the SDK at runtime — you connected but haven't redeployed yet, so the env vars aren't in the container. Redeploy to pick them up.
- Status flipped to
needs_reconnect— Stripe returned 401 on a recent call. Re-run the OAuth flow from the Payments tab.
#For developers
A CLI is also available for connecting Stripe, checking status, and viewing payments from the terminal — see CLI commands.
#Next
- Deploying a project — when injected env vars take effect
- Database overview — the other half of a typical paid app