Claim this agent
Agent DossierCLAWHUBSafety 84/100

Xpersona Agent

afrexai-stripe-production

Stripe Production Engineering Stripe Production Engineering Complete methodology for building, scaling, and operating production Stripe payment systems. From first checkout to enterprise billing at scale. Quick Health Check Run through these 8 signals. Score 1 point each. Below 5 = stop and fix. 1. ✅ Webhook endpoint verified and idempotent 2. ✅ All API calls use idempotency keys 3. ✅ Customer portal enabled for self-service 4. ✅ Stripe Tax or ma

OpenClaw · self-declared
Trust evidence available
clawhub skill install skills:1kalin:afrexai-stripe-production

Overall rank

#62

Adoption

No public adoption signal

Trust

Unknown

Freshness

Feb 25, 2026

Freshness

Last checked Feb 25, 2026

Best For

afrexai-stripe-production is best for general automation workflows where OpenClaw compatibility matters.

Not Ideal For

Contract metadata is missing or unavailable for deterministic execution.

Evidence Sources Checked

editorial-content, CLAWHUB, runtime-metrics, public facts pack

Overview

Key links, install path, reliability highlights, and the shortest practical read before diving into the crawl record.

Verifiededitorial-content

Overview

Executive Summary

Stripe Production Engineering Stripe Production Engineering Complete methodology for building, scaling, and operating production Stripe payment systems. From first checkout to enterprise billing at scale. Quick Health Check Run through these 8 signals. Score 1 point each. Below 5 = stop and fix. 1. ✅ Webhook endpoint verified and idempotent 2. ✅ All API calls use idempotency keys 3. ✅ Customer portal enabled for self-service 4. ✅ Stripe Tax or ma Capability contract not published. No trust telemetry is available yet. Last updated 4/15/2026.

No verified compatibility signals

Trust score

Unknown

Compatibility

OpenClaw

Freshness

Feb 25, 2026

Vendor

Openclaw

Artifacts

0

Benchmarks

0

Last release

Unpublished

Install & run

Setup Snapshot

clawhub skill install skills:1kalin:afrexai-stripe-production
  1. 1

    Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.

  2. 2

    Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.

Evidence & Timeline

Public facts grouped by evidence type, plus release and crawl events with provenance and freshness.

Verifiededitorial-content

Public facts

Evidence Ledger

Vendor (1)

Vendor

Openclaw

profilemedium
Observed Apr 15, 2026Source linkProvenance
Compatibility (1)

Protocol compatibility

OpenClaw

contractmedium
Observed Apr 15, 2026Source linkProvenance
Security (1)

Handshake status

UNKNOWN

trustmedium
Observed unknownSource linkProvenance
Integration (1)

Crawlable docs

6 indexed pages on the official domain

search_documentmedium
Observed Apr 15, 2026Source linkProvenance

Artifacts & Docs

Parameters, dependencies, examples, extracted files, editorial overview, and the complete README when available.

Self-declaredCLAWHUB

Captured outputs

Artifacts Archive

Extracted files

0

Examples

6

Snippets

0

Languages

typescript

Parameters

Executable Examples

text

src/
  payments/
    stripe.config.ts        # Stripe client initialization
    webhooks.handler.ts     # Webhook endpoint + event routing
    checkout.service.ts     # Checkout session creation
    subscription.service.ts # Subscription lifecycle
    customer.service.ts     # Customer CRUD + portal
    invoice.service.ts      # Invoice customization
    tax.service.ts          # Tax calculation
    types.ts                # Shared types
  middleware/
    webhook-verify.ts       # Signature verification middleware

typescript

// stripe.config.ts
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-12-18.acacia',  // Pin API version!
  maxNetworkRetries: 2,
  timeout: 10_000,
  telemetry: false,
});

export { stripe };

typescript

// customer.service.ts
async function getOrCreateCustomer(userId: string, email: string, name?: string) {
  // Check DB first
  const existing = await db.users.findOne({ id: userId });
  if (existing?.stripeCustomerId) {
    return existing.stripeCustomerId;
  }

  // Create in Stripe
  const customer = await stripe.customers.create({
    email,
    name,
    metadata: {
      user_id: userId,
      created_via: 'signup',
    },
  });

  // Store mapping
  await db.users.update({ id: userId }, { stripeCustomerId: customer.id });
  return customer.id;
}

typescript

