Skip to content

Repository files navigation

@ciscode/PaymentKit

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.

npm versionLicense: MITTypeScript


Features

  • Unified API: Easy-to-integrate payment flow for Stripe and PayPal
  • Next Action Handling: Automatic routing for client-side actions (client_secret for 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

Architecture

PaymentKit implements a Modular architecture:

  1. PaymentKitModule: The central module for registering and wiring all payment logic.
  2. PaymentsService: The service used by the host app to manage the payment lifecycle.
  3. Gateways:
    • StripeGateway: Handles Stripe-specific payment flow.
    • PaypalGateway: Handles PayPal-specific payment flow.
  4. Webhook Handler: Automatically handles incoming webhooks from Stripe/PayPal and triggers the appropriate actions based on gateway events.
  5. Error Handling: Maps gateway-specific errors to a unified error structure.
  6. Next Action: Facilitates the next step of the payment process (either redirect URL or client secret for Stripe).

Install & Run

  1. Install the package: In your NestJS application, install PaymentKit via npm:

    npm install @ciscode/paymentkit@latest
  2. 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{}
  3. 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);}}}
  4. Start the app Start your NestJS app as usual:

    npm run start

Environment Variables

Set the following environment variables for gateway configuration:

Required Variables

# 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

Optional Variables

# 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-signature

Security Note: Never commit secrets to version control. Use environment variables or secret management services.


Usage Example

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&LimitationsStripewebhooksignatureverification is notincludedinthispackage.Pleaseensureyourwebhookhandlingissecure.OnlysupportsStripePaymentIntentflow,notCheckoutSessionsyet(we’lladdthisinfutureversions).---
## Maintainer[TheVlpha](https://gihub.com/Zaiidmo)

About

A unified PaymentPackage for NestJs apps, that handles simple configs of different gateways through one single config file

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages