PaymentKit is a flexible payment orchestration package for NestJS, designed to integrate Stripe and PayPal payment gateways with minimal configuration. This package simplifies the payment lifecycle while exposing a unified API for payment creation, status retrieval, refunds, and webhook handling.
- Unified API: Easy-to-integrate payment flow for Stripe and PayPal
- Next Action Handling: Automatic routing for client-side actions (
client_secretfor Stripe, redirect URL for PayPal) - Complete Webhook Support: Built-in webhook signature verification, event normalization, and routing for both gateways
- Type-Safe: Full TypeScript support with strict mode enabled
- Error Normalization: Gateway-specific errors mapped to unified error codes
- Idempotency & Retry Safe: Built-in idempotency key support for safe retries
- Hexagonal Architecture: Clean separation of concerns with ports & adapters pattern
- Production Ready: 85%+ test coverage with comprehensive unit tests
PaymentKit implements a Modular architecture:
- PaymentKitModule: The central module for registering and wiring all payment logic.
- PaymentsService: The service used by the host app to manage the payment lifecycle.
- Gateways:
- StripeGateway: Handles Stripe-specific payment flow.
- PaypalGateway: Handles PayPal-specific payment flow.
- Webhook Handler: Automatically handles incoming webhooks from Stripe/PayPal and triggers the appropriate actions based on gateway events.
- Error Handling: Maps gateway-specific errors to a unified error structure.
- Next Action: Facilitates the next step of the payment process (either redirect URL or client secret for Stripe).
-
Install the package: In your NestJS application, install PaymentKit via npm:
npm install @ciscode/paymentkit@latest
-
Configure the payment module: Import the PaymentKitModule in your AppModule and pass the necessary configuration (PayPal/Stripe).
import { Module } from '@nestjs/common'; import { PaymentKitModule } from '@ciscode/paymentkit'; @Module({ imports: [ PaymentKitModule.register({ environment: process.env.PAYMENTKIT_ENVIRONMENT ?? 'sandbox', gateways: { paypal: { enabled: true }, stripe: { enabled: true }, }, webhooks: { mode: 'internal' }, // Optionally set to 'external' if required }), ], }) export class AppModule {}
-
Create payment Use the PaymentsService to create a payment:
import { Injectable } from '@nestjs/common'; import { PaymentsService } from '@ciscode/paymentkit'; import { CreatePaymentCommand } from '@ciscode/paymentkit'; @Injectable() export class MyPaymentService { constructor(private readonly paymentsService: PaymentsService) {} async createPayment() { const command: CreatePaymentCommand = { gateway: 'paypal', // or 'stripe' amount: { amount: 1000, currency: 'USD' }, metadata: { orderId: 'o_1' }, }; const result = await this.paymentsService.createPayment(command); if (result.nextAction?.type === 'redirect') { // Redirect the user to PayPal console.log('Redirect to PayPal: ', result.nextAction.url); } else if (result.nextAction?.type === 'client_secret') { // Process Stripe payment with client_secret console.log('Stripe client secret: ', result.nextAction.clientSecret); } } }
-
Start the app Start your NestJS app as usual:
npm run start
Set the following environment variables for gateway configuration:
# Environment
PAYMENTKIT_ENVIRONMENT=sandbox # 'sandbox' or 'production'
PAYMENTKIT_DEFAULT_CURRENCY=USD # Default currency code
# Stripe Configuration
PAYMENTKIT_STRIPE_ENABLED=true
PAYMENTKIT_STRIPE_SECRET_KEY=sk_test_... # Use sk_live_... for production
PAYMENTKIT_STRIPE_WEBHOOK_SECRET=whsec_... # For webhook signature verification
# PayPal Configuration
PAYMENTKIT_PAYPAL_ENABLED=true
PAYMENTKIT_PAYPAL_CLIENT_ID=your-paypal-client-id
PAYMENTKIT_PAYPAL_SECRET=your-paypal-secret
PAYMENTKIT_PAYPAL_WEBHOOK_ID=your-webhook-id # For webhook verification# Webhook Configuration
PAYMENTKIT_WEBHOOK_MODE=internal # 'internal' (default) or 'external'
# Stripe Advanced
PAYMENTKIT_STRIPE_API_VERSION=2023-10-16 # Specific API version
# PayPal Advanced
PAYMENTKIT_PAYPAL_WEBHOOK_VERIFICATION_URL=https://api-m.paypal.com/v1/notifications/verify-webhook-signatureSecurity Note: Never commit secrets to version control. Use environment variables or secret management services.
This example creates a payment via PayPal or Stripe.
const command = {
gateway: 'paypal', // or 'stripe'
## API Reference
### Core Methods
#### `createPayment(command: CreatePaymentCommand): Promise<CreatePaymentResult>`
Creates a new payment through the specified gateway.
#### `getPaymentStatus(query: GetPaymentStatusQuery): Promise<GetPaymentStatusResult>`
Retrieves the current status of a payment.
#### `refundPayment(command: RefundPaymentCommand): Promise<RefundPaymentResult>`
Processes a full or partial refund for a completed payment.
See [examples](./examples) directory for detailed usage patterns.
---
## Security Best Practices
1. **Webhook Verification**: PaymentKit includes built-in HMAC signature verification for both Stripe and PayPal webhooks
2. **Secret Management**: Never hardcode API keys - use environment variables or secret managers
3. **HTTPS Only**: Always use HTTPS in production for webhook endpoints
4. **Idempotency Keys**: Use unique idempotency keys to prevent duplicate charges
5. **Error Handling**: Never expose raw gateway errors to end users - use the normalized error codes
---
## Troubleshooting
### Payment Creation Fails
**Problem**: `createPayment` returns an error
**Solutions**:
- Verify environment variables are correctly set
- Check gateway is enabled in configuration
- Ensure amount is in correct format (integer cents for Stripe, dollars for PayPal)
- Verify API keys are valid for the environment (test/production)
### Webhooks Not Working
**Problem**: Webhook events not being received or verified
**Solutions**:
- Confirm webhook secret is correctly set in environment variables
- For Stripe: Use Stripe CLI for local testing: `stripe listen --forward-to localhost:3000/webhooks/stripe`
- For PayPal: Ensure webhook ID is registered in PayPal developer dashboard
- Check webhook endpoint is publicly accessible (use ngrok for local testing)
- Verify webhook signature verification is not failing (check logs)
### Gateway Not Configured Error
**Problem**: `Gateway not configured` error when creating payments
**Solutions**:
- Ensure gateway is enabled: `PAYMENTKIT_STRIPE_ENABLED=true`
- Verify all required environment variables for the gateway are set
- Check `PaymentKitModule.register()` configuration includes the gateway
---
## Performance
- **Average Latency**: 200-500ms per payment operation (depends on gateway API response time)
- **Webhook Processing**: < 50ms for signature verification and event normalization
- **Memory Footprint**: ~15MB base + gateway client overhead
---
## Contributing
We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
---
## Changelog
See [CHANGELOG.md](./CHANGELOG.md) for version history and release notes.
---
## License
MIT License - see [LICENSE](./LICENSE) for details.
---
## Maintainer
**Zaiid Moumni** ([@TheVlpha](https://github.com/Zaiidmo))
---
## Links
- [Documentation](./docs)
- [Examples](./examples)
- [GitHub Issues](https://github.com/CISCODE-MA/PaymentKit/issues)
- [npm Package](https://www.npmjs.com/package/@ciscode/paymentkit)
## Changelog
This package uses automated changelog generation. All releases are tagged and documented in the changelog.
---
## Known Issues & Limitations
• Stripe webhook signature verification is not included in this package. Please ensure your webhook handling is secure.
• Only supports Stripe PaymentIntent flow, not Checkout Sessions yet (we’ll add this in future versions).
---
## Maintainer
[TheVlpha](https://gihub.com/Zaiidmo)