// checkout.service.ts
async function createCheckoutSession(params: {
  customerId: string;
  priceId: string;
  mode: 'payment' | 'subscription';
  successUrl: string;
  cancelUrl: string;
  metadata?: Record<string, string>;
}) {
  const session = await stripe.checkout.sessions.create({
    customer: params.customerId,
    mode: params.mode,
    line_items: [{ price: params.priceId, quantity: 1 }],
    success_url: `${params.successUrl}?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: params.cancelUrl,
    metadata: params.metadata ?? {},

    // Recommended defaults
    allow_promotion_codes: true,
    billing_address_collection: 'auto',
    tax_id_collection: { enabled: true },
    customer_update: { address: 'auto', name: 'auto' },
    payment_method_types: ['card'],
    
    // For subscriptions
    ...(params.mode === 'subscription' && {
      subscription_data: {
        metadata: params.metadata ?? {},
        trial_period_days: 14,
      },
    }),
  }, {
    idempotencyKey: `checkout_${params.customerId}_${params.priceId}_${Date.now()}`,
  });

  return session;
}

typescript

// Server: create PaymentIntent
async function createPaymentIntent(params: {
  customerId: string;
  amount: number;      // in cents!
  currency: string;
  metadata?: Record<string, string>;
}) {
  return stripe.paymentIntents.create({
    customer: params.customerId,
    amount: params.amount,
    currency: params.currency,
    automatic_payment_methods: { enabled: true },
    metadata: {
      ...params.metadata,
      created_at: new Date().toISOString(),
    },
  }, {
    idempotencyKey: `pi_${params.customerId}_${params.amount}_${Date.now()}`,
  });
}

// Client: React Payment Element
// <PaymentElement /> handles all payment method rendering
// Use confirmPayment() on form submit

text

Created → Active → Past Due → Canceled → (optionally) Unpaid
                ↓
            Trialing → Active
                ↓
            Paused → Resumed → Active

Editorial read

Docs & README

Docs source

CLAWHUB

Editorial quality

ready

Stripe Production Engineering Stripe Production Engineering Complete methodology for building, scaling, and operating production Stripe payment systems. From first checkout to enterprise billing at scale. Quick Health Check Run through these 8 signals. Score 1 point each. Below 5 = stop and fix. 1. ✅ Webhook endpoint verified and idempotent 2. ✅ All API calls use idempotency keys 3. ✅ Customer portal enabled for self-service 4. ✅ Stripe Tax or ma

Full README

Stripe Production Engineering

Complete methodology for building, scaling, and operating production Stripe payment systems. From first checkout to enterprise billing at scale.

Quick Health Check

Run through these 8 signals. Score 1 point each. Below 5 = stop and fix.

  1. ✅ Webhook endpoint verified and idempotent
  2. ✅ All API calls use idempotency keys
  3. ✅ Customer portal enabled for self-service
  4. ✅ Stripe Tax or manual tax collection configured
  5. ✅ Failed payment retry logic with dunning emails
  6. ✅ PCI compliance questionnaire completed (SAQ-A minimum)
  7. ✅ Test mode → live mode checklist completed
  8. ✅ Monitoring/alerting on payment failures and webhook errors

Score: /8 — Below 5? Fix gaps before adding features.


Phase 1: Architecture Strategy

Integration Pattern Decision

| Pattern | Best For | Complexity | PCI Scope | |---------|----------|------------|-----------| | Stripe Checkout (hosted) | MVPs, quick launch | Low | SAQ-A (minimal) | | Payment Element (embedded) | Custom UX, brand control | Medium | SAQ-A | | Card Element (legacy) | Existing integrations | Medium | SAQ-A-EP | | Direct API | Platform/marketplace | High | SAQ-D (avoid) |

Decision rule: Start with Checkout. Move to Payment Element only when you have specific UX requirements that Checkout can't solve.

Billing Model Selection

| Model | Stripe Product | Use When | |-------|---------------|----------| | One-time | Payment Links / Checkout | Single purchases, lifetime deals | | Recurring flat | Subscriptions | Fixed monthly/annual SaaS | | Usage-based | Metered billing | API calls, compute, storage | | Per-seat | Subscriptions + quantity | Team/user-based pricing | | Tiered | Tiered pricing | Volume discounts | | Hybrid | Subscription + usage records | Base fee + overage |

Project Structure

src/
  payments/
    stripe.config.ts        # Stripe client initialization
    webhooks.handler.ts     # Webhook endpoint + event routing
    checkout.service.ts     # Checkout session creation
    subscription.service.ts # Subscription lifecycle
    customer.service.ts     # Customer CRUD + portal
    invoice.service.ts      # Invoice customization
    tax.service.ts          # Tax calculation
    types.ts                # Shared types
  middleware/
    webhook-verify.ts       # Signature verification middleware

7 Architecture Rules

  1. Never trust the client — verify payment status server-side via webhooks, never from redirect URLs
  2. Webhooks are the source of truth — your database updates from webhook events, not API call responses
  3. Idempotency everywhere — every mutating API call gets an idempotency key
  4. One Stripe customer per user — create customer at signup, store stripe_customer_id in your DB
  5. Metadata is your friend — attach user_id, plan, source to every object for debugging
  6. Test mode mirrors live — your test environment should use the exact same code paths
  7. Never store card numbers — use Stripe.js/Elements, never handle raw card data

Phase 2: Core Integration Patterns

Stripe Client Setup

// stripe.config.ts
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-12-18.acacia',  // Pin API version!
  maxNetworkRetries: 2,
  timeout: 10_000,
  telemetry: false,
});

export { stripe };

Rules:

  • Pin API version — never use rolling latest
  • Set explicit timeout (10s default is fine)
  • Disable telemetry in production if privacy-sensitive
  • Use restricted keys with minimum required permissions

Customer Lifecycle

// customer.service.ts
async function getOrCreateCustomer(userId: string, email: string, name?: string) {
  // Check DB first
  const existing = await db.users.findOne({ id: userId });
  if (existing?.stripeCustomerId) {
    return existing.stripeCustomerId;
  }

  // Create in Stripe
  const customer = await stripe.customers.create({
    email,
    name,
    metadata: {
      user_id: userId,
      created_via: 'signup',
    },
  });

  // Store mapping
  await db.users.update({ id: userId }, { stripeCustomerId: customer.id });
  return customer.id;
}

Customer rules:

  • Create at signup, not at first purchase
  • Always set metadata.user_id for reverse lookups
  • Store stripe_customer_id in your users table
  • Use customer email updates to sync — listen for customer.updated

Checkout Session (Recommended Starting Point)

// checkout.service.ts
async function createCheckoutSession(params: {
  customerId: string;
  priceId: string;
  mode: 'payment' | 'subscription';
  successUrl: string;
  cancelUrl: string;
  metadata?: Record<string, string>;
}) {
  const session = await stripe.checkout.sessions.create({
    customer: params.customerId,
    mode: params.mode,
    line_items: [{ price: params.priceId, quantity: 1 }],
    success_url: `${params.successUrl}?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: params.cancelUrl,
    metadata: params.metadata ?? {},

    // Recommended defaults
    allow_promotion_codes: true,
    billing_address_collection: 'auto',
    tax_id_collection: { enabled: true },
    customer_update: { address: 'auto', name: 'auto' },
    payment_method_types: ['card'],
    
    // For subscriptions
    ...(params.mode === 'subscription' && {
      subscription_data: {
        metadata: params.metadata ?? {},
        trial_period_days: 14,
      },
    }),
  }, {
    idempotencyKey: `checkout_${params.customerId}_${params.priceId}_${Date.now()}`,
  });

  return session;
}

Payment Element (Custom UI)

// Server: create PaymentIntent
async function createPaymentIntent(params: {
  customerId: string;
  amount: number;      // in cents!
  currency: string;
  metadata?: Record<string, string>;
}) {
  return stripe.paymentIntents.create({
    customer: params.customerId,
    amount: params.amount,
    currency: params.currency,
    automatic_payment_methods: { enabled: true },
    metadata: {
      ...params.metadata,
      created_at: new Date().toISOString(),
    },
  }, {
    idempotencyKey: `pi_${params.customerId}_${params.amount}_${Date.now()}`,
  });
}

// Client: React Payment Element
// <PaymentElement /> handles all payment method rendering
// Use confirmPayment() on form submit

Phase 3: Subscription Management

Subscription Lifecycle Events

Created → Active → Past Due → Canceled → (optionally) Unpaid
                ↓
            Trialing → Active
                ↓
            Paused → Resumed → Active

Critical Webhook Events for Subscriptions

| Event | Action | |-------|--------| | customer.subscription.created | Provision access, set plan in DB | | customer.subscription.updated | Handle plan changes, quantity updates | | customer.subscription.deleted | Revoke access, clean up | | customer.subscription.trial_will_end | Send conversion email (3 days before) | | invoice.payment_succeeded | Confirm access renewal | | invoice.payment_failed | Start dunning sequence | | customer.subscription.paused | Restrict access, retain data | | customer.subscription.resumed | Restore access |

Plan Change Patterns

// Upgrade (immediate)
async function upgradePlan(subscriptionId: string, newPriceId: string) {
  const sub = await stripe.subscriptions.retrieve(subscriptionId);
  return stripe.subscriptions.update(subscriptionId, {
    items: [{
      id: sub.items.data[0].id,
      price: newPriceId,
    }],
    proration_behavior: 'create_prorations',  // charge difference immediately
    payment_behavior: 'error_if_incomplete',
  });
}

// Downgrade (at period end)
async function downgradePlan(subscriptionId: string, newPriceId: string) {
  const sub = await stripe.subscriptions.retrieve(subscriptionId);
  return stripe.subscriptions.update(subscriptionId, {
    items: [{
      id: sub.items.data[0].id,
      price: newPriceId,
    }],
    proration_behavior: 'none',               // no refund, change at renewal
    billing_cycle_anchor: 'unchanged',
  });
}

// Cancel (at period end — always prefer this)
async function cancelSubscription(subscriptionId: string) {
  return stripe.subscriptions.update(subscriptionId, {
    cancel_at_period_end: true,
  });
  // User keeps access until period ends
  // Handle `customer.subscription.deleted` to revoke
}

Dunning (Failed Payment Recovery)

# Stripe Dashboard → Settings → Subscriptions → Smart Retries
retry_schedule:
  attempt_1: 1 day after failure    # Smart timing
  attempt_2: 3 days after failure
  attempt_3: 5 days after failure
  attempt_4: 7 days after failure   # Final attempt

# Custom dunning emails (supplement Stripe's built-in)
dunning_sequence:
  - day: 0
    action: "Email: payment failed, update card link"
    template: "Your payment of {amount} failed. Update → {portal_url}"
  - day: 3
    action: "Email: second notice, urgency"
    template: "Still unable to charge. Update payment to avoid interruption."
  - day: 5
    action: "Email: final warning"
    template: "Last chance to update. Access pauses in 48 hours."
  - day: 7
    action: "Pause or cancel subscription"
    note: "Automatic via Stripe if all retries fail"

Usage-Based Billing

// Report usage for metered billing
async function reportUsage(subscriptionItemId: string, quantity: number) {
  return stripe.subscriptionItems.createUsageRecord(subscriptionItemId, {
    quantity,
    timestamp: Math.floor(Date.now() / 1000),
    action: 'increment',  // or 'set' for absolute value
  }, {
    idempotencyKey: `usage_${subscriptionItemId}_${Date.now()}`,
  });
}

// Best practice: batch usage reports
// Don't report every API call individually — aggregate per hour/day
// Report at least daily to avoid surprise bills at period end

Phase 4: Webhooks (The Most Critical Part)

Webhook Handler Template

// webhooks.handler.ts
import { stripe } from './stripe.config';
import type { Request, Response } from 'express';

const WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!;

// Event handlers map
const handlers: Record<string, (event: Stripe.Event) => Promise<void>> = {
  'checkout.session.completed': handleCheckoutCompleted,
  'customer.subscription.created': handleSubscriptionCreated,
  'customer.subscription.updated': handleSubscriptionUpdated,
  'customer.subscription.deleted': handleSubscriptionDeleted,
  'invoice.payment_succeeded': handleInvoicePaymentSucceeded,
  'invoice.payment_failed': handleInvoicePaymentFailed,
  'customer.subscription.trial_will_end': handleTrialEnding,
  'payment_intent.succeeded': handlePaymentSucceeded,
  'payment_intent.payment_failed': handlePaymentFailed,
};

export async function handleWebhook(req: Request, res: Response) {
  // 1. Verify signature (NEVER skip this)
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body,        // raw body, not parsed JSON!
      req.headers['stripe-signature']!,
      WEBHOOK_SECRET,
    );
  } catch (err) {
    console.error('Webhook signature verification failed:', err);
    return res.status(400).send('Invalid signature');
  }

  // 2. Idempotency check
  const alreadyProcessed = await db.webhookEvents.findOne({ eventId: event.id });
  if (alreadyProcessed) {
    return res.status(200).json({ received: true, duplicate: true });
  }

  // 3. Route to handler
  const handler = handlers[event.type];
  if (handler) {
    try {
      await handler(event);
      await db.webhookEvents.insert({ eventId: event.id, type: event.type, processedAt: new Date() });
    } catch (err) {
      console.error(`Webhook handler failed for ${event.type}:`, err);
      return res.status(500).send('Handler error');  // Stripe will retry
    }
  }

  // 4. Always return 200 quickly
  res.status(200).json({ received: true });
}

10 Webhook Rules

  1. Verify every signature — never process unverified events
  2. Use raw body — don't parse JSON before verification (Express: express.raw({type: 'application/json'}))
  3. Idempotency — store processed event IDs, handle duplicates gracefully
  4. Return 200 fast — do heavy processing async/in background
  5. Handle out-of-order — events may arrive in unexpected order; check current state before applying
  6. Don't rely on event data alone — for critical actions, re-fetch the object from the API
  7. Log everything — event ID, type, relevant object IDs, processing result
  8. Monitor failures — alert on repeated 500s or unhandled event types
  9. Use CLI for local devstripe listen --forward-to localhost:3000/webhooks
  10. Register only events you handle — don't subscribe to everything

Essential Events by Use Case

| Use Case | Must-Have Events | |----------|-----------------| | One-time payments | checkout.session.completed, payment_intent.succeeded, payment_intent.payment_failed | | Subscriptions | All subscription.* + invoice.payment_succeeded, invoice.payment_failed, invoice.upcoming | | Marketplace/Connect | account.updated, payout.paid, payout.failed, transfer.created | | Invoicing | invoice.created, invoice.finalized, invoice.paid, invoice.payment_failed |


Phase 5: Customer Portal & Self-Service

// Customer portal — saves you building billing UI
async function createPortalSession(customerId: string, returnUrl: string) {
  return stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: returnUrl,
  });
}

// Configure in Dashboard → Settings → Customer portal
// Enable: Update payment method, Cancel subscription, View invoices
// Optional: Plan switching, Invoice history download

Portal Configuration Checklist

  • [ ] Payment method update enabled
  • [ ] Subscription cancellation with reason collection
  • [ ] Plan switching with proration preview
  • [ ] Invoice history visible
  • [ ] Business information (name, logo) set
  • [ ] Return URL configured
  • [ ] Terms of service / privacy policy linked

Phase 6: Tax Collection

Tax Decision Tree

Do you sell to EU customers?
  YES → Need VAT collection
    Use Stripe Tax (automatic) OR manual tax rates
  NO → 
Do you sell to US customers in multiple states?
  YES → Need sales tax (nexus rules)
    Use Stripe Tax (automatic) — manual is nightmare
  NO →
Do you exceed $100K revenue or 200 transactions in any US state?
  YES → You have economic nexus — collect tax
  NO → May not need to collect, but verify with accountant

Stripe Tax Setup

// Enable automatic tax on Checkout
const session = await stripe.checkout.sessions.create({
  // ... other config
  automatic_tax: { enabled: true },
  customer_update: { address: 'auto' },  // Required for tax calculation
});

// For subscriptions via API
const subscription = await stripe.subscriptions.create({
  customer: customerId,
  items: [{ price: priceId }],
  automatic_tax: { enabled: true },
});

Tax rules:

  • Stripe Tax handles calculation + collection automatically
  • You still need to file/remit taxes yourself (or use Stripe Tax filing in supported regions)
  • Always collect billing address for accurate tax calculation
  • Enable tax ID collection for B2B reverse charge (EU)

Phase 7: Stripe Connect (Marketplaces & Platforms)

Connect Account Types

| Type | Control | Onboarding | Best For | |------|---------|------------|----------| | Standard | Low (Stripe-hosted dashboard) | Stripe-hosted | Marketplaces where sellers manage their own Stripe | | Express | Medium (limited dashboard) | Stripe-hosted | Platforms managing payouts for contractors/sellers | | Custom | Full (you build everything) | You build it | Enterprise platforms needing total control |

Decision rule: Use Express unless you have a specific reason not to.

Payment Flow Patterns

// Direct charge (platform takes cut)
const paymentIntent = await stripe.paymentIntents.create({
  amount: 10000,  // $100
  currency: 'usd',
  application_fee_amount: 1500,  // $15 platform fee
  transfer_data: {
    destination: 'acct_seller123',
  },
});

// Destination charge (seller's Stripe processes)
// Same as above but payment appears on seller's statement

// Separate charges and transfers (most flexible)
const charge = await stripe.paymentIntents.create({
  amount: 10000,
  currency: 'usd',
});
// Then transfer to seller
const transfer = await stripe.transfers.create({
  amount: 8500,
  currency: 'usd',
  destination: 'acct_seller123',
  transfer_group: 'order_123',
});

Phase 8: Testing Strategy

Test Mode Checklist

| Test | How | Pass Criteria | |------|-----|--------------| | Successful payment | Card: 4242424242424242 | Checkout completes, webhook fires, DB updated | | Declined card | Card: 4000000000000002 | Error shown, no DB change | | 3D Secure required | Card: 4000002500003155 | Auth modal shown, completes after | | Insufficient funds | Card: 4000000000009995 | Graceful failure message | | Subscription create | Use test price, complete checkout | Sub active, access granted | | Payment failure + retry | Attach 4000000000000341, trigger invoice | Dunning sequence fires | | Webhook replay | stripe events resend evt_xxx | Idempotent — no duplicate processing | | Refund | Refund via API or Dashboard | Customer notified, access handled | | Upgrade/downgrade | Change plan mid-cycle | Proration correct | | Cancel at period end | Cancel, verify access until period end | Access maintained, then revoked |

Stripe CLI for Local Development

# Install
brew install stripe/stripe-cli/stripe

# Login
stripe login

# Forward webhooks to local server
stripe listen --forward-to localhost:3000/api/webhooks/stripe

# Trigger specific events for testing
stripe trigger checkout.session.completed
stripe trigger invoice.payment_failed
stripe trigger customer.subscription.deleted

Phase 9: Security & PCI Compliance

PCI Compliance Levels

| Level | Criteria | Requirement | |-------|----------|-------------| | SAQ-A | Checkout or Elements (recommended) | Annual questionnaire, no scan | | SAQ-A-EP | Client-side tokenization | Annual questionnaire + quarterly scan | | SAQ-D | Direct API card handling (avoid) | Full audit, quarterly scans, penetration tests |

Security Checklist (P0 — Mandatory)

  • [ ] API keys in environment variables, never in code
  • [ ] Webhook signatures verified on every request
  • [ ] Restricted API keys with minimum permissions
  • [ ] HTTPS everywhere (Stripe requires it)
  • [ ] No card numbers logged, stored, or transmitted
  • [ ] CSRF protection on payment endpoints
  • [ ] Rate limiting on checkout creation
  • [ ] Idempotency keys on all mutating calls

API Key Strategy

Live mode:
  sk_live_xxx    → Server only, env var, restricted permissions
  pk_live_xxx    → Client-side (public, safe to expose)
  whsec_xxx      → Webhook secret, server only

Test mode:
  sk_test_xxx    → Same restrictions as live
  pk_test_xxx    → Client-side
  whsec_test_xxx → Webhook secret (different from live!)

Restricted key permissions (create in Dashboard → API Keys):

  • Checkout Sessions: Write
  • Customers: Write
  • Subscriptions: Read/Write
  • Webhook Endpoints: Read
  • Everything else: None

Phase 10: Go-Live Checklist

Pre-Launch (P0 — Mandatory)

  • [ ] Webhook endpoint registered and verified in live mode
  • [ ] All webhook events subscribed (same as test)
  • [ ] Live API keys in production environment
  • [ ] Customer portal configured with live branding
  • [ ] Test a real $1 payment end-to-end (then refund)
  • [ ] Error handling for all payment states (success, failure, pending, requires_action)
  • [ ] Logging: payment ID, customer ID, amount, status on every transaction
  • [ ] PCI SAQ-A completed in Stripe Dashboard

Pre-Launch (P1 — Within First Week)

  • [ ] Monitoring: alert on payment failure rate > 5%
  • [ ] Monitoring: alert on webhook delivery failures
  • [ ] Receipt emails configured (Stripe auto-sends or custom)
  • [ ] Refund process documented
  • [ ] Dispute/chargeback response process
  • [ ] Dunning emails active for subscriptions
  • [ ] Stripe Tax enabled (if applicable)

Pre-Launch (P2 — Within First Month)

  • [ ] Revenue analytics dashboard
  • [ ] MRR/churn tracking
  • [ ] Coupon/promotion code strategy
  • [ ] Annual vs monthly pricing toggle
  • [ ] Customer portal self-service verified

Phase 11: Monitoring & Operations

Key Metrics Dashboard

metrics:
  payment_success_rate:
    calculation: "successful_payments / total_attempts × 100"
    healthy: ">= 95%"
    warning: "90-95%"
    critical: "< 90%"
    
  webhook_delivery_rate:
    calculation: "successful_deliveries / total_events × 100"  
    healthy: ">= 99.5%"
    critical: "< 99%"
    
  average_revenue_per_user:
    calculation: "total_revenue / active_customers"
    track: "weekly trend"
    
  monthly_recurring_revenue:
    calculation: "sum(active_subscription_amounts)"
    track: "monthly growth rate"
    
  churn_rate:
    calculation: "canceled_subscriptions / total_active × 100"
    healthy: "< 5% monthly"
    warning: "5-10%"
    critical: "> 10%"
    
  involuntary_churn:
    calculation: "failed_payment_cancellations / total_churn × 100"
    note: "Should be < 30% of total churn — fix with better dunning"

Weekly Review Checklist

  • [ ] Payment success rate vs last week
  • [ ] Failed payments — any patterns? (card type, region, amount)
  • [ ] Webhook failures — any endpoints timing out?
  • [ ] New disputes/chargebacks — respond within 7 days
  • [ ] Subscription metrics: new, churned, upgraded, downgraded
  • [ ] Revenue: MRR, net new MRR, expansion MRR, contraction MRR

Phase 12: Advanced Patterns

Pricing Page with Annual Toggle

// Create both monthly and annual prices for each plan
const prices = {
  starter: {
    monthly: 'price_starter_monthly',   // $29/mo
    annual: 'price_starter_annual',     // $290/yr (save ~17%)
  },
  pro: {
    monthly: 'price_pro_monthly',       // $79/mo
    annual: 'price_pro_annual',         // $790/yr
  },
};

// Client toggles monthly/annual → creates checkout with correct priceId

Grandfathering & Price Increases

// New price, existing customers keep old price
// 1. Create new price object (don't modify existing)
// 2. New signups use new price
// 3. Existing subs stay on old price until they change plans
// 4. Optional: scheduled price migration with notice

