Files
Kordant/docs/STRIPE_INTEGRATION.md

8.1 KiB

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:

# 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
  2. Navigate to DevelopersAPI 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 DevelopersWebhooks
  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

GET /api/v1/billing/subscription
Authorization: Bearer <JWT_TOKEN>

Response:

{
  "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

POST /api/v1/billing/subscription/create
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "tier": "basic",
  "customerId": "cus_123"
}

Update Subscription Tier

PUT /api/v1/billing/subscription/:subscriptionId/tier
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "tier": "plus"
}

Cancel Subscription

DELETE /api/v1/billing/subscription/:subscriptionId
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "cancelAtPeriodEnd": true
}

Get User Tier

GET /api/v1/billing/user/tier
Authorization: Bearer <JWT_TOKEN>

Response:

{
  "tier": "basic",
  "limits": {
    "callMinutesLimit": 500,
    "smsCountLimit": 2000,
    "darkWebScans": 12
  }
}

Create Customer Portal Session

POST /api/v1/billing/customer/portal
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json

{
  "customerId": "cus_123",
  "returnUrl": "https://yourapp.com/billing"
}

Response:

{
  "url": "https://billing.stripe.com/p/login/...",
  "expiresAt": "2026-05-14T14:00:00.000Z"
}

Get Invoice History

GET /api/v1/billing/invoices?customerId=cus_123
Authorization: Bearer <JWT_TOKEN>

Webhook Handler

Stripe Webhook

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
  2. Login: stripe login
  3. Forward webhooks: stripe listen --forward-to localhost:3000/api/v1/billing/webhooks/stripe

Test Events

# 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

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:

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: