more package declarations

This commit is contained in:
2026-05-17 21:52:38 -04:00
parent a8a5930ced
commit f118d3a4f3
44 changed files with 14019 additions and 1918 deletions

View File

@@ -0,0 +1,389 @@
# Push Notifications - Mobile App Quick Start
This guide helps you integrate push notifications into the ShieldAI React Native mobile app.
## Prerequisites
Before starting, ensure:
- ✅ Backend push notification infrastructure is deployed
- ✅ Firebase project is set up (for Android)
- ✅ Apple Developer account is active (for iOS)
- ✅ Environment variables are configured on the backend
## Step 1: Install Dependencies
```bash
npm install @react-native-firebase/app @react-native-firebase/messaging
```
## Step 2: Android Setup
### 2.1 Add Firebase to Android Project
1. Go to [Firebase Console](https://console.firebase.google.com)
2. Select your ShieldAI project
3. Add Android app with package name: `com.shieldai.mobile`
4. Download `google-services.json`
5. Place it in `android/app/google-services.json`
### 2.2 Update Build Configuration
In `android/build.gradle`:
```gradle
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
```
In `android/app/build.gradle`:
```gradle
apply plugin: 'com.google.gms.google-services'
```
### 2.3 Request Permissions
In `AndroidManifest.xml`:
```xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
```
## Step 3: iOS Setup
### 3.1 Enable Push Notifications
1. Open Xcode project
2. Select your app target
3. Go to "Signing & Capabilities"
4. Click "+ Capability"
5. Add "Push Notifications"
6. Add "Background Modes" and check "Remote notifications"
### 3.2 Configure Firebase
1. Download `GoogleService-Info.plist` from Firebase Console
2. Add it to your Xcode project (drag to project folder)
3. Ensure "Copy items if needed" is checked
### 3.3 Add Import in AppDelegate.swift
```swift
import FirebaseMessaging
import UserNotifications
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self
return true
}
// Request permission
func requestAuthorization() {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { granted, error in
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
)
}
// Handle token refresh
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("FCM token refreshed: \(fcmToken)")
// Send new token to backend
registerDeviceToken(fcmToken)
}
// Handle foreground notifications
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
print("Foreground notification: \(userInfo)")
completionHandler([.banner, .sound, .badge])
}
// Handle notification tap
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print("Notification tapped: \(userInfo)")
completionHandler()
}
}
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("FCM token received: \(fcmToken ?? "none")")
if let token = fcmToken {
registerDeviceToken(token)
}
}
}
// Helper function to register with backend
func registerDeviceToken(_ token: String) {
// Call your API to register the device
// POST /api/v1/devices/register
// Body: { userId, platform: "ios", token, deviceType: "mobile" }
}
```
## Step 4: React Native Integration
### 4.1 Create Notification Service
Create `src/services/NotificationService.ts`:
```typescript
import messaging from '@react-native-firebase/messaging';
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios from 'axios';
const API_BASE_URL = 'https://api.shieldai.com/api/v1';
export class NotificationService {
private static instance: NotificationService;
private userId: string | null = null;
private constructor() {}
static getInstance(): NotificationService {
if (!NotificationService.instance) {
NotificationService.instance = new NotificationService();
}
return NotificationService.instance;
}
setUserId(userId: string) {
this.userId = userId;
}
async requestPermission(): Promise<boolean> {
try {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push notification permission granted');
await this.registerDevice();
return true;
}
return false;
} catch (error) {
console.error('Failed to request permission:', error);
return false;
}
}
async registerDevice(): Promise<void> {
if (!this.userId) {
console.warn('User ID not set, cannot register device');
return;
}
try {
const token = await messaging().getToken();
const platform = Platform.OS === 'ios' ? 'ios' : 'android';
const response = await axios.post(`${API_BASE_URL}/devices/register`, {
userId: this.userId,
platform,
token,
deviceType: 'mobile',
appName: 'ShieldAI Mobile',
appVersion: '1.0.0',
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
setupListeners() {
// Foreground messages
messaging().onMessage(async (remoteMessage) => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
this.showLocalNotification(remoteMessage);
});
// Background messages
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Background message received:', remoteMessage);
});
// Notification opened
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log('Notification opened app:', remoteMessage);
// Navigate to relevant screen
this.handleNotificationTap(remoteMessage);
});
// Check if app was opened from notification
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
console.log('App opened from notification:', remoteMessage);
this.handleNotificationTap(remoteMessage);
}
});
}
private showLocalNotification(message: any) {
// Use react-native-push-notification or similar
console.log('Show notification:', message.notification?.title);
}
private handleNotificationTap(message: any) {
// Navigate to relevant screen based on notification data
const { alertId, type } = message.data || {};
if (alertId) {
// Navigate to alert detail
console.log('Navigate to alert:', alertId);
}
}
async deregisterDevice(): Promise<void> {
if (!this.userId) return;
try {
const token = await messaging().getToken();
await axios.post(`${API_BASE_URL}/devices/deregister`, {
token,
userId: this.userId,
});
} catch (error) {
console.error('Failed to deregister device:', error);
}
}
}
```
### 4.2 Initialize in App Component
```typescript
// App.tsx
import React, { useEffect } from 'react';
import { NotificationService } from './src/services/NotificationService';
const notificationService = NotificationService.getInstance();
function App() {
useEffect(() => {
// Initialize push notifications
notificationService.setupListeners();
}, []);
// When user logs in
const handleLogin = async (userId: string) => {
notificationService.setUserId(userId);
await notificationService.requestPermission();
};
// When user logs out
const handleLogout = async () => {
await notificationService.deregisterDevice();
notificationService.setUserId('');
};
return (
// Your app components
);
}
```
## Step 5: Testing
### Android Emulator
1. Start Android emulator with Google Play Services
2. Install and run app
3. Trigger a test notification from backend
4. Check notification appears
### iOS Device (Required)
iOS Simulator does not support push notifications. Use a real device.
### Backend Test
```bash
# Test notification API
curl -X POST https://api.shieldai.com/api/v1/notifications/send \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-uuid",
"channel": "push",
"subject": "Test Alert",
"body": "This is a test notification from ShieldAI",
"priority": "high",
"metadata": {
"alertId": "alert-uuid",
"type": "darkweb_exposure"
}
}'
```
## Troubleshooting
### Android Issues
**Problem**: Token not received
- Check `google-services.json` is in correct location
- Verify Firebase project ID matches
- Check internet connection on emulator
**Problem**: Notifications not showing
- Ensure notification permissions granted
- Check battery optimization settings
- Verify notification channel is created
### iOS Issues
**Problem**: Token not received
- Verify Push Notifications capability is enabled
- Check APNs key configuration in backend
- Ensure device is not in development mode if using production certs
**Problem**: Notifications not showing
- Check notification permissions granted
- Verify APNs configuration on backend
- Ensure proper certificate/key is used
## Next Steps
1. ✅ Set up Firebase project
2. ✅ Configure APNs on Apple Developer Portal
3. ✅ Implement notification handling in app
4. ✅ Test on Android device/emulator
5. ✅ Test on iOS device
6. ✅ Integrate with DarkWatch and SpamShield alerts
7. ✅ Add notification preferences UI
8. ✅ Implement deep linking from notifications
## Resources
- [Firebase Cloud Messaging Docs](https://firebase.google.com/docs/cloud-messaging)
- [React Native Firebase Messaging](https://rnfirebase.io/messaging/usage)
- [Apple Push Notification Service](https://developer.apple.com/documentation/usernotifications)

View File

@@ -0,0 +1,462 @@
# Push Notifications Setup Guide (FCM & APNs)
## Overview
This guide covers setting up Firebase Cloud Messaging (FCM) for Android and Apple Push Notification service (APNs) for iOS push notifications in the ShieldAI mobile app.
## Architecture
```
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Mobile │────▶│ API Gateway │────▶│ Notification │
│ App │ │ /devices/* │ │ Service │
└─────────────┘ └──────────────────┘ └────────┬────────┘
┌──────────────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Firebase │ │ Apple Push │ │ Redis (Rate │
│ Cloud │ │ Notification │ │ Limiting) │
│ Messaging │ │ Service │ │ │
│ (Android) │ │ (iOS) │ │ │
└────────────────┘ └─────────────────┘ └──────────────────┘
```
## Environment Variables
Add the following to your `.env` file:
```bash
# Firebase Cloud Messaging (FCM)
FCM_PROJECT_ID=your-firebase-project-id
FCM_CLIENT_EMAIL=service-account@your-project.iam.gserviceaccount.com
FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Apple Push Notification (APNs)
APNS_KEY_ID=your-key-id
APNS_TEAM_ID=your-team-id
APNS_BUNDLE_ID=com.yourcompany.shieldai
APNS_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Redis (for rate limiting)
REDIS_URL=redis://localhost:6379
# Rate Limits
PUSH_RATE_LIMIT=100
RATE_LIMIT_WINDOW_SECONDS=60
```
## Firebase Cloud Messaging (FCM) Setup
### 1. Create Firebase Project
1. Go to [Firebase Console](https://console.firebase.google.com/)
2. Click **Add project**
3. Enter project name: `shieldai-production` (or your preferred name)
4. Disable Google Analytics (optional)
5. Click **Create project**
### 2. Enable Cloud Messaging
1. In Firebase Console, go to **Project settings**
2. Scroll down to **Your apps** section
3. Click the **Web** icon `</>` to add a web app
4. Register app nickname: `ShieldAI API`
5. **Do not** check "Also set up for Firebase Hosting"
6. Click **Register app**
7. Copy the `firebaseConfig` for later use in mobile app
### 3. Generate Service Account Key
1. Go to **Project settings****Service accounts**
2. Click **Generate new private key**
3. Save the downloaded JSON file securely
4. Extract the following values:
- `project_id`
- `client_email`
- `private_key`
### 4. Configure FCM in ShieldAI
Create a file `packages/shared-notifications/.fcm-config.json` (gitignored):
```json
{
"projectId": "your-firebase-project-id",
"clientEmail": "service-account@your-project.iam.gserviceaccount.com",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
}
```
Set environment variables:
```bash
export FCM_PROJECT_ID="your-firebase-project-id"
export FCM_CLIENT_EMAIL="service-account@your-project.iam.gserviceaccount.com"
export FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
```
### 5. Install Firebase Admin SDK
```bash
cd packages/shared-notifications
npm install firebase-admin
```
## Apple Push Notification (APNs) Setup
### 1. Create App ID
1. Go to [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/list)
2. Click **+** to create new identifier
3. Select **App IDs****App**
4. Enter description: `ShieldAI Mobile`
5. Enter Bundle ID: `com.yourcompany.shieldai`
6. Enable **Push Notifications** capability
7. Click **Continue****Register**
### 2. Create APNs Key
1. Go to **Certificates, IDs & Profiles****Keys**
2. Click **+** to create new key
3. Enter key name: `ShieldAI APNs Key`
4. Enable **Apple Push Notification service (APNs)**
5. Click **Continue****Register**
6. **Download the key** (`.p8` file) - you can only download once!
7. Note the **Key ID** displayed
### 3. Configure APNs in ShieldAI
Convert the `.p8` file to PEM format:
```bash
# Convert .p8 to PEM
openssl pkcs8 -topk8 -nocrypt -in AuthKey_XXXXXX.p8 -out apns_key.pem
# Copy the PEM content
cat apns_key.pem
```
Set environment variables:
```bash
export APNS_KEY_ID="XXXXXX"
export APNS_TEAM_ID="YYYYYY"
export APNS_BUNDLE_ID="com.yourcompany.shieldai"
export APNS_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
```
### 4. Configure in Xcode
In your iOS app's `Info.plist`:
```xml
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
```
Enable capabilities in Xcode:
- **Push Notifications**
- **Background Modes** → **Remote notifications**
## API Endpoints
### Device Registration
#### Register Device
```http
POST /api/v1/devices/register
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"platform": "android",
"fcmToken": "eXwR9...",
"appVersion": "1.0.0",
"osVersion": "Android 13"
}
```
Response:
```json
{
"success": true,
"device": {
"deviceId": "dev_1234567890_abc123",
"platform": "android",
"registeredAt": "2026-05-14T13:00:00.000Z"
},
"message": "Device registered successfully"
}
```
#### Update Device Tokens
```http
PUT /api/v1/devices/:deviceId/tokens
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"fcmToken": "new-token-here",
"apnsToken": "new-token-here"
}
```
#### Get Registered Devices
```http
GET /api/v1/devices
Authorization: Bearer <JWT_TOKEN>
```
#### Deregister Device
```http
DELETE /api/v1/devices/:deviceId
Authorization: Bearer <JWT_TOKEN>
```
## Mobile App Integration
### Android (React Native)
```javascript
import messaging from '@react-native-firebase/messaging';
import { API } from '@shieldai/api-client';
// Request permission
async function requestPushPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push permission granted:', authStatus);
}
}
// Get FCM token
async function getFCMToken() {
const token = await messaging().getToken();
return token;
}
// Register device with API
async function registerDevice() {
try {
const fcmToken = await getFCMToken();
const response = await API.post('/devices/register', {
platform: 'android',
fcmToken,
appVersion: '1.0.0',
osVersion: Platform.OS + ' ' + Platform.Version,
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
// Listen for token refresh
messaging().onTokenRefresh(async (newToken) => {
await API.put('/devices/tokens', {
fcmToken: newToken,
});
});
// Handle foreground messages
messaging().onMessage(async (remoteMessage) => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
});
// Handle background messages
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Background message received:', remoteMessage);
});
```
### iOS (React Native)
```javascript
import messaging from '@react-native-firebase/messaging';
import { API } from '@shieldai/api-client';
// Request permission
async function requestPushPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Push permission granted:', authStatus);
}
}
// Get APNs token
async function getAPNSToken() {
const token = await messaging().getToken();
return token;
}
// Register device with API
async function registerDevice() {
try {
const apnsToken = await getAPNSToken();
const response = await API.post('/devices/register', {
platform: 'ios',
apnsToken,
appVersion: '1.0.0',
osVersion: Platform.OS + ' ' + Platform.Version,
});
console.log('Device registered:', response.data);
} catch (error) {
console.error('Failed to register device:', error);
}
}
// Handle foreground messages
messaging().onMessage(async (remoteMessage => {
console.log('Foreground message received:', remoteMessage);
// Show local notification
}));
```
## Testing Push Notifications
### Test with Firebase Console
1. Go to [Firebase Console](https://console.firebase.google.com/) → **Cloud Messaging**
2. Click **Send your first message**
3. Enter notification title and body
4. Choose test device or all users
5. Click **Send test message**
### Test with API
```bash
# Send test push notification
curl -X POST https://your-api.com/api/v1/notifications/send \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"channel": "push",
"title": "Test Notification",
"body": "This is a test push notification",
"data": {
"type": "test",
"action": "open_app"
}
}'
```
### Test with cURL (Direct FCM)
```bash
curl -X POST https://fcm.googleapis.com/v1/projects/your-project-id/messages:send \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"message": {
"token": "FCM_TOKEN_HERE",
"notification": {
"title": "Test Title",
"body": "Test Body"
},
"data": {
"type": "test"
}
}
}'
```
## Production Checklist
### FCM Configuration
- [ ] Firebase project created
- [ ] Service account key generated and stored securely
- [ ] FCM environment variables configured
- [ ] Firebase Admin SDK initialized
- [ ] Test notifications sent successfully
### APNs Configuration
- [ ] App ID created with push capability
- [ ] APNs key generated and downloaded
- [ ] Key converted to PEM format
- [ ] APNs environment variables configured
- [ ] Xcode capabilities enabled
- [ ] Test notifications sent from simulator
### API Configuration
- [ ] Device registration endpoints working
- [ ] Token update endpoints working
- [ ] Rate limiting configured
- [ ] Error handling implemented
- [ ] Logging for push notifications
### Mobile App Configuration
- [ ] Push permissions requested
- [ ] Token retrieval implemented
- [ ] Device registration on app start
- [ ] Token refresh handling
- [ ] Foreground message handling
- [ ] Background message handling
- [ ] Notification display implemented
## Troubleshooting
### FCM Token Not Received
- Check Firebase configuration in mobile app
- Verify Google Services (Android) / GoogleService-Info.plist (iOS)
- Ensure push permissions granted
### APNs Token Not Received
- Verify App ID configuration in Apple Developer
- Check APNs key configuration
- Ensure background modes enabled in Xcode
- Test on actual device (not simulator)
### Notifications Not Delivering
- Check device registration status
- Verify tokens are valid
- Check rate limiting status
- Review server logs for errors
### Token Refresh Issues
- Listen for `onTokenRefresh` events
- Update tokens via API immediately
- Handle network errors gracefully
## Security Considerations
1. **Never expose service account keys** in client-side code
2. **Always validate** device ownership on server
3. **Use HTTPS** for all API calls
4. **Implement rate limiting** to prevent abuse
5. **Store tokens securely** using secure storage libraries
6. **Deregister devices** on user logout
## Monitoring
Monitor the following metrics:
- Push notification delivery rate
- Token refresh frequency
- Device registration failures
- Rate limit hits
- Notification open rate
## Support
- Firebase Support: https://firebase.google.com/support
- Apple Developer Support: https://developer.apple.com/contact/
- FCM Documentation: https://firebase.google.com/docs/cloud-messaging
- APNs Documentation: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server

353
docs/STRIPE_INTEGRATION.md Normal file
View 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/