CoDuck Docs

#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

  1. Open your project at https://app.coduck.ai/project/<projectId>.
  2. Switch to the Cloud panel and select the Payments tab.
  3. Click Connect Stripe. A Stripe OAuth window opens.
  4. Sign in to Stripe (or create an account) and approve the connection.
  5. 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:

VariableDescription
STRIPE_SECRET_KEYRestricted API key for the connected account (auto-rotated on refresh)
STRIPE_PUBLISHABLE_KEYPublic key for the connected account
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYSame 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.

The SDK reads STRIPE_SECRET_KEY from the environment automatically:

ts
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.

ts
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.

  1. In the Stripe dashboard, add an endpoint pointing at your deployed app — e.g. https://<project>.coduck.app/api/stripe/webhook.
  2. Copy the signing secret Stripe gives you.
  3. 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:

ts
// 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