Skip to content

Tutorial

This tutorial deploys the Stripe capability and calls it from a second Worker. The steps are the same for every capability. Change the name, the secret, and the binding.

Each step shows the cf CLI first. Wrangler still works. Select the Wrangler tab to see it.

You need a Cloudflare account and a Stripe test key (sk_test_...).

Terminal window
npm install -g cf
cf auth login

cf needs Node.js 22 or later.

Clone the repo and open the Stripe capability.

Terminal window
git clone https://github.com/acoyfellow/capa
cd capa && bun install
cd capabilities/stripe

Convert the Worker config to cloudflare.config.ts, then deploy.

Terminal window
cf migrate
cf deploy

cf migrate reads wrangler.jsonc and writes cloudflare.config.ts:

cloudflare.config.ts
import { defineConfig } from "cf/config";
export default defineConfig({
worker: {
name: "capa-stripe",
compatibilityDate: "2026-04-17",
compatibilityFlags: ["nodejs_compat"],
entrypoint: "src/index.ts",
workersDev: false,
observability: { enabled: true },
},
});

You can also open the Stripe capability and select Deploy to Cloudflare.

Terminal window
cf workers secrets update STRIPE_API_KEY --worker capa-stripe --type secret_text

cf asks for the value. To script it, pipe the key on stdin from a file:

Terminal window
cf workers secrets update STRIPE_API_KEY --worker capa-stripe --type secret_text < stripe-key.txt

Do not pass it with --text, because the key then goes into your shell history.

The key stays in the capability Worker. Your Worker never sees it.

In your own Worker, bind the capability as STRIPE.

cloudflare.config.ts
import { bindings, defineConfig } from "cf/config";
export default defineConfig({
worker: {
name: "my-app",
compatibilityDate: "2026-09-01",
entrypoint: "src/index.ts",
env: {
STRIPE: bindings.worker({
worker: "capa-stripe",
exportName: "StripeCapability",
}),
},
},
});

cf builds with Wrangler. Add it as a dev dependency: npm install -D wrangler.

src/index.ts
export default {
async fetch(request, env) {
const { result, evidence } = await env.STRIPE.paymentIntents.create({
amount: 2500,
currency: "usd",
});
if (evidence.verdict === "fail") {
return Response.json({ error: "Stripe call failed", evidence }, { status: 502 });
}
return Response.json({ id: result.id, evidence });
},
};

Method names come from the OpenAPI spec, so guessing them does not work. Search the generated manifest for the API path you want:

Terminal window
grep '"path":"/user"' capabilities/github/src/generated/manifest.gen.ts
"users/get-authenticated": {"namespace":"user","method":"list","http":"get","path":"/user","risk":"low"},

Call it as env.GITHUB.user.list(). A namespace with _ or - becomes camelCase on the binding, for example payment_intents becomes paymentIntents.

Terminal window
cf deploy
curl https://my-app.<your-subdomain>.workers.dev

The response contains the payment intent ID and the evidence record. evidence.verdict is "pass" when every check passed.

  1. Your Worker called paymentIntents.create over the service binding.
  2. capa-stripe sent POST /v1/payment_intents to Stripe with your key.
  3. It checked the HTTP status and any method-specific checks.
  4. It returned { result, evidence } to your Worker.