async function schedulePriceIncrease(subscriptionId: string, newPriceId: string, effectiveDate: Date) {
  // Create a subscription schedule
  const schedule = await stripe.subscriptionSchedules.create({
    from_subscription: subscriptionId,
  });
  
  // Add phase with new price
  await stripe.subscriptionSchedules.update(schedule.id, {
    phases: [
      { items: [{ price: currentPriceId }], end_date: Math.floor(effectiveDate.getTime() / 1000) },
      { items: [{ price: newPriceId }] },
    ],
  });
}

Coupon & Promotion Codes

// Create coupon (reusable)
const coupon = await stripe.coupons.create({
  percent_off: 20,
  duration: 'repeating',
  duration_in_months: 3,
  max_redemptions: 100,
  metadata: { campaign: 'launch_2024' },
});

// Create promotion code (shareable link)
const promoCode = await stripe.promotionCodes.create({
  coupon: coupon.id,
  code: 'LAUNCH20',
  max_redemptions: 50,
  expires_at: Math.floor(new Date('2024-12-31').getTime() / 1000),
});

Handling Disputes (Chargebacks)

dispute_response_process:
  when_received:
    - Log dispute details: amount, reason, deadline
    - Alert team immediately
    - Begin evidence collection within 24 hours
    
  evidence_to_collect:
    - Customer communication (emails, chat logs)
    - Delivery proof (access logs, download records)
    - Terms of service acceptance timestamp
    - Refund policy shown at checkout
    - IP address and device fingerprint
    - Prior successful transactions from same customer
    
  submit:
    - Within 7 days (Stripe deadline is usually 21 days, but act fast)
    - Use Stripe Dashboard evidence submission form
    - Include written rebuttal addressing specific reason code
    
  prevention:
    - Clear billing descriptor (customer recognizes charge)
    - Send receipt emails immediately
    - Offer easy refunds before disputes escalate
    - Use Radar for fraud detection

10 Common Mistakes

| # | Mistake | Fix | |---|---------|-----| | 1 | Trusting client-side redirect as payment confirmation | Always verify via webhook | | 2 | Parsing JSON body before webhook signature verification | Use raw body buffer | | 3 | No idempotency keys on API calls | Add to every mutating call | | 4 | Immediately canceling instead of cancel_at_period_end | Always cancel at period end unless refunding | | 5 | Amounts in dollars instead of cents | Stripe uses smallest currency unit (cents) | | 6 | Not handling 3D Secure / requires_action status | Check payment_intent.status, handle authentication | | 7 | Same webhook secret for test and live | Use separate secrets per environment | | 8 | Not testing with Stripe CLI locally | Set up stripe listen in development | | 9 | Hardcoding price IDs | Use config/env vars, different per environment | | 10 | No dunning strategy for failed subscription payments | Configure Smart Retries + custom emails |


Quality Rubric (0-100)

| Dimension | Weight | Criteria | |-----------|--------|----------| | Webhook reliability | 25% | Signature verification, idempotency, error handling, event coverage | | Security & PCI | 20% | SAQ-A compliance, key management, no card data exposure | | Subscription lifecycle | 15% | Create/upgrade/downgrade/cancel/pause all handled correctly | | Customer experience | 15% | Portal, receipts, dunning emails, clear error messages | | Testing coverage | 10% | All payment states tested, CLI setup, edge cases | | Monitoring | 10% | Failure alerts, revenue metrics, dispute tracking | | Code quality | 5% | TypeScript types, error handling, idempotency keys, logging |


Commands

The agent responds to these natural language requests:

  1. "Set up Stripe checkout" → Full Checkout integration with webhook handler
  2. "Add subscriptions" → Subscription lifecycle with plan changes and dunning
  3. "Configure webhooks" → Webhook handler with signature verification and idempotency
  4. "Set up customer portal" → Billing portal configuration
  5. "Add usage-based billing" → Metered subscription with usage reporting
  6. "Stripe security audit" → PCI compliance check + security hardening
  7. "Go-live checklist" → Pre-launch verification for production
  8. "Set up Stripe Connect" → Marketplace/platform payment flows
  9. "Add coupons and promos" → Promotion code system
  10. "Review payment metrics" → Revenue and payment health dashboard
  11. "Handle a dispute" → Chargeback response process
  12. "Migrate pricing" → Grandfathering and price increase strategy

API & Reliability

Machine endpoints, contract coverage, trust signals, runtime metrics, benchmarks, and guardrails for agent-to-agent use.

MissingCLAWHUB

Machine interfaces

Contract & API

Contract coverage

Status

missing

Auth

None

Streaming

No

Data region

Unspecified

Protocol support

OpenClaw: self-declared

Requires: none

Forbidden: none

Guardrails

Operational confidence: low

No positive guardrails captured.
Invocation examples
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/snapshot"
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/contract"
curl -s "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/trust"

Operational fit

Reliability & Benchmarks

Trust signals

Handshake

UNKNOWN

Confidence

unknown

Attempts 30d

unknown

Fallback rate

unknown

Runtime metrics

Observed P50

unknown

Observed P95

unknown

Rate limit

unknown

Estimated cost

unknown

Do not use if

Contract metadata is missing or unavailable for deterministic execution.
No benchmark suites or observed failure patterns are available.

Machine Appendix

Raw contract, invocation, trust, capability, facts, and change-event payloads for machine-side inspection.

MissingCLAWHUB

Contract JSON

{
  "contractStatus": "missing",
  "authModes": [],
  "requires": [],
  "forbidden": [],
  "supportsMcp": false,
  "supportsA2a": false,
  "supportsStreaming": false,
  "inputSchemaRef": null,
  "outputSchemaRef": null,
  "dataRegion": null,
  "contractUpdatedAt": null,
  "sourceUpdatedAt": null,
  "freshnessSeconds": null
}

Invocation Guide

{
  "preferredApi": {
    "snapshotUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/snapshot",
    "contractUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/contract",
    "trustUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/trust"
  },
  "curlExamples": [
    "curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/snapshot\"",
    "curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/contract\"",
    "curl -s \"https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/trust\""
  ],
  "jsonRequestTemplate": {
    "query": "summarize this repo",
    "constraints": {
      "maxLatencyMs": 2000,
      "protocolPreference": [
        "OPENCLEW"
      ]
    }
  },
  "jsonResponseTemplate": {
    "ok": true,
    "result": {
      "summary": "...",
      "confidence": 0.9
    },
    "meta": {
      "source": "CLAWHUB",
      "generatedAt": "2026-04-17T02:56:30.913Z"
    }
  },
  "retryPolicy": {
    "maxAttempts": 3,
    "backoffMs": [
      500,
      1500,
      3500
    ],
    "retryableConditions": [
      "HTTP_429",
      "HTTP_503",
      "NETWORK_TIMEOUT"
    ]
  }
}

Trust JSON

{
  "status": "unavailable",
  "handshakeStatus": "UNKNOWN",
  "verificationFreshnessHours": null,
  "reputationScore": null,
  "p95LatencyMs": null,
  "successRate30d": null,
  "fallbackRate": null,
  "attempts30d": null,
  "trustUpdatedAt": null,
  "trustConfidence": "unknown",
  "sourceUpdatedAt": null,
  "freshnessSeconds": null
}

Capability Matrix

{
  "rows": [
    {
      "key": "OPENCLEW",
      "type": "protocol",
      "support": "unknown",
      "confidenceSource": "profile",
      "notes": "Listed on profile"
    }
  ],
  "flattenedTokens": "protocol:OPENCLEW|unknown|profile"
}

Facts JSON

[
  {
    "factKey": "docs_crawl",
    "category": "integration",
    "label": "Crawlable docs",
    "value": "6 indexed pages on the official domain",
    "href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
    "sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
    "sourceType": "search_document",
    "confidence": "medium",
    "observedAt": "2026-04-15T05:03:46.393Z",
    "isPublic": true
  },
  {
    "factKey": "vendor",
    "category": "vendor",
    "label": "Vendor",
    "value": "Openclaw",
    "href": "https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-stripe-production",
    "sourceUrl": "https://github.com/openclaw/skills/tree/main/skills/1kalin/afrexai-stripe-production",
    "sourceType": "profile",
    "confidence": "medium",
    "observedAt": "2026-04-15T00:45:39.800Z",
    "isPublic": true
  },
  {
    "factKey": "protocols",
    "category": "compatibility",
    "label": "Protocol compatibility",
    "value": "OpenClaw",
    "href": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/contract",
    "sourceUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/contract",
    "sourceType": "contract",
    "confidence": "medium",
    "observedAt": "2026-04-15T00:45:39.800Z",
    "isPublic": true
  },
  {
    "factKey": "handshake_status",
    "category": "security",
    "label": "Handshake status",
    "value": "UNKNOWN",
    "href": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/trust",
    "sourceUrl": "https://xpersona.co/api/v1/agents/clawhub-skills-1kalin-afrexai-stripe-production/trust",
    "sourceType": "trust",
    "confidence": "medium",
    "observedAt": null,
    "isPublic": true
  }
]

Change Events JSON

[
  {
    "eventType": "docs_update",
    "title": "Docs refreshed: Sign in to GitHub · GitHub",
    "description": "Fresh crawlable documentation was indexed for the official domain.",
    "href": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
    "sourceUrl": "https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fskills%2Ftree%2Fmain%2Fskills%2Fasleep123%2Fcaldav-calendar",
    "sourceType": "search_document",
    "confidence": "medium",
    "observedAt": "2026-04-15T05:03:46.393Z",
    "isPublic": true
  }
]

Sponsored

Ads related to afrexai-stripe-production and adjacent AI workflows.