354 lines
8.1 KiB
Markdown
354 lines
8.1 KiB
Markdown
# Stripe Integration Guide
|
|
|
|
## Overview
|
|
|
|
This guide covers the Stripe live API integration for ShieldAI subscription management. The implementation includes webhook handlers, subscription management endpoints, and tier-based feature gating.
|
|
|
|
## Environment Variables
|
|
|
|
Add the following to your `.env` file:
|
|
|
|
```bash
|
|
# Stripe Configuration
|
|
STRIPE_API_KEY=sk_live_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
STRIPE_FREE_TIER_PRICE_ID=price_...
|
|
STRIPE_BASIC_TIER_PRICE_ID=price_...
|
|
STRIPE_PLUS_TIER_PRICE_ID=price_...
|
|
STRIPE_PREMIUM_TIER_PRICE_ID=price_...
|
|
```
|
|
|
|
## Getting Stripe Live API Keys
|
|
|
|
### 1. Get Live API Key
|
|
|
|
1. Go to [Stripe Dashboard](https://dashboard.stripe.com/)
|
|
2. Navigate to **Developers** → **API keys**
|
|
3. Toggle **Live mode** (top right corner)
|
|
4. Copy the **Secret key** (starts with `sk_live_`)
|
|
|
|
### 2. Get Webhook Signing Secret
|
|
|
|
1. In Stripe Dashboard, go to **Developers** → **Webhooks**
|
|
2. Click **Add endpoint**
|
|
3. Add your webhook URL: `https://your-api-domain.com/api/v1/billing/webhooks/stripe`
|
|
4. Select these events to listen for:
|
|
- `customer.subscription.created`
|
|
- `customer.subscription.updated`
|
|
- `customer.subscription.deleted`
|
|
- `invoice.payment_succeeded`
|
|
- `invoice.payment_failed`
|
|
5. Click **Add endpoint**
|
|
6. Copy the **Signing secret** (starts with `whsec_`)
|
|
|
|
### 3. Create Price IDs for Subscription Tiers
|
|
|
|
1. Go to **Products** in Stripe Dashboard
|
|
2. Create products for each tier:
|
|
- Free Tier ( $0/month)
|
|
- Basic Tier ($9.99/month)
|
|
- Plus Tier ($19.99/month)
|
|
- Premium Tier ($49.99/month)
|
|
3. For each product, create a recurring price
|
|
4. Copy the Price IDs (start with `price_`)
|
|
|
|
## API Endpoints
|
|
|
|
### Subscription Management
|
|
|
|
#### Get Current Subscription
|
|
```http
|
|
GET /api/v1/billing/subscription
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"subscription": {
|
|
"id": "sub_123",
|
|
"status": "active",
|
|
"currentPeriodStart": "2026-05-01T00:00:00.000Z",
|
|
"currentPeriodEnd": "2026-06-01T00:00:00.000Z",
|
|
"cancelAtPeriodEnd": false
|
|
},
|
|
"customer": {
|
|
"id": "cus_123"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Subscription
|
|
```http
|
|
POST /api/v1/billing/subscription/create
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"tier": "basic",
|
|
"customerId": "cus_123"
|
|
}
|
|
```
|
|
|
|
#### Update Subscription Tier
|
|
```http
|
|
PUT /api/v1/billing/subscription/:subscriptionId/tier
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"tier": "plus"
|
|
}
|
|
```
|
|
|
|
#### Cancel Subscription
|
|
```http
|
|
DELETE /api/v1/billing/subscription/:subscriptionId
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"cancelAtPeriodEnd": true
|
|
}
|
|
```
|
|
|
|
#### Get User Tier
|
|
```http
|
|
GET /api/v1/billing/user/tier
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"tier": "basic",
|
|
"limits": {
|
|
"callMinutesLimit": 500,
|
|
"smsCountLimit": 2000,
|
|
"darkWebScans": 12
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Customer Portal Session
|
|
```http
|
|
POST /api/v1/billing/customer/portal
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"customerId": "cus_123",
|
|
"returnUrl": "https://yourapp.com/billing"
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"url": "https://billing.stripe.com/p/login/...",
|
|
"expiresAt": "2026-05-14T14:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
#### Get Invoice History
|
|
```http
|
|
GET /api/v1/billing/invoices?customerId=cus_123
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
```
|
|
|
|
### Webhook Handler
|
|
|
|
#### Stripe Webhook
|
|
```http
|
|
POST /api/v1/billing/webhooks/stripe
|
|
Stripe-Signature: <SIGNATURE>
|
|
Content-Type: application/json
|
|
|
|
<Raw Stripe Event Body>
|
|
```
|
|
|
|
## Webhook Events Handled
|
|
|
|
### customer.subscription.created
|
|
Triggered when a new subscription is created.
|
|
|
|
### customer.subscription.updated
|
|
Triggered when subscription details change (tier upgrade/downgrade, payment method update).
|
|
|
|
### customer.subscription.deleted
|
|
Triggered when a subscription is cancelled.
|
|
|
|
### invoice.payment_succeeded
|
|
Triggered when a payment is successfully processed.
|
|
|
|
### invoice.payment_failed
|
|
Triggered when a payment fails.
|
|
|
|
## Testing
|
|
|
|
### Test with Stripe CLI
|
|
|
|
1. Install [Stripe CLI](https://stripe.com/docs/stripe-cli)
|
|
2. Login: `stripe login`
|
|
3. Forward webhooks: `stripe listen --forward-to localhost:3000/api/v1/billing/webhooks/stripe`
|
|
|
|
### Test Events
|
|
|
|
```bash
|
|
# Trigger a subscription created event
|
|
stripe trigger customer.subscription.created
|
|
|
|
# Trigger a payment succeeded event
|
|
stripe trigger invoice.payment_succeeded
|
|
```
|
|
|
|
## Mobile App Integration
|
|
|
|
### React Native Example
|
|
|
|
```javascript
|
|
import { API } from '@shieldai/api-client';
|
|
|
|
// Get current subscription
|
|
const getSubscription = async () => {
|
|
try {
|
|
const response = await API.get('/billing/subscription');
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to fetch subscription:', error);
|
|
}
|
|
};
|
|
|
|
// Create subscription
|
|
const createSubscription = async (tier, customerId) => {
|
|
try {
|
|
const response = await API.post('/billing/subscription/create', {
|
|
tier,
|
|
customerId,
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to create subscription:', error);
|
|
}
|
|
};
|
|
|
|
// Upgrade subscription
|
|
const upgradeSubscription = async (subscriptionId, newTier) => {
|
|
try {
|
|
const response = await API.put(
|
|
`/billing/subscription/${subscriptionId}/tier`,
|
|
{ tier: newTier }
|
|
);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to upgrade subscription:', error);
|
|
}
|
|
};
|
|
|
|
// Cancel subscription
|
|
const cancelSubscription = async (subscriptionId) => {
|
|
try {
|
|
const response = await API.delete(
|
|
`/billing/subscription/${subscriptionId}`,
|
|
{ data: { cancelAtPeriodEnd: true } }
|
|
);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('Failed to cancel subscription:', error);
|
|
}
|
|
};
|
|
```
|
|
|
|
## Feature Gating
|
|
|
|
Use the middleware to protect routes based on subscription tier:
|
|
|
|
```typescript
|
|
import { requireTier } from '@shieldai/shared-billing';
|
|
import { SubscriptionTier } from '@shieldai/shared-billing';
|
|
|
|
// Require minimum tier
|
|
fastify.get(
|
|
'/premium-feature',
|
|
{
|
|
preHandler: requireTier([SubscriptionTier.BASIC, SubscriptionTier.PLUS, SubscriptionTier.PREMIUM])
|
|
},
|
|
async (request, reply) => {
|
|
// Only accessible to BASIC tier and above
|
|
}
|
|
);
|
|
|
|
// Require specific tier
|
|
fastify.get(
|
|
'/exclusive-feature',
|
|
{
|
|
preHandler: requireTier([SubscriptionTier.PREMIUM])
|
|
},
|
|
async (request, reply) => {
|
|
// Only accessible to PREMIUM tier
|
|
}
|
|
);
|
|
```
|
|
|
|
## Deployment Checklist
|
|
|
|
- [ ] Set `STRIPE_API_KEY` to live key (not test key)
|
|
- [ ] Set `STRIPE_WEBHOOK_SECRET` to live webhook secret
|
|
- [ ] Configure webhook endpoint in Stripe Dashboard
|
|
- [ ] Verify webhook events are being received
|
|
- [ ] Test subscription creation flow
|
|
- [ ] Test tier upgrade/downgrade flow
|
|
- [ ] Test cancellation flow
|
|
- [ ] Verify feature gating works correctly
|
|
- [ ] Monitor Stripe dashboard for errors
|
|
- [ ] Set up alerts for failed payments
|
|
|
|
## Production Considerations
|
|
|
|
### Security
|
|
|
|
1. **Never expose secret keys** in client-side code
|
|
2. **Always verify webhook signatures** on the server
|
|
3. **Use HTTPS** for all API endpoints in production
|
|
4. **Implement rate limiting** on webhook endpoints
|
|
|
|
### Error Handling
|
|
|
|
1. **Idempotency**: Webhook events may be delivered multiple times
|
|
2. **Retry logic**: Stripe will retry failed webhook deliveries
|
|
3. **Logging**: Log all webhook events for debugging
|
|
4. **Alerts**: Set up alerts for payment failures
|
|
|
|
### Compliance
|
|
|
|
1. **PCI DSS**: Use Stripe Elements for payment collection
|
|
2. **GDPR**: Handle customer data according to regulations
|
|
3. **Tax**: Consider tax calculation for different regions
|
|
|
|
## Troubleshooting
|
|
|
|
### Webhook Signature Verification Fails
|
|
|
|
- Ensure `STRIPE_WEBHOOK_SECRET` is correctly set
|
|
- Verify the webhook URL matches what's configured in Stripe
|
|
- Check that raw body is being captured (not parsed JSON)
|
|
|
|
### Subscription Creation Fails
|
|
|
|
- Verify `STRIPE_API_KEY` is valid
|
|
- Check that price IDs exist and are active
|
|
- Ensure customer ID is valid
|
|
|
|
### Tier Not Updating
|
|
|
|
- Verify the new tier's price ID exists
|
|
- Check for active subscriptions on the customer
|
|
- Review Stripe dashboard for error messages
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
- Stripe Dashboard: https://dashboard.stripe.com/
|
|
- Stripe Docs: https://stripe.com/docs
|
|
- Stripe Support: https://support.stripe.com/
|