Integrations
Stripe
Connect Conductor to Stripe for payments, customers, subscriptions, and invoices. Covers test vs live mode, restricted keys, webhook setup, idempotency, and all available tools.
Test mode vs live mode
key prefixes
// Test mode keys — safe for development, hit no real charges
sk_test_... // secret key
pk_test_... // publishable key (not needed for Conductor)
// Live mode keys — real money, real customers
sk_live_... // secret key
pk_live_... // publishable key
// NEVER use sk_live_ in development, CI, or staging environments.
// Test mode and live mode are completely separate environments:
// different customers, different charges, different subscriptions.Warning
If you configure a sk_live_ key in development, Conductor will execute operations against real customers and real payment methods. Always use sk_test_ in any non-production environment.
Finding your API keys
- 1.Go to dashboard.stripe.com/apikeys (or Developers → API keys).
- 2.Toggle the test/live mode switch in the top right of the dashboard.
- 3.Copy the Secret key — click "Reveal" if hidden.
- 4.For production, use a Restricted key rather than the full secret key (see below).
Restricted API keys
Restricted keys limit what the key can access. Follow the principle of least privilege: only grant the permissions Conductor needs for your specific workflow.
restricted key setup
// Create a restricted key at:
// dashboard.stripe.com → Developers → API keys → Create restricted key
// Recommended minimal permissions for Conductor:
// Customers: Read
// Charges: Read
// PaymentIntents: Write (if creating payments)
// Subscriptions: Read + Write (if managing subscriptions)
// Invoices: Read
// Products: Read
// Prices: Read
// Refunds: Write (if issuing refunds)
// Restricted keys start with: rk_test_ or rk_live_Webhook setup — local development
The Stripe CLI forwards webhook events to your local machine. It also provides a webhook signing secret for verifying event authenticity. Use this during development instead of exposing a public URL.
stripe cli — local webhook forwarding
# Install the Stripe CLI for local webhook forwarding
brew install stripe/stripe-cli/stripe
# Log in
stripe login
# Forward webhooks to your local Conductor instance
stripe listen --forward-to http://localhost:3000/webhooks/stripe
# The CLI prints your webhook signing secret:
# > Ready! Your webhook signing secret is whsec_xxxxxxxx (^C to quit)Webhook setup — production
dashboard webhook configuration
// Production webhook setup:
// 1. Go to dashboard.stripe.com → Developers → Webhooks
// 2. Click "Add endpoint"
// 3. Enter your public URL: https://yourdomain.com/webhooks/stripe
// 4. Select events to listen for (e.g., payment_intent.succeeded)
// 5. After saving, click "Reveal" under Signing secret
// 6. Copy the whsec_... value into Conductor configConductor config
conductor.config.json
{
"plugins": {
"stripe": {
"secretKey": "sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"webhookSecret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}Available tools
| Tool | Description |
|---|---|
| stripe.customer.list | List customers with optional email or metadata filter. |
| stripe.customer.create | Create a new customer with email, name, and metadata. |
| stripe.charge.list | List charges with optional customer, date range, or status filter. |
| stripe.charge.get | Retrieve a single charge by charge ID. |
| stripe.payment-intent.create | Create a PaymentIntent for a given amount and currency. |
| stripe.subscription.list | List subscriptions with optional customer or status filter. |
| stripe.subscription.cancel | Cancel a subscription immediately or at period end. |
| stripe.invoice.list | List invoices with optional customer or status filter. |
| stripe.product.list | List all products in the Stripe account. |
| stripe.price.list | List prices with optional product filter. |
| stripe.refund.create | Issue a full or partial refund for a charge or PaymentIntent. |
Idempotency keys
idempotency key usage
// Idempotency keys prevent duplicate operations on retries.
// Conductor automatically generates and attaches idempotency keys
// for all write operations (charge creation, refunds, etc.).
//
// For manual calls, pass an idempotency key as a parameter:
{
"tool": "stripe.payment-intent.create",
"amount": 2000,
"currency": "usd",
"idempotencyKey": "order_12345_attempt_1"
}
// Using the same key within 24 hours returns the original response
// without creating a duplicate charge.Rate limits
| Mode / endpoint | Limit |
|---|---|
| Test mode — read | 100 requests/second |
| Test mode — write | 100 requests/second |
| Live mode — read | 100 requests/second |
| Live mode — write (standard) | 100 requests/second |
| Live mode — write (some endpoints) | 25 requests/second |
| Webhook delivery | 3 delivery attempts with exponential backoff |
Security
- —Use restricted keys in production. Never store the full secret key in version control or plaintext config files.
- —Always verify webhook signatures using the signing secret. Conductor does this automatically when
webhookSecretis configured. - —Never log card data, CVV, or full PAN numbers. Stripe's API never returns full card numbers after initial creation.
- —Rotate keys immediately if compromised. Stripe lets you have up to two active keys simultaneously for zero-downtime rotation.
- —Test mode and live mode have separate key sets. A compromised test key cannot access live data.
Common errors
| Error | Cause | Fix |
|---|---|---|
| invalid_request_error | A required parameter is missing, has the wrong type, or an ID references a nonexistent resource. | Read the error message — it names the specific parameter. Check IDs are correct for the current mode (test vs live). |
| authentication_required | The secret key is invalid, from the wrong mode, or has been revoked. | Verify the key starts with sk_test_ (test) or sk_live_ (live). Regenerate if it was compromised. |
| card_declined | In test mode: use test card numbers. In live mode: the card issuer declined the charge. | Test mode: use 4242 4242 4242 4242 for success. In live mode, the decline reason is in error.decline_code. |
| rate_limit | Too many API requests in a short window. | Conductor automatically retries with backoff. In test mode: 100 read + 100 write/second. In live mode: 25 write/second on some endpoints. |
| no such customer | The customer ID does not exist in the current mode. | Test and live mode customers are separate. cus_xxx from test mode will not exist in live mode. |
| no such charge / subscription | The resource ID is from the wrong mode or was deleted. | Verify you are in the correct mode. Check the dashboard to confirm the resource exists. |
| idempotency_key_in_use | A concurrent request is using the same idempotency key. | Wait for the first request to complete, or use a different idempotency key for the new request. |