npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@biorbank/moon-sdk

v0.1.6

Published

TypeScript SDK for Moon's Card Issuing API

Readme

Moon Card Issuing SDK for TypeScript

A comprehensive TypeScript SDK for Moon's Card Issuing API, providing type-safe access to card management, transaction processing, and crypto funding capabilities.

Features

  • 🔒 Type Safe - Full TypeScript support with auto-generated types
  • 🏗️ Modular - Clean resource-based architecture
  • Modern - Built with async/await and ES modules
  • 🛡️ Robust - Comprehensive error handling and retries
  • 🔄 Auto Retry - Smart retry logic for transient failures
  • 📖 Well Documented - Complete JSDoc documentation
  • 🛡️ PCI DSS Compliant - Automatic card data masking and secure handling
  • 🔐 Webhook Security - HMAC signature validation and replay protection
  • JIT Authorization - Sub-second response with rate limiting
  • 🔑 API Key Management - Rotation tracking and security monitoring
  • 📋 Secure Logging - Environment-aware sensitive data filtering
  • 🔍 Audit Framework - Comprehensive security event tracking
  • 🔓 Sensitive Data Access - Controlled access to unredacted card data for legitimate business use

⚠️ Important: Sensitive Data Access

Version 0.1.4+ includes fixed sensitive data access methods that properly return unredacted card data:

  • getUnredactedPAN() - Returns actual PAN (not masked)
  • getUnredactedCVV() - Returns actual CVV (not redacted)
  • getUnredactedPIN() - Returns actual PIN (not masked)
  • getAllSensitiveData() - Returns all unredacted data

These methods now bypass automatic sanitization and return the raw data from the Moon API as intended. Use with extreme caution and proper authorization controls.

Installation

npm install moon-card-issuing-sdk
# or
yarn add moon-card-issuing-sdk

Setup

Quick Setup (Recommended)

Use our automated setup script to get started quickly:

# Create .env file and generate secure webhook secret
npm run setup

# This will:
# 1. Copy .env.example to .env
# 2. Generate a cryptographically secure webhook secret
# 3. Show you what values to edit

Manual Setup

1. Environment Configuration

Copy the example environment file and configure your settings:

cp .env.example .env

Edit .env with your actual values:

# Required: Your Moon API key
MOON_API_KEY=your_actual_moon_api_key_here

# Required for webhooks: Secure webhook secret (16+ characters)
MOON_WEBHOOK_SECRET=your_cryptographically_secure_webhook_secret

# Environment (staging or production)
NODE_ENV=staging

2. Generate Secure Webhook Secret

For webhook security, generate a cryptographically secure secret:

# Use our built-in generator
npm run setup:webhook-secret

# Or generate manually with OpenSSL
openssl rand -hex 32

# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

3. API Key Security

  • Staging: Use test API keys (may start with pk_test_)
  • Production: Use live API keys (may start with pk_live_)
  • Never: Commit API keys to version control
  • Rotate: Change keys regularly (monthly recommended)

4. Run Security Checks

Validate your setup with security checks:

# Run type checking and security validation
npm run security:check

# View security documentation
npm run security:docs

Quick Start

import { MoonClient } from 'moon-card-issuing-sdk';

const moon = new MoonClient({
  apiKey: 'your-api-key',
  environment: 'staging' // or 'production'
});

// Create a card
const card = await moon.cards.create('card-product-id', {
  amount: 100,
  card_type: 'VIRTUAL'
});

// Add balance
await moon.cards.addBalance(card.id, 50);

// Get transactions
const transactions = await moon.cards.getTransactions(card.id);

Configuration

Client Options

const moon = new MoonClient({
  apiKey: 'your-api-key',           // Required: Your Moon API key
  environment: 'staging',           // 'staging' | 'production' 
  baseURL: 'custom-url',           // Optional: Override base URL
  timeout: 30000,                  // Optional: Request timeout (ms)
  retryOptions: {                  // Optional: Retry configuration
    retries: 3,
    retryDelay: 1000,
    retryCondition: (error) => true
  }
});

Environment URLs

  • Staging: https://stagingapi.paywithmoon.com
  • Production: https://api.paywithmoon.com

API Reference

Cards Resource

Create Card

const card = await moon.cards.create(cardProductId, {
  amount?: number,
  card_type?: 'VIRTUAL' | 'PHYSICAL',
  card_currency?: 'USD' | 'MXN',
  end_customer_id?: string
});

Get Card

const card = await moon.cards.get(cardId);

List Cards

const cards = await moon.cards.list({
  currentPage: 1,
  perPage: 10,
  end_customer_id?: string,
  include_inactive_cards?: boolean
});

Add Balance

