npm package: @reeboot/strapi-payment-plugin
Description: Handle payments
Author: Bastoun
Latest version: 0.0.13

# Strapi Payment Plugin

A comprehensive Stripe integration plugin for Strapi v5 that provides complete payment processing capabilities, customer management, order handling, subscription management, and webhook processing for modern e-commerce applications.

[![npm version](https://img.shields.io/npm/v/@reeboot/strapi-payment-plugin.svg)](https://www.npmjs.com/package/@reeboot/strapi-payment-plugin)
![Strapi](https://img.shields.io/badge/Strapi-v5.33.1-green.svg)
![Stripe](https://img.shields.io/badge/Stripe-v21-purple.svg)
![License](https://img.shields.io/badge/license-MIT-yellow.svg)

## Features

### Core Payment Processing
- **Payment Intent Creation & Management** - Secure payment processing with Stripe Payment Intents
- **Customer Management** - Create and manage Stripe customers with automatic Strapi synchronization
- **Order Processing** - Complete order lifecycle management with payment integration
- **Refund Processing** - Full and partial refund capabilities with audit trails
- **Subscription Management** - Create, update, and cancel recurring subscriptions via Stripe Billing
- **Webhook Handling** - Automatic webhook processing with signature verification

### Advanced Features
- **Real-time Payment Tracking** - Live payment status updates via webhooks
- **Admin Dashboard** - Comprehensive admin interface for payment management
- **Analytics & Reporting** - Payment analytics, revenue tracking, and customer insights
- **Multi-currency Support** - Support for multiple currencies and payment methods
- **Security First** - PCI-compliant payment handling with encrypted data storage

### Developer Experience
- **TypeScript Support** - Full TypeScript typing for all operations
- **RESTful API** - Clean, documented API endpoints following REST conventions
- **Rate Limiting** - Built-in rate limiting for sensitive operations
- **Error Handling** - Comprehensive error handling with detailed logging
- **Admin Interface** - Modern React-based admin panel with responsive design

## Prerequisites

- **Strapi v5.33.1+** - Latest Strapi v5 version
- **Node.js 20+** - Node.js runtime environment
- **Stripe Account** - Active Stripe account with API keys
- **Database** - PostgreSQL, MySQL, or SQLite database

## Installation

### Method 1: NPM Package (Recommended)

Install the plugin directly from npm:

```bash
npm install @reeboot/strapi-payment-plugin
# or
yarn add @reeboot/strapi-payment-plugin
```

Then configure the plugin in `config/plugins.ts`:

```typescript
export default () => ({
  'payment-plugin': {
    enabled: true,
    config: {
      stripe: {
        apiVersion: '2026-03-25.dahlia',
      },
      payment: {
        defaultCurrency: 'usd',
      },
    },
  },
});
```

### Method 2: Copy Plugin to Project

1. Copy the `payment-plugin` folder to your Strapi project's plugins directory:
   ```bash
   cp -r payment-plugin /path/to/your/strapi-project/src/plugins/
   ```

2. Install dependencies:
   ```bash
   npm install
   ```

3. Configure the plugin in `config/plugins.ts`:
   ```typescript
   export default () => ({
     'payment-plugin': {
       enabled: true,
       resolve: './src/plugins/payment-plugin',
       config: {
         stripe: {
           apiVersion: '2026-03-25.dahlia',
         },
         payment: {
           defaultCurrency: 'usd',
         },
       },
     },
   });
   ```

### Method 3: Development Setup

1. Navigate to the plugin directory:
   ```bash
   cd src/plugins/payment-plugin
   ```

2. Install dependencies:
   ```bash
   npm install
   ```

3. Build the plugin:
   ```bash
   npm run build
   ```

## Configuration

### Environment Variables

Add these to your `.env` file:

```env
# Stripe API Configuration
STRIPE_API_KEY=sk_test_... # Your Stripe secret key
STRIPE_WEBHOOK_SECRET=whsec_... # Your Stripe webhook endpoint secret

# Alternative configuration
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
```

### Plugin Configuration

Update `config/plugins.ts` with your settings:

```typescript
export default () => ({
  'payment-plugin': {
    enabled: true,
    resolve: './src/plugins/payment-plugin',
    config: {
      stripe: {
        apiVersion: '2026-03-25.dahlia',
        apiKey: process.env.STRIPE_API_KEY,
        webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
      },
      payment: {
        defaultCurrency: 'usd',
      },
      logging: {
        level: 'info',
        enableWebhookLogging: true,
        enableDebugLogging: false,
      },
    },
  },
});
```

### Webhook Raw Body Support (CRITICAL)

For Stripe webhook signature verification to work, you **must** configure Strapi's body parser middleware to preserve the raw request body.

Update `config/middlewares.ts` in your Strapi project:

```typescript
export default [
  // ... other middlewares
  {
    name: 'strapi::body',
    config: {
      includeUnparsed: true,
    },
  },
  // ... other middlewares
];
```

Without `includeUnparsed: true`, the webhook verification will fail with an error: "No signatures found matching the expected signature for payload".

## Quick Start

### 1. Create a Customer

```javascript
const customerData = {
  email: 'customer@example.com',
  firstName: 'John',
  lastName: 'Doe',
  phone: '+1234567890',
  address: {
    line1: '123 Main St',
    city: 'New York',
    postal_code: '10001'
  }
};

const response = await fetch('/api/payment-plugin/customers', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  },
  body: JSON.stringify(customerData)
});
```

### 2. Create a Payment Intent

```javascript
const paymentData = {
  amount: 2500, // $25.00 in cents
  currency: 'usd',
  customerId: 1, // Optional: Strapi customer ID
  orderId: 1,    // Optional: Strapi order ID
  metadata: {
    product_id: 'prod_123',
    subscription_type: 'premium'
  }
};

const response = await fetch('/api/payment-plugin/payments/create-intent', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  },
  body: JSON.stringify(paymentData)
});

const result = await response.json();
console.log(result.data.client_secret); // Use this for Stripe Elements
```

### 3. Handle Payment on Frontend

```javascript
import { loadStripe } from '@stripe/stripe-js';

const stripe = await loadStripe('pk_test_...');

const { error } = await stripe.confirmCardPayment(clientSecret, {
  payment_method: {
    card: cardElement,
    billing_details: {
      name: 'John Doe',
      email: 'john@example.com'
    }
  }
});

if (error) {
  console.error('Payment failed:', error);
} else {
  console.log('Payment succeeded!');
}
```

### 4. Create a Subscription

```javascript
const subscriptionData = {
  customerId: 1, // Strapi customer ID
  priceId: 'price_1234567890', // Stripe Price ID
  metadata: {
    plan: 'premium'
  }
};

const response = await fetch('/api/payment-plugin/subscriptions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  },
  body: JSON.stringify(subscriptionData)
});
```

### 5. Process a Refund

```javascript
const paymentId = 1; // Strapi payment ID

const refundData = {
  amount: 500, // Optional: partial refund in cents (omit for full refund)
  reason: 'requested_by_customer',
  metadata: {
    reason: 'customer_request'
  }
};

const response = await fetch(`/api/payment-plugin/payments/${paymentId}/refund`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  },
  body: JSON.stringify(refundData)
});
```

## API Documentation

The plugin provides comprehensive REST API endpoints:

### Content API Routes

#### Payments
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/payment-plugin/payments/create-intent` | Create a payment intent |
| `POST` | `/api/payment-plugin/payments/confirm/:paymentIntentId` | Confirm a payment |
| `GET` | `/api/payment-plugin/payments/:id` | Get payment details |
| `GET` | `/api/payment-plugin/payments` | List payments (supports `page`, `pageSize`, `status`, `customer`, `order` filters) |
| `POST` | `/api/payment-plugin/payments/:id/refund` | Process a refund |

#### Customers
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/payment-plugin/customers` | Create a customer |
| `GET` | `/api/payment-plugin/customers/:id` | Get customer details |
| `GET` | `/api/payment-plugin/customers` | List customers (supports `page`, `pageSize`, `email` filters) |

#### Orders
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/payment-plugin/orders` | Create an order |
| `GET` | `/api/payment-plugin/orders/:id` | Get order details |
| `GET` | `/api/payment-plugin/orders` | List orders (supports `page`, `pageSize`, `status`, `customer` filters) |

#### Subscriptions
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/payment-plugin/subscriptions` | Create a subscription |
| `GET` | `/api/payment-plugin/subscriptions` | List subscriptions |
| `GET` | `/api/payment-plugin/subscriptions/:id` | Get subscription details |
| `PUT` | `/api/payment-plugin/subscriptions/:id` | Update a subscription |
| `POST` | `/api/payment-plugin/subscriptions/:id/cancel` | Cancel a subscription |

#### Webhooks
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/api/payment-plugin/webhook` | Handle Stripe webhooks (no auth required) |

### Admin API Routes

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/admin/api/payment-plugin/admin/dashboard` | Dashboard data |
| `GET` | `/admin/api/payment-plugin/admin/reports` | Payment reports |
| `GET` | `/admin/api/payment-plugin/admin/analytics` | Analytics data |
| `GET` | `/admin/api/payment-plugin/admin/config` | Get plugin configuration |
| `PUT` | `/admin/api/payment-plugin/admin/config` | Update plugin configuration |
| `GET` | `/admin/api/payment-plugin/admin/payments` | List all payments |
| `POST` | `/admin/api/payment-plugin/admin/payments/:id/refund` | Admin refund |
| `GET` | `/admin/api/payment-plugin/admin/customers` | List all customers |
| `GET` | `/admin/api/payment-plugin/admin/orders` | List all orders |
| `GET` | `/admin/api/payment-plugin/admin/subscriptions` | List all subscriptions |
| `POST` | `/admin/api/payment-plugin/admin/subscriptions/:id/cancel` | Cancel a subscription |
| `POST` | `/admin/api/payment-plugin/admin/test-webhook` | Test webhook processing |
| `POST` | `/admin/api/payment-plugin/admin/initialize-payment` | Initialize a payment flow |
| `POST` | `/admin/api/payment-plugin/admin/create-sample-payment` | Create a sample payment |

For detailed API documentation with request/response examples, see [PAYMENT_ROUTES_DOCUMENTATION.md](./PAYMENT_ROUTES_DOCUMENTATION.md).

## Content Types

The plugin registers the following content types:

### Payment
| Field | Type | Description |
|-------|------|-------------|
| `stripe_payment_intent_id` | string (unique, required) | Links to Stripe payment intent |
| `amount` | decimal (min: 0) | Payment amount in cents |
| `currency` | string (default: "usd") | Currency code |
| `payment_status` | enum | `pending`, `succeeded`, `failed`, `canceled`, `refunded` |
| `payment_method` | string | Payment method used |
| `metadata` | json | Additional data |
| `customer` | relation (manyToOne) | Relation to Customer |
| `order` | relation (manyToOne) | Relation to Order |

### Customer
| Field | Type | Description |
|-------|------|-------------|
| `email` | email (unique, required) | Customer email |
| `stripe_customer_id` | string (unique, required) | Links to Stripe customer |
| `first_name` | string (required) | First name |
| `last_name` | string (required) | Last name |
| `phone` | string | Phone number |
| `address` | json | Address information |
| `metadata` | json | Additional data |

### Order
| Field | Type | Description |
|-------|------|-------------|
| `order_number` | string (unique, required) | Unique order identifier |
| `total_amount` | decimal (min: 0) | Order total in cents |
| `currency` | string (default: "usd") | Currency code |
| `order_status` | enum | `pending`, `processing`, `completed`, `failed`, `refunded` |
| `payment_status` | enum | `unpaid`, `paid`, `partially_paid`, `refunded` |
| `customer` | relation (manyToOne) | Relation to Customer |
| `items` | json (required) | Order line items |
| `metadata` | json | Additional data |

### Subscription
| Field | Type | Description |
|-------|------|-------------|
| `stripe_subscription_id` | string (unique, required) | Links to Stripe subscription |
| `stripe_customer_id` | string (required) | Stripe customer ID |
| `stripe_price_id` | string (required) | Stripe price ID |
| `stripe_product_id` | string | Stripe product ID |
| `status` | enum | `active`, `canceled`, `incomplete`, `incomplete_expired`, `past_due`, `paused`, `trialing`, `unpaid` |
| `current_period_start` | datetime | Start of current billing period |
| `current_period_end` | datetime | End of current billing period |
| `cancel_at_period_end` | boolean (default: false) | Cancel at period end |
| `canceled_at` | datetime | Cancellation timestamp |
| `trial_start` | datetime | Trial start date |
| `trial_end` | datetime | Trial end date |
| `latest_invoice_id` | string | Latest Stripe invoice ID |
| `metadata` | json | Additional data |
| `customer` | relation (manyToOne) | Relation to Customer |

## Webhook Events

The plugin processes these Stripe webhook events automatically:

| Event | Description |
|-------|-------------|
| `payment_intent.succeeded` | Payment completed successfully |
| `payment_intent.processing` | Payment is processing |
| `payment_intent.payment_failed` | Payment failed |
| `payment_intent.canceled` | Payment was canceled |
| `charge.refunded` | Charge was refunded |
| `customer.created` | New Stripe customer created |
| `customer.subscription.created` | Subscription created |
| `customer.subscription.updated` | Subscription updated |
| `customer.subscription.deleted` | Subscription canceled/deleted |
| `invoice.payment_succeeded` | Invoice payment succeeded |
| `invoice.payment_failed` | Invoice payment failed |

## Security

### Payment Security
- **PCI Compliance** - Stripe handles all sensitive payment data
- **Webhook Verification** - All webhooks are cryptographically verified using Stripe signatures
- **Audit Logging** - All payment operations are logged for compliance

### Access Control
- **JWT Authentication** - All content API endpoints require valid authentication
- **Admin Authentication** - Admin routes require authenticated admin users
- **Rate Limiting** - 10 requests per minute per IP for sensitive operations
- **Input Sanitization** - Built-in XSS protection and input validation

## Development

### Project Structure

```
src/plugins/payment-plugin/
├── admin/                 # Admin panel React components
│   └── src/
│       ├── components/    # UI components
│       ├── pages/         # Admin pages (Dashboard, Payments, Customers,
│       │                  #   Orders, Subscriptions, Analytics, Settings)
│       ├── types/         # TypeScript definitions
│       └── utils/         # Helper utilities
├── server/                # Server-side code
│   └── src/
│       ├── controllers/   # API controllers
│       ├── services/      # Business logic (Stripe service)
│       ├── routes/        # API route definitions
│       ├── content-types/ # Database schemas
│       ├── middlewares/   # Webhook validator, rate limiter, input sanitizer
│       ├── policies/      # Access control policies
│       └── types/         # Plugin configuration types
├── docs/                  # Documentation
├── package.json           # Plugin dependencies
└── README.md              # This file
```

### Building and Development

```bash
# Install dependencies
npm install

# Build for production
npm run build

# Watch for changes during development
npm run watch

# Verify plugin structure
npm run verify

# Type checking
npm run test:ts:front  # Frontend TypeScript
npm run test:ts:back   # Backend TypeScript
```

## Troubleshooting

### Common Issues

#### "Stripe API key not found"
- Ensure `STRIPE_API_KEY` or `STRIPE_SECRET_KEY` is set in your environment variables
- Check that the key starts with `sk_test_` (test) or `sk_live_` (live)
- Verify the key has the correct permissions

#### "Webhook signature verification fails"
- Ensure `STRIPE_WEBHOOK_SECRET` is configured
- Verify `includeUnparsed: true` is set in `config/middlewares.ts` for the `strapi::body` middleware
- Check that the webhook endpoint URL matches Stripe Dashboard configuration
- Ensure your webhook endpoint is publicly accessible

#### "Failed to create Strapi payment record"
- Ensure content types are properly registered
- Check database permissions and connectivity
- Verify all required fields are provided

### Debug Mode

Enable detailed logging:

```typescript
// config/plugins.ts
'payment-plugin': {
  config: {
    logging: {
      level: 'debug',
      enableWebhookLogging: true,
      enableDebugLogging: true,
    },
  },
},
```

## Documentation

Additional documentation is available in the `docs/` directory:

- [Installation Guide](./docs/INSTALLATION.md)
- [Configuration Guide](./docs/CONFIGURATION.md)
- [API Reference](./docs/API_RE)
- [Usage Guide](./docs/USAGE.md)
- [Security Guide](./docs/SECURITY.md)
- [Deployment Guide](./docs/DEPLOYMENT.md)

See also:
- [Stripe Service Documentation](./STRIPE_SERVICE_README.md) - Detailed service-level documentation
- [Payment Routes Documentation](./PAYMENT_ROUTES_DOCUMENTATION.md) - Complete API endpoint documentation
- [Changelog](./CHANGELOG.md) - Version history
- [Strapi v5 Migration Guide](./STRAPI_V5_MIGRATION_GUIDE.md)

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Submit a pull request

### Development Guidelines

- Follow TypeScript best practices
- Include unit tests for new features
- Update documentation for any API changes
- Follow the existing code style and formatting

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- [Strapi](https://strapi.io/) - The Headless CMS
- [Stripe](https://stripe.com/) - Payment processing
- [Stripe Elements](https://stripe.com/elements) - Payment UI components