Skip to content

Setup

Sign up at stripe.com. Every account has a test mode with its own keys and data — use that for everything until you’re ready to charge real cards. Copy the test secret key (sk_test_…) from Developers → API keys.

alchemy.run.ts
import * as Alchemy from "alchemy";
import * as Cloudflare from "alchemy/Cloudflare";
import * as Stripe from "alchemy/Stripe";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
export default Alchemy.Stack(
"MyApp",
{
providers: Layer.mergeAll(Cloudflare.providers(), Stripe.providers()),
state: Alchemy.localState(),
},
Effect.gen(function* () {
// resources go here
}),
);

The first alchemy deploy that touches a Stripe resource prompts for the key and saves it under ~/.alchemy/credentials/<profile>/. To set it up ahead of time, or to add Stripe to an existing profile:

Terminal window
alchemy profile edit --add Stripe

An optional API base URL overrides https://api.stripe.com (useful for stripe-mock).

In CI (CI=true) profiles are bypassed and alchemy reads STRIPE_API_KEY from the environment. STRIPE_API_BASE_URL is optional.

See Profiles for switching between accounts and stages.

A sk_test_… key talks to a fully working Stripe account. Products, Prices, Customers, Checkout Sessions, and webhook deliveries all behave exactly as in live mode; the only difference is that cards like 4242 4242 4242 4242 succeed and no money moves. Deploy, destroy, and redeploy freely.

A Worker that calls Stripe at runtime needs a key on the host. You never wire that up by hand. Each binding you yield — Stripe.CreateCustomer(), Stripe.CreateCheckoutSession(), and so on — declares the permission it needs (customers_write, checkout_sessions_write, …) on a RestrictedApiKey resource that alchemy creates per Worker. The key’s value is injected as a secret_text binding.

Today Stripe has no public API for minting restricted keys, so the value alchemy injects is your account secret key. The permissions are still recorded on the resource, which means:

  • you can see exactly which Stripe scopes each Worker uses in the plan output, and
  • if you’d rather the Worker hold a narrower key, create one in Dashboard → API keys → Restricted keys with those scopes and pass it as value — bindings will use it unchanged.

When Stripe ships a mint API the same declarations will drive it with no code change in your Worker.

If you’re going to create connected accounts, Connect must be switched on once at dashboard.stripe.com/connect. There’s no API for that step; POST /v1/accounts returns an error until it’s done.