- β
Cloudflare Worker deployed:
https://pipilot-search-api.hanscadx8.workers.dev - β KV namespaces created and configured
- β Global quota management (95k/day with graceful degradation)
- β Rate limiting (per-user and global)
- β 3 endpoints: /search, /extract, /smart-search
- β CLI tool for manual key management
-
β Landing page (
/api)- Hero with value prop
- Live code examples
- Pricing table (4 tiers)
- Features showcase
- FAQ section
-
β Dashboard (
/dashboard/api)- Subscription status
- Usage quota display
- API key management (generate, view, revoke)
- Quick start guide
-
β Checkout flow (
/api/checkout)- Stripe Checkout integration
- Subscription creation
- β
/api/keys/generate- Generate API keys (stored in KV) - β
/api/keys/list- List user's keys (from KV) - β
/api/keys/revoke- Revoke keys (updates KV) - β
/api/subscription/current- Get subscription (from KV) - β
/api/stripe/create-checkout- Stripe checkout session
- β Starter: $29/mo (prod_U8KFiBzqU8sSFJ)
- β Pro: $149/mo (prod_U8KFSvIHon4TPZ)
- β Free tier (no Stripe product needed)
- β Enterprise (contact sales)
- β Search API added to Products dropdown
- β Shows as "AI search for your apps"
Add these to your .env.local or Vercel environment:
# Cloudflare (for KV access from Next.js API routes)
CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token
# Stripe
STRIPE_SECRET_KEY=sk_live_xxx # Use your Stripe secret key
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxx # Get from Stripe dashboard
# App URL
NEXT_PUBLIC_APP_URL=https://pipilot.dev # Or your current domainTo get Cloudflare Account ID:
- Go to Cloudflare dashboard
- Click on Workers & Pages
- Copy the Account ID from the right sidebar
Everything is stored in Cloudflare KV (no Supabase tables needed!):
// API Key
"{apiKey}": {
id, name, tier, userId, userEmail,
createdAt, totalRequests, lastUsedAt,
revoked, revokedAt, rateLimit
}
// User's keys list
"user:{userId}:keys": [apiKey1, apiKey2, ...]
// User's subscription (created on upgrade)
"user:{userId}:subscription": {
tier, status, stripeCustomerId,
stripeSubscriptionId, periodEnd
}
// Global quota (already working)
"global:quota:{YYYY-MM-DD}": usageCount
// Rate limit (already working)
"ratelimit:{key}:{hour}": requestCount- User visits
/api - Clicks "Get Started Free"
- Redirects to signup (if not logged in)
- After signup β Redirects to
/dashboard/api - User generates API key
- Key stored in KV:
user:{userId}:subscription = {tier: "free"} - User copies key and starts using API
- User visits
/api - Clicks "Upgrade to Starter/Pro"
- Redirects to signup (if not logged in)
- Redirects to
/api/checkout?plan=starter - Creates Stripe checkout session
- User completes payment
- Stripe webhook creates subscription in KV
- User redirected to
/dashboard/api?success=true - Auto-generated API key ready
- User starts using API
- Add environment variables to Vercel
- Test free tier signup flow
- Generate test API key
- Verify API key works with Worker
- Test paid tier checkout (use Stripe test mode first)
- Verify Stripe webhook creates subscription in KV
- Test quota tracking in dashboard
- Test key revocation
- Test rate limiting
- Add Stripe webhook handler (
/api/webhooks/stripe) - Add homepage announcement banner
- Add Search API section to
/docs - Send welcome email on first API key generation
- Add usage analytics dashboard
You need to create a Stripe webhook to handle subscription events:
File: app/api/webhooks/stripe/route.ts
import { NextRequest, NextResponse } from 'next/server'
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-12-18.acacia',
})
export async function POST(request: NextRequest) {
const body = await request.text()
const signature = request.headers.get('stripe-signature')!
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
)
} catch (err: any) {
return NextResponse.json({ error: err.message }, { status: 400 })
}
// Handle events
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session
const userId = session.metadata?.user_id
const tier = session.metadata?.tier
if (userId && tier) {
// Store subscription in KV
const subscriptionData = {
tier,
status: 'active',
stripeCustomerId: session.customer,
stripeSubscriptionId: session.subscription,
periodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
createdAt: new Date().toISOString()
}
// Store in KV via Cloudflare API
const kvUrl = `https://api.cloudflare.com/client/v4/accounts/${process.env.CLOUDFLARE_ACCOUNT_ID}/storage/kv/namespaces/e3b571cde10d48e38fdb107e0b9e2911/values/user:${userId}:subscription`
await fetch(kvUrl, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(subscriptionData)
})
// Auto-generate API key for paid users
// ... call /api/keys/generate internally
}
break
}
case 'customer.subscription.updated':
case 'customer.subscription.deleted':
// Update subscription status in KV
break
}
return NextResponse.json({ received: true })
}- Go to Stripe Dashboard β Developers β Webhooks
- Add endpoint:
https://pipilot.dev/api/webhooks/stripe - Select events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted
- Copy webhook signing secret
- Add to
.env.local:STRIPE_WEBHOOK_SECRET=whsec_xxx
Based on your pricing (10x cheaper than competitors):
- 100 users: 70 free, 20 starter, 8 pro, 2 enterprise
- MRR: $2,772 ($33k/year)
- 500 users: 350 free, 100 starter, 40 pro, 10 enterprise
- MRR: $13,860 ($166k/year)
- 1,000 users: 700 free, 200 starter, 80 pro, 20 enterprise
- MRR: $27,720 ($332k/year)
Once you:
- β Add environment variables
- β Create Stripe webhook
- β Test the flows
You're ready to:
- Announce on Twitter/X
- Post on ProductHunt
- Share on HackerNews
- Email existing PiPilot users
- Update homepage with banner
# 1. Sign up at pipilot.dev/api
# 2. Generate API key in dashboard
# 3. Start using:
curl -X POST https://pipilot-search-api.hanscadx8.workers.dev/search \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "AI news", "maxResults": 5, "rerank": true}'Built with β€οΈ by Hans Ade - Pixelways Solutions Inc
Live API: https://pipilot-search-api.hanscadx8.workers.dev
Landing Page: https://pipilot.dev/api (once deployed)
Dashboard: https://pipilot.dev/dashboard/api (once deployed)