Files
tenderpilot/BILLING_API_EXAMPLES.md

269 lines
6.9 KiB
Markdown
Raw Normal View History

# TenderRadar Billing API Examples
Quick reference for testing billing endpoints. Replace `AUTH_TOKEN` with a real JWT token from `/api/auth/login`.
## Setup
```bash
# 1. Register a user
curl -X POST http://localhost:3456/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "testpass123",
"company_name": "Test Corp"
}'
# Response includes: user object and JWT token
# Save the token for subsequent calls:
export AUTH_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```
## 1. Create Checkout Session
Start the subscription flow by creating a checkout session:
```bash
curl -X POST http://localhost:3456/api/billing/checkout \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-d '{
"plan": "starter",
"successUrl": "https://app.example.com/billing/success",
"cancelUrl": "https://app.example.com/billing/cancel"
}'
```
**Response:**
```json
{
"sessionId": "cs_test_abc123...",
"url": "https://checkout.stripe.com/pay/cs_test_abc123..."
}
```
**Next steps:**
1. Open the `url` in a browser
2. Complete the payment form (test card: 4242 4242 4242 4242)
3. User is redirected to `successUrl`
4. Stripe sends webhook to `/api/billing/webhook`
## 2. Get Subscription Status
Check the current subscription status (after completing checkout):
```bash
curl -X GET http://localhost:3456/api/billing/subscription \
-H "Authorization: Bearer $AUTH_TOKEN"
```
**Response (with active subscription):**
```json
{
"subscription": {
"id": 1,
"user_id": 5,
"stripe_customer_id": "cus_ABC123...",
"stripe_subscription_id": "sub_ABC123...",
"plan": "starter",
"status": "active",
"trial_start": "2026-02-14T12:49:00.000Z",
"trial_end": "2026-02-28T12:49:00.000Z",
"current_period_start": "2026-02-14T12:49:00.000Z",
"current_period_end": "2026-03-14T12:49:00.000Z",
"cancel_at_period_end": false,
"created_at": "2026-02-14T12:49:00.000Z",
"updated_at": "2026-02-14T12:49:00.000Z"
}
}
```
**Response (no subscription):**
```json
{
"subscription": null,
"message": "No active subscription. User is on free tier."
}
```
## 3. Create Customer Portal Session
Allow users to manage their subscription (upgrade, downgrade, cancel):
```bash
curl -X POST http://localhost:3456/api/billing/portal \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-d '{
"returnUrl": "https://app.example.com/account/billing"
}'
```
**Response:**
```json
{
"url": "https://billing.stripe.com/session/cs_test_abc123..."
}
```
**Usage:**
1. Open the `url` in a browser (user must be logged into Stripe or their payment method)
2. User can upgrade/downgrade plans, update payment method, or cancel
3. After managing subscription, redirected back to `returnUrl`
## Test Scenarios
### Scenario 1: New User Signup → Checkout
```bash
# 1. Register
TOKEN=$(curl -s -X POST http://localhost:3456/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "newuser@example.com",
"password": "pass123",
"company_name": "New Corp"
}' | jq -r '.token')
# 2. Create checkout session
curl -X POST http://localhost:3456/api/billing/checkout \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"plan": "growth",
"successUrl": "https://app.example.com/success",
"cancelUrl": "https://app.example.com/cancel"
}' | jq '.url'
# 3. Open URL in browser and complete payment
# (Use test card 4242 4242 4242 4242, any future expiry, any 3-digit CVC)
# 4. Check subscription status (after webhook processes)
curl -X GET http://localhost:3456/api/billing/subscription \
-H "Authorization: Bearer $TOKEN"
```
### Scenario 2: Upgrade Plan
```bash
# 1. User is on "starter" plan, wants to upgrade to "pro"
# 2. Create new checkout session (Stripe recognizes customer, handles proration)
curl -X POST http://localhost:3456/api/billing/checkout \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"plan": "pro",
"successUrl": "https://app.example.com/success",
"cancelUrl": "https://app.example.com/cancel"
}'
# 3. Complete payment
# 4. Webhook updates subscription to "pro" plan
```
### Scenario 3: Manage via Customer Portal
```bash
# User goes to billing page in app and clicks "Manage Subscription"
# Create portal session
curl -X POST http://localhost:3456/api/billing/portal \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"returnUrl": "https://app.example.com/account/billing"
}' | jq '.url'
# Open URL in browser
# User can downgrade, upgrade, or cancel without returning to app
```
## Testing with Stripe CLI (Local Webhooks)
To test webhooks locally without exposing your server:
```bash
# 1. Install Stripe CLI (if not already installed)
# macOS: brew install stripe/stripe-cli/stripe
# Linux/Windows: See https://stripe.com/docs/stripe-cli
# 2. Login to your Stripe account
stripe login
# 3. Start listening and forwarding to local server
stripe listen --forward-to localhost:3456/api/billing/webhook
# Output will show: Ready! Your webhook signing secret is: whsec_test_abc123...
# Update .env: STRIPE_WEBHOOK_SECRET=whsec_test_abc123...
# 4. In another terminal, trigger test events:
stripe trigger checkout.session.completed
# Webhook will be forwarded to localhost:3456/api/billing/webhook
```
## Test Cards
Stripe provides test cards for different scenarios:
| Card Number | Result | Expiry | CVC |
|---|---|---|---|
| 4242 4242 4242 4242 | Successful charge | Any future | Any 3 digits |
| 4000 0025 0000 3155 | Insufficient funds | Any future | Any 3 digits |
| 4000 0000 0000 0002 | Card declined | Any future | Any 3 digits |
| 4000 0000 0000 0010 | Address verification failed | Any future | Any 3 digits |
## Error Responses
### Missing Authorization Token
```bash
curl -X GET http://localhost:3456/api/billing/subscription
# Response:
{"error": "No token provided"}
```
### Invalid Plan
```bash
curl -X POST http://localhost:3456/api/billing/checkout \
-H "Authorization: Bearer $TOKEN" \
-d '{"plan": "invalid_plan", ...}'
# Response:
{"error": "Invalid plan: invalid_plan"}
```
### No Active Subscription
```bash
curl -X POST http://localhost:3456/api/billing/portal \
-H "Authorization: Bearer $TOKEN" \
-d '{"returnUrl": "..."}'
# Response (if user not subscribed):
{"error": "No subscription found for user"}
```
## Debugging
Check server logs for detailed webhook processing:
```bash
# Terminal running the server shows:
# Processing webhook event: checkout.session.completed
# Subscription created for user 5 on plan starter
```
Database query to check subscription status:
```bash
# Connect to PostgreSQL
psql -U tenderpilot -d tenderpilot -h localhost
# Check subscriptions
SELECT * FROM subscriptions WHERE user_id = 5;
# Check user tier
SELECT id, email, tier FROM users WHERE id = 5;
```