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}),],})exportclassAppModule{}
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()exportclassMyPaymentService{constructor(privatereadonlypaymentsService: PaymentsService){}asynccreatePayment(){constcommand: CreatePaymentCommand={gateway: 'paypal',// or 'stripe'amount: {amount: 1000,currency: 'USD'},metadata: {orderId: 'o_1'},};constresult=awaitthis.paymentsService.createPayment(command);if(result.nextAction?.type==='redirect'){// Redirect the user to PayPalconsole.log('Redirect to PayPal: ',result.nextAction.url);}elseif(result.nextAction?.type==='client_secret'){// Process Stripe payment with client_secretconsole.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.
constcommand={gateway: 'paypal',// or 'stripe'
## APIReference
### CoreMethods
#### `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: `stripelisten--forward-tolocalhost: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**: `Gatewaynotconfigured` 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()` configurationincludesthegateway---
## Performance-**AverageLatency**: 200-500msperpaymentoperation(dependsongatewayAPIresponsetime)-**WebhookProcessing**: <50msforsignatureverificationandeventnormalization-**MemoryFootprint**: ~15MBbase+gatewayclientoverhead---
## ContributingWewelcomecontributions!Pleasesee[CONTRIBUTING.md](./CONTRIBUTING.md)forguidelines.---
## ChangelogSee[CHANGELOG.md](./CHANGELOG.md)forversionhistoryandreleasenotes.---
## LicenseMITLicense-see[LICENSE](./LICENSE)fordetails.---
## Maintainer**ZaiidMoumni**([@TheVlpha](https://github.com/Zaiidmo))---
## Links-[Documentation](./docs)-[Examples](./examples)-[GitHubIssues](https://github.com/CISCODE-MA/PaymentKit/issues)-[npmPackage](https://www.npmjs.com/package/@ciscode/paymentkit)
## ChangelogThispackageusesautomatedchangeloggeneration.Allreleasesaretaggedanddocumentedinthechangelog.---
## KnownIssues&Limitations•Stripewebhooksignatureverification is notincludedinthispackage.Pleaseensureyourwebhookhandlingissecure.•OnlysupportsStripePaymentIntentflow,notCheckoutSessionsyet(we’lladdthisinfutureversions).---
## Maintainer[TheVlpha](https://gihub.com/Zaiidmo)