Skip to main content

Overview

The VaultConfig interface defines all configuration options accepted by new VaultClient(config). Configuration is validated on construction and will throw VaultConfigError if invalid.

VaultConfig

Root configuration object for VaultClient.
interface VaultConfig {
  providers: Record<string, ProviderConfig>;
  routing?: {
    rules: RoutingRule[];
  };
  idempotency?: {
    store?: IdempotencyStore;
    ttlMs?: number;
  };
  platformApiKey?: string;
  platform?: {
    baseUrl?: string;
    timeoutMs?: number;
    batchSize?: number;
    flushIntervalMs?: number;
    maxRetries?: number;
    initialBackoffMs?: number;
  };
  logging?: {
    level?: 'silent' | 'error' | 'warn' | 'info' | 'debug';
    logger?: LoggerInterface;
  };
  timeout?: number;
}

providers

providers
Record<string, ProviderConfig>
required
Map of provider names to their configurations. At least one enabled provider is required.

Example

import { VaultClient, StripeAdapter, DLocalAdapter } from '@vaultsaas/core';

const client = new VaultClient({
  providers: {
    stripe: {
      adapter: StripeAdapter,
      config: {
        apiKey: process.env.STRIPE_API_KEY,
      },
      priority: 0,
    },
    dlocal: {
      adapter: DLocalAdapter,
      config: {
        apiKey: process.env.DLOCAL_API_KEY,
        apiSecret: process.env.DLOCAL_SECRET,
      },
      priority: 1,
    },
  },
  routing: {
    rules: [{ match: { default: true }, provider: 'stripe' }],
  },
});

routing

routing
object
Local routing configuration. Optional if using platform routing.

RoutingRule

Each routing rule matches transaction attributes and routes to a specific provider.
interface RoutingRule {
  match: {
    currency?: string | string[];
    country?: string | string[];
    paymentMethod?: string | string[];
    amountMin?: number;
    amountMax?: number;
    metadata?: Record<string, string>;
    default?: boolean;
  };
  provider: string;
  weight?: number;
}
match
object
required
Conditions that must be met for this rule to apply
provider
string
required
The provider name to route to (must match a key in config.providers)
weight
number
Weight for probabilistic routing among multiple matching rules. Higher weights increase selection probability.

Routing Examples

const config: VaultConfig = {
  providers: {
    stripe: { /* ... */ },
    dlocal: { /* ... */ },
    paystack: { /* ... */ },
  },
  routing: {
    rules: [
      // Route Brazilian PIX to DLocal
      {
        match: { currency: 'BRL', paymentMethod: 'pix' },
        provider: 'dlocal',
      },
      // Route Nigerian transactions to Paystack
      {
        match: { country: 'NG' },
        provider: 'paystack',
      },
      // Route high-value USD transactions to Stripe
      {
        match: { currency: 'USD', amountMin: 100000 }, // $1000+
        provider: 'stripe',
      },
      // Load-balance remaining USD between Stripe (70%) and DLocal (30%)
      {
        match: { currency: 'USD' },
        provider: 'stripe',
        weight: 70,
      },
      {
        match: { currency: 'USD' },
        provider: 'dlocal',
        weight: 30,
      },
      // Default fallback to Stripe
      {
        match: { default: true },
        provider: 'stripe',
      },
    ],
  },
};

idempotency

idempotency
object
Idempotency configuration for preventing duplicate operations

IdempotencyStore Interface

Custom idempotency stores must implement:
interface IdempotencyStore {
  get(key: string): Promise<IdempotencyRecord | null>;
  set(record: IdempotencyRecord): Promise<void>;
  delete(key: string): Promise<void>;
  clearExpired(): Promise<void>;
}

interface IdempotencyRecord {
  key: string;
  payloadHash: string;
  result: unknown;
  expiresAt: number;
}

Example with Custom Redis Store

import { VaultClient, type IdempotencyStore, type IdempotencyRecord } from '@vaultsaas/core';
import Redis from 'ioredis';

// Custom Redis implementation of IdempotencyStore
class RedisIdempotencyStore implements IdempotencyStore {
  constructor(private redis: Redis) {}

  async get(key: string): Promise<IdempotencyRecord | null> {
    const data = await this.redis.get(`idempotency:${key}`);
    return data ? JSON.parse(data) : null;
  }

  async set(record: IdempotencyRecord): Promise<void> {
    const ttl = Math.max(0, record.expiresAt - Date.now());
    await this.redis.setex(
      `idempotency:${record.key}`,
      Math.ceil(ttl / 1000),
      JSON.stringify(record)
    );
  }

  async delete(key: string): Promise<void> {
    await this.redis.del(`idempotency:${key}`);
  }

  async clearExpired(): Promise<void> {
    // Redis TTL handles expiration automatically
  }
}

const redis = new Redis({
  host: 'localhost',
  port: 6379,
});

const client = new VaultClient({
  providers: { /* ... */ },
  idempotency: {
    store: new RedisIdempotencyStore(redis),
    ttlMs: 86400000, // 24 hours
  },
});

platformApiKey

platformApiKey
string
API key for VaultSaaS platform integration. Enables platform routing, analytics, and monitoring.

Example

const client = new VaultClient({
  providers: { /* ... */ },
  platformApiKey: process.env.VAULTSAAS_API_KEY,
});

platform

platform
object
Advanced platform connector configuration. Only relevant when platformApiKey is set.

Example

const client = new VaultClient({
  providers: { /* ... */ },
  platformApiKey: process.env.VAULTSAAS_API_KEY,
  platform: {
    timeoutMs: 3000,
    batchSize: 50,
    flushIntervalMs: 5000,
    maxRetries: 5,
  },
});

logging

logging
object
Logging configuration for SDK operations

LoggerInterface

Custom loggers must implement:
interface LoggerInterface {
  error(message: string, context?: Record<string, unknown>): void;
  warn(message: string, context?: Record<string, unknown>): void;
  info(message: string, context?: Record<string, unknown>): void;
  debug(message: string, context?: Record<string, unknown>): void;
}

Example with Winston

import { VaultClient } from '@vaultsaas/core';
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'vault.log' }),
  ],
});

const client = new VaultClient({
  providers: { /* ... */ },
  logging: {
    level: 'debug',
    logger: {
      error: (msg, ctx) => logger.error(msg, ctx),
      warn: (msg, ctx) => logger.warn(msg, ctx),
      info: (msg, ctx) => logger.info(msg, ctx),
      debug: (msg, ctx) => logger.debug(msg, ctx),
    },
  },
});

timeout

timeout
number
Global timeout in milliseconds for all payment operations. Individual adapters may have their own timeouts.

Example

const client = new VaultClient({
  providers: { /* ... */ },
  timeout: 30000, // 30 seconds
});

Validation

The SDK validates all configuration options on construction:

Required Fields

  • At least one provider must be configured
  • At least one provider must be enabled
  • Each provider must have a valid adapter constructor
  • Each provider must have a config object

Provider Validation

  • adapter must be a constructor function with static supportedMethods, supportedCurrencies, and supportedCountries arrays
  • config must be a plain object
  • priority must be an integer (if provided)
  • enabled must be a boolean (if provided)

Routing Validation

  • If routing is provided, rules must be a non-empty array
  • Each rule must have a provider that references an enabled provider
  • Each rule must have a match object
  • At least one rule must have match.default: true
  • amountMin and amountMax must be non-negative numbers
  • amountMin must not exceed amountMax
  • weight must be a positive number (if provided)

Idempotency Validation

  • ttlMs must be a positive integer (if provided)
  • store must implement all required methods: get, set, delete, clearExpired

Platform Validation

  • platformApiKey must not be empty (if provided)
  • baseUrl must not be empty (if provided)
  • timeoutMs, batchSize, flushIntervalMs, maxRetries, initialBackoffMs must all be positive integers (if provided)

Logging Validation

  • level must be one of: 'silent', 'error', 'warn', 'info', 'debug'
  • logger must implement all required methods: error, warn, info, debug

Complete Example

import { 
  VaultClient, 
  StripeAdapter, 
  DLocalAdapter, 
  PaystackAdapter,
  MemoryIdempotencyStore
} from '@vaultsaas/core';
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'vault.log' }),
  ],
});

const client = new VaultClient({
  // Provider configuration
  providers: {
    stripe: {
      adapter: StripeAdapter,
      config: {
        apiKey: process.env.STRIPE_API_KEY!,
      },
      priority: 0,
      enabled: true,
    },
    dlocal: {
      adapter: DLocalAdapter,
      config: {
        apiKey: process.env.DLOCAL_API_KEY!,
        apiSecret: process.env.DLOCAL_SECRET!,
      },
      priority: 1,
      enabled: true,
    },
    paystack: {
      adapter: PaystackAdapter,
      config: {
        secretKey: process.env.PAYSTACK_SECRET_KEY!,
      },
      priority: 2,
      enabled: true,
    },
  },

  // Routing rules
  routing: {
    rules: [
      {
        match: { currency: 'BRL', paymentMethod: 'pix' },
        provider: 'dlocal',
      },
      {
        match: { country: 'NG' },
        provider: 'paystack',
      },
      {
        match: { currency: 'USD' },
        provider: 'stripe',
      },
      {
        match: { default: true },
        provider: 'stripe',
      },
    ],
  },

  // Idempotency (use custom Redis store in production - see above example)
  idempotency: {
    store: new MemoryIdempotencyStore(),
    ttlMs: 86400000, // 24 hours
  },

  // Platform integration
  platformApiKey: process.env.VAULTSAAS_API_KEY,
  platform: {
    timeoutMs: 5000,
    batchSize: 100,
    flushIntervalMs: 10000,
    maxRetries: 3,
    initialBackoffMs: 1000,
  },

  // Logging
  logging: {
    level: 'info',
    logger: {
      error: (msg, ctx) => logger.error(msg, ctx),
      warn: (msg, ctx) => logger.warn(msg, ctx),
      info: (msg, ctx) => logger.info(msg, ctx),
      debug: (msg, ctx) => logger.debug(msg, ctx),
    },
  },

  // Global timeout
  timeout: 30000,
});

// Use the client
const result = await client.charge({
  amount: 5000,
  currency: 'BRL',
  paymentMethod: { type: 'pix' },
  customer: {
    email: 'customer@example.com',
    document: '12345678900',
  },
});

Build docs developers (and LLMs) love