ATOM Documentation

← Back to App

Stripe Setup Status & Recommendations

✅ What's Working Correctly

1. **Checkout Creation** (`/api/billing/checkout`)

  • ✅ Creates Stripe checkout sessions with proper metadata
  • ✅ Includes tenant_id in metadata for tracking
  • ✅ Uses idempotency keys to prevent duplicate sessions
  • ✅ Handles both subscription and trial charge ($1 verification) flows
  • ✅ Success URL: ${tenantBaseUrl}/settings?success=true
  • ✅ Cancel URL: ${tenantBaseUrl}/pricing

2. **Webhook Handlers**

  • ✅ **Backend**: /api/v1/stripe/webhook
  • ✅ **Frontend**: /api/webhooks/stripe
  • ✅ **Events handled**:
  • checkout.session.completed
  • customer.subscription.created/updated/deleted
  • invoice.paid
  • invoice.payment_failed
  • ✅ **Security**: Signature verification, tenant validation, duplicate protection

3. **Stripe Secrets (Fly.io)**

  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • ✅ All price IDs configured

---

⚠️ Issues Found

**Issue #1: Settings Page Doesn't Handle Success Parameter**

**Problem**: When Stripe redirects to /settings?success=true&trial=true, the page doesn't show a success message.

**Current code** (/app/settings/page.tsx):

export default function SettingsPage() {
    return (
        <div>
            <h2>Profile</h2>
            <p>Manage your profile settings here.</p>
        </div>
    );
}

**Fix**: Update to handle success/trial parameters:

'use client'

import { useSearchParams } from 'next/navigation'
import { useEffect } from 'react'
import { toast } from 'sonner'

export default function SettingsPage() {
    const searchParams = useSearchParams()

    useEffect(() => {
        const success = searchParams.get('success')
        const trial = searchParams.get('trial')

        if (success === 'true') {
            if (trial === 'true') {
                toast.success('🎉 Trial verified! Your workspace has been upgraded to the Team plan.')
            } else {
                toast.success('✅ Payment successful! Your subscription is now active.')
            }

            // Clear the URL parameters
            window.history.replaceState({}, '', '/settings')
        }
    }, [searchParams])

    return (
        <div>
            <h2 className="text-xl font-semibold mb-4">Settings</h2>
            <p>Manage your workspace settings here.</p>
        </div>
    )
}

---

**Issue #2: Missing Success URL Parameter for Stripe Dashboard**

The success URL should include {CHECKOUT_SESSION_ID} for verification:

**Current**:

success_url: `${tenantBaseUrl}/settings?success=true`

**Recommended**:

success_url: `${tenantBaseUrl}/settings?success=true&session_id={CHECKOUT_SESSION_ID}`

This allows you to verify the session in Stripe if needed.

---

**Issue #3: Price ID Validation**

**Status**: ✅ Validation exists but might be using placeholders

**Check your environment variables**:

# On Fly.io
fly secrets list -a atom-saas | grep STRIPE_PRICE

# Should show real price IDs like:
# STRIPE_PRICE_SOLO_MONTHLY = price_1Sn09eGHtIVNNi8sSVFY32U2
# STRIPE_PRICE_TEAM_MONTHLY = price_1SnJ2UGHtIVNNi8sUGQfPOm2
# STRIPE_PRICE_ENTERPRISE_MONTHLY = price_1SnJ8BGHtIVNNi8sCdtGwN25

**If still using placeholders**, update in Stripe Dashboard:

  1. Go to **Products** → Find your price
  2. Copy the **Price ID** (starts with price_)
  3. Set as environment variable

---

📋 Complete Stripe Flow

**Step 1: User Clicks Upgrade**

**Frontend** (/pricing/page.tsx):

const response = await fetch('/api/billing/checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        priceId: 'price_...',
        successUrl: `${window.location.origin}/settings?success=true&session_id={CHECKOUT_SESSION_ID}`
    }),
})
window.location.href = data.url // Redirects to Stripe Checkout

**Step 2: Stripe Checkout**

  • User enters payment details
  • Stripe processes payment
  • Stripe creates checkout.session.completed event

**Step 3: Webhook Processing**

**Backend** (/api/v1/stripe/webhook):

@router.post("/webhook")
async def stripe_webhook(request: Request):
    event = stripe.Webhook.construct_event(payload, signature, webhook_secret)

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        tenant_id = session['metadata']['tenant_id']

        # Update tenant plan
        # Update subscription_id
        # Send confirmation email

**Step 4: Success Redirect**

  • Stripe redirects to: https://atomagentos.com/settings?success=true
  • Settings page shows success toast
  • (Optional) Verify session with Stripe API

---

🔧 Required Actions

**1. Update Settings Page** (HIGH PRIORITY)

  • [ ] Add success/trial parameter handling
  • [ ] Show success toast message
  • [ ] Clear URL parameters after showing message

**2. Add Webhook to Stripe Dashboard** (CRITICAL)

**Webhook URL**: https://atomagentos.com/api/v1/stripe/webhook

**Events to select**:

  • [x] checkout.session.completed
  • [x] customer.subscription.created
  • [x] customer.subscription.updated
  • [x] customer.subscription.deleted
  • [x] invoice.paid
  • [x] invoice.payment_failed

**3. Verify Price IDs**

  • [ ] Check all price IDs are real (not placeholders)
  • [ ] Test checkout flow with real payment

**4. Test End-to-End**

  • [ ] Create test checkout session
  • [ ] Complete payment
  • [ ] Verify webhook fires
  • [ ] Check tenant plan updates
  • [ ] Verify success page appears

---

📝 Stripe Dashboard Configuration

**Webhook Settings**

  • **URL**: https://atomagentos.com/api/v1/stripe/webhook
  • **Events**: All 6 events listed above
  • **HTTP Method**: POST
  • **Signing Secret**: Already configured (STRIPE_WEBHOOK_SECRET)

**Product/Price Configuration**

PlanPrice ID Env VarAmountDescription
SoloSTRIPE_PRICE_SOLO_MONTHLY$19/moFor individuals
TeamSTRIPE_PRICE_TEAM_MONTHLY$79/moFor growing teams
EnterpriseSTRIPE_PRICE_ENTERPRISE_MONTHLY$299/moUnlimited

---

✅ Deployment Status

**Current Deployment**: ✅ Live on https://atomagentos.com

**Changes Deployed**:

  • ✅ ACU tracking for skill execution
  • ✅ Commit: 2b1934d3b
  • ✅ Pushed to GitHub
  • ✅ Deployed to Fly.io

---

🚀 Next Steps

  1. **Add webhook URL to Stripe Dashboard** (5 minutes)
  2. **Update settings page** to handle success parameter (15 minutes)
  3. **Test checkout flow** (10 minutes)
  4. **Verify webhook delivery** in logs

Need help with any of these?