const updatedCard = await moon.cards.addBalance(cardId, amount);

Card Management

// Freeze/unfreeze
await moon.cards.freeze(cardId, true);  // freeze
await moon.cards.freeze(cardId, false); // unfreeze

// Activate
await moon.cards.activate(cardId);

// PIN management
const pin = await moon.cards.getPin(cardId);
await moon.cards.updatePin(cardId, '1234');

// CVV access (always redacted for PCI DSS compliance)
const cvv = await moon.cards.getCvv(cardId); // Returns { cvv: "***" }

// ⚠️ SENSITIVE DATA ACCESS - Use with extreme caution!
// These methods return UNREDACTED sensitive data for legitimate business use
// All access is heavily logged and monitored

// Get actual PAN (unredacted)
const { pan } = await moon.cards.getUnredactedPAN(cardId); // Returns actual PAN

// Get actual CVV (unredacted) 
const { cvv } = await moon.cards.getUnredactedCVV(cardId); // Returns actual CVV

// Get actual PIN (unredacted)
const { pin } = await moon.cards.getUnredactedPIN(cardId); // Returns actual PIN

// Get all sensitive data at once (maximum security risk)
const sensitiveData = await moon.cards.getAllSensitiveData(cardId);
// Returns: { pan, cvv, pin, expiration, display_expiration, support_token }

// Assign cardholder
await moon.cards.assignCardholder(cardId, externalId);

Transactions

// Get transactions
const transactions = await moon.cards.getTransactions(cardId, {
  currentPage: 1,
  perPage: 20
});

// Simulate transaction (sandbox only)
await moon.cards.simulateTransaction(cardId, {
  transactionAmount: 25.00,
  transactionCurrency: 'USD',
  transactionType: 'AUTHORIZATION',
  merchantName: 'Test Store',
  merchantCountryCode: 'US'
});

Card Products

const products = await moon.cards.getCardProducts({
  currentPage: 1,
  perPage: 10
});

Webhooks Resource

Register Webhook

// Register a webhook endpoint
await moon.webhooks.register({
  url: 'https://your-app.com/webhooks/moon'
});

// Validate webhook URL before registration
const validation = moon.webhooks.validateWebhookUrl('https://your-app.com/webhooks/moon');
if (!validation.isValid) {
  console.error('Invalid webhook URL:', validation.error);
}

Delete Webhook

// Delete registered webhook
await moon.webhooks.delete();

Complete Webhook Integration

import { MoonClient, createWebhookMiddleware, createWebhookConfig } from 'moon-card-issuing-sdk';
import express from 'express';

const moon = new MoonClient({
  apiKey: 'your-api-key',
  environment: 'staging'
});

const app = express();

// 1. Register webhook endpoint
await moon.webhooks.register({
  url: 'https://your-app.com/webhooks/moon'
});

// 2. Set up webhook handler with security validation
const config = createWebhookConfig(process.env.MOON_WEBHOOK_SECRET!);

app.post('/webhooks/moon', 
  createWebhookMiddleware(config, async (payload) => {
    console.log('Secure webhook received:', payload.type);
    
    // Handle different event types
    switch (payload.type) {
      case 'CARD_TRANSACTION':
        // Handle card transaction
        break;
      case 'CARD_DECLINE':
        // Handle declined transaction
        break;
      case 'MOON_CREDIT_FUNDS_CREDITED':
        // Handle funds credited
        break;
    }
  })
);

Gift Cards Resource

Purchase Gift Card

// Purchase a gift card
const giftCard = await moon.giftCards.purchase({
  card_product_id: 'product-id',
  amount: '50.00'
});

// Validate purchase amount before buying
const product = await moon.giftCards.getProducts();
const validation = moon.giftCards.validatePurchaseAmount(product.data[0], 50);
if (!validation.isValid) {
  console.error('Invalid amount:', validation.error);
}

Get Gift Card Details

// Get gift card by ID (returns masked sensitive data)
const giftCard = await moon.giftCards.get('gift-card-id');
console.log('Gift card value:', giftCard.value);
console.log('Barcode:', giftCard.barcode);
// PIN and security code are masked for security: "***"

Manage Gift Card Usage

// Mark as used
await moon.giftCards.markAsUsed('gift-card-id');

// Mark as unused
await moon.giftCards.markAsUnused('gift-card-id');

// Custom usage status
await moon.giftCards.updateUsageStatus('gift-card-id', {
  marked_used: true
});

Browse Gift Card Products

// Get all available products
const products = await moon.giftCards.getProducts({
  currentPage: 1,
  perPage: 10
});

// Filter by category
const retailProducts = await moon.giftCards.getProductsByCategory('retail');

