more package declarations
This commit is contained in:
353
docs/STRIPE_INTEGRATION.md
Normal file
353
docs/STRIPE_INTEGRATION.md
Normal file
@@ -0,0 +1,353 @@
|
||||
# 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/
|
||||
Reference in New Issue
Block a user