@biorbank/moon-card-issuing-sdk
v0.1.0
Published
TypeScript SDK for Moon's Card Issuing API
Maintainers
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
Installation
npm install moon-card-issuing-sdk
# or
yarn add moon-card-issuing-sdkSetup
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 editManual Setup
1. Environment Configuration
Copy the example environment file and configure your settings:
cp .env.example .envEdit .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=staging2. 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:docsQuick 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');
// 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 modeTesting
npm test # Run tests
npm run test:watch # Run tests in watch modeType Generation
npm run generate-types # Regenerate types from API schemasExamples
Check the examples directory for complete usage examples:
- Basic Usage - Card creation and management with PCI DSS compliance
- Secure Integration - Complete security implementation
- Webhook Management - Secure webhook integration
- Gift Card Management - Complete gift card lifecycle
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-cardsMake 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
- Automatic card data masking (PAN shows only last 4 digits)
- CVV always redacted in responses
- PIN protection (never shown in production)
- Secure logging without sensitive 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
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Run tests:
npm test - Commit changes:
git commit -m 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
License
MIT License - see LICENSE file for details.