// Filter by merchant
const amazonCards = await moon.giftCards.getProductsByMerchant('Amazon');

Calculate Costs

// Calculate total cost including fees and discounts
const product = products.data[0];
const calculation = moon.giftCards.calculateTotalCost(product, 100);

console.log('Gift card amount:', calculation.giftCardAmount);
console.log('Fee amount:', calculation.feeAmount);
console.log('Total cost:', calculation.totalCost);
console.log('Final amount (after discount):', calculation.finalAmount);

Cardholders Resource

Create and Manage Cardholders

// Create a new cardholder
const cardholder = await moon.cardholders.create({
  email: '[email protected]',
  external_id: 'EMP-12345',
  organization_id: 'org-id'
});

// Get cardholder by ID
const cardholder = await moon.cardholders.get('cardholder-id');

// Update cardholder information
const updatedCardholder = await moon.cardholders.update('cardholder-id', {
  external_id: 'NEW-EMP-67890'
});

List and Search Cardholders

// List all cardholders with pagination
const cardholders = await moon.cardholders.list({
  currentPage: 1,
  perPage: 10,
  organization_id: 'org-id'
});

// Find cardholders by external ID
const found = await moon.cardholders.findByExternalId('EMP-12345');

// Find cardholders by email
const byEmail = await moon.cardholders.findByEmail('[email protected]');

Two-Factor Authentication

// Step 1: Request login code
await moon.cardholders.requestLoginCode({
  email: '[email protected]',
  organization_id: 'org-id'
});

// Step 2: Redeem code for token
const session = await moon.cardholders.redeemLoginCode({
  email: '[email protected]',
  code: '123456',
  organization_id: 'org-id'
});

// Use the JWT token for authenticated requests
console.log('Token:', session.token);
console.log('Expires:', session.expiresAt);

// Complete authentication flow with convenience method
const auth = await moon.cardholders.authenticate(
  '[email protected]',
  'org-id',
  async () => {
    // This function should prompt user for the 6-digit code
    // and return it (e.g., from a form input)
    return prompt('Enter the 6-digit code from your email:') || '';
  }
);

Cardholder-Card Associations

// Get all cards for a cardholder
const cards = await moon.cardholders.getCards('cardholder-id', {
  currentPage: 1,
  perPage: 10,
  include_inactive_cards: false
});

// Check if cardholder has active cards
const hasCards = await moon.cardholders.hasActiveCards('cardholder-id');

// Get total card count
const cardCount = await moon.cardholders.getCardCount('cardholder-id', true);

Utility Methods

// Update external ID
await moon.cardholders.updateExternalId('cardholder-id', 'NEW-ID-123');

// Move to different organization
await moon.cardholders.moveToOrganization('cardholder-id', 'new-org-id');

// Update KYC status
await moon.cardholders.updateKYCStatus('cardholder-id', true);

Error Handling

The SDK provides specific error types for different scenarios:

import { 
  MoonError, 
  MoonAPIError, 
  MoonNetworkError,
  MoonValidationError,
  MoonRateLimitError,
  MoonAuthenticationError,
  MoonNotFoundError
} from 'moon-card-issuing-sdk';

try {
  const card = await moon.cards.get('invalid-id');
} catch (error) {
  if (error instanceof MoonNotFoundError) {
    console.log('Card not found');
  } else if (error instanceof MoonAuthenticationError) {
    console.log('Invalid API key');
  } else if (error instanceof MoonRateLimitError) {
    console.log('Rate limited, retry after:', error.retryAfter);
  } else if (error instanceof MoonAPIError) {
    console.log('API error:', error.status, error.message);
  }
}

TypeScript Support

The SDK is fully typed with auto-generated interfaces:

import { Card, Transaction, CardProduct } from 'moon-card-issuing-sdk';

// All responses are properly typed
const card: Card = await moon.cards.get('card-id');
const transactions: PaginatedResponse<Transaction> = await moon.cards.getTransactions('card-id');

Pagination

List methods return paginated responses:

interface PaginatedResponse<T> {
  data: T[];
  pagination: {
    currentPage: number;
    from: number;
    lastPage: number;
    perPage: number;
    total: number;
  };
}

Development

Building

npm run build          # Build for production
npm run dev           # Build in watch mode

Testing

npm test              # Run tests
npm run test:watch    # Run tests in watch mode

Type Generation

npm run generate-types # Regenerate types from API schemas

Examples

Check the examples directory for complete usage examples:

Running Examples

Use the built-in npm scripts to run examples easily:

# Run basic card management example
npm run example:basic

# Run complete security integration example (includes webhook server)
npm run example:secure

# Run webhook management example
npm run example:webhooks

# Run gift card management example
npm run example:gift-cards

# Run CVV access example with security compliance
npm run example:cvv

# Run sensitive data access example (⚠️ UNREDACTED data)
npm run example:sensitive

Make sure to configure your .env file first with:

npm run setup

🛡️ Security Features

This SDK implements comprehensive security measures for production use:

PCI DSS Compliance

  • Default Security: Automatic card data masking (PAN shows only last 4 digits)
  • CVV Protection: CVV always redacted in standard responses
  • PIN Protection: PIN never shown in production environment
  • Secure Logging: No sensitive data in standard logs

⚠️ Sensitive Data Access

For legitimate business operations, the SDK provides secure access to unredacted sensitive data:

Standard (Secure) Methods

// These methods return REDACTED/MASKED data for safety
const card = await moon.cards.get(cardId);         // PAN: ****1234
const cvv = await moon.cards.getCvv(cardId);       // CVV: ***
const pin = await moon.cards.getPin(cardId);       // PIN: [REDACTED]

Sensitive Data Access Methods

// ⚠️ These methods return ACTUAL unredacted data - use with extreme caution!
const { pan } = await moon.cards.getUnredactedPAN(cardId);  // Actual PAN
const { cvv } = await moon.cards.getUnredactedCVV(cardId);  // Actual CVV  
const { pin } = await moon.cards.getUnredactedPIN(cardId);  // Actual PIN

// Maximum risk: Get all sensitive data at once
const all = await moon.cards.getAllSensitiveData(cardId);   // All unredacted

Security Measures for Sensitive Access

  • Heavy Audit Logging: All access logged with [CRITICAL-AUDIT] tags
  • Environment Tracking: Logs include environment information
  • Timestamp Recording: Precise access time tracking
  • Card ID Masking: Even audit logs mask card identifiers
  • Access Warnings: Clear warnings about data sensitivity

Implementation Details

The sensitive data access methods use existing Moon API endpoints:

  • PAN & CVV: Retrieved from the regular card endpoint (/v1/api-gateway/card/{id})
  • PIN: Retrieved from the dedicated PIN endpoint (/v1/api-gateway/card/{id}/pin)
  • All Data: Combines multiple endpoint calls for comprehensive access

This approach ensures compatibility with the actual Moon API while maintaining security logging and audit trails.

⚠️ CRITICAL SECURITY WARNING

The sensitive data access methods (getUnredactedPAN, getUnredactedCVV, getUnredactedPIN, getAllSensitiveData) return ACTUAL UNREDACTED sensitive data. This represents a maximum security risk and should only be used for legitimate business purposes.

Before using these methods:

  1. Ensure you have proper authorization/permissions
  2. Implement additional authentication (2FA, biometric, etc.)
  3. Use environment-based access controls
  4. Never log the returned sensitive values
  5. Clear sensitive data from memory after use
  6. Monitor and audit all access attempts
  7. Consider if you truly need unredacted data vs. masked data

Webhook Security

  • HMAC-SHA256 signature validation
  • Replay attack protection with timestamp validation
  • Automatic idempotency handling
  • Secure error handling

JIT Authorization

  • Sub-second response time enforcement
  • Rate limiting per card
  • Request validation and sanitization
  • Comprehensive audit logging

API Key Management

  • Automatic rotation tracking
  • Environment-specific security recommendations
  • Usage monitoring and analytics
  • Secure key masking for logs

See SECURITY.md for complete security documentation.

Webhook Support

Full webhook security implementation with HMAC validation:

import { createWebhookMiddleware, createWebhookConfig } from 'moon-card-issuing-sdk';

// CRITICAL: Never use hardcoded secrets or fallbacks
if (!process.env.MOON_WEBHOOK_SECRET) {
  throw new Error('MOON_WEBHOOK_SECRET environment variable is required');
}

const config = createWebhookConfig(process.env.MOON_WEBHOOK_SECRET);

app.post('/webhooks/moon', 
  createWebhookMiddleware(config, async (payload) => {
    console.log('Secure webhook received:', payload.type);
  })
);

API Coverage

Implemented Resources

  • Cards - Full CRUD, balance management, transactions, PIN management
  • Webhooks - Register and delete webhook endpoints with security validation
  • Gift Cards - Purchase, manage, and track branded gift cards
  • Cardholders - Identity management, two-factor authentication, card associations
  • Invoices - Coming soon
  • Velocity Controls - Coming soon
  • Organizations - Coming soon
  • Accounts - Coming soon

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Make your changes and add tests
  4. Run tests: npm test
  5. Commit changes: git commit -m 'Add feature'
  6. Push to the branch: git push origin feature-name
  7. Submit a pull request

License

MIT License - see LICENSE file for details.

Support