Skip to main content

Overview

The SnapPay JavaScript SDK provides a comprehensive interface for integrating payment processing, subscription management, and real-time event streaming into your JavaScript/Node.js applications. Built with modern async/await patterns and robust error handling, it offers seamless integration with SnapPay’s complete platform. Requirements: Node.js 18+

Key Features

  • Modern async/await design with fetch API for optimal performance
  • Comprehensive error handling with typed error responses
  • Real-time event streaming via Server-Sent Events (SSE)
  • Service-based architecture for organized functionality
  • Automatic retry logic and error handling
  • Environment-based configuration
  • TypeScript support with full type definitions

Installation

npm install @snappay/sdk

Configuration & Initialization

The SDK is configured through environment variables and the client’s constructor. All operations require proper authentication and should use async/await patterns for optimal resource management.

API Key Authentication

Authentication is handled via an API key that must start with pk_test_ (for testing) or pk_live_ (for production). Configure your API key in one of these ways: Environment Variable (Recommended):
export SNAPPAY_API_KEY="pk_test_xxxxxxxxxx"
Direct Configuration:
import { SnapPay } from "@snappay/sdk";

// Using environment variable (recommended)
const client = new SnapPay();

// Using direct API key
const clientWithKey = new SnapPay("pk_test_xxxxxxxxxx");

Core Methods

All methods are async functions that return promises and must be called with await. The SDK uses a service-based architecture where methods are organized into logical groups: customers, checkout, access, and usage.

Customer Management

customers.get

Retrieves or creates a customer record (upsert logic).
const result = await client.customers.get(
  "cus_123",
  "[email protected]",
  "John Doe"
);
if (!result.ok) {
  console.error(result.error.message);
} else {
  const customer = result.data;
  console.log(`Customer ID: ${customer.customerId}`);
}
Parameters:
  • customerId (string): Customer identifier
  • email (string, optional): Customer email address
  • name (string, optional): Customer full name
Returns: Customer object with:
  • customerId (string): SnapPay customer ID
  • email (string): Customer email
  • name (string): Customer name

Checkout Sessions

checkout.createSession

Creates a payment checkout session URL for customer purchases.
import { Provider } from "@snappay/sdk";

const result = await client.checkout.createSession(
  "cus_123",
  "premium-plan",
  "https://yourapp.com/success",
  "https://yourapp.com/cancel", // Optional
  "price_id" // Optional priceId
);
if (!result.ok) {
  console.error(result.error.message);
} else {
  console.log(`Checkout URL: ${result.data.url}`);
}
Parameters:
  • customerId (string): SnapPay customer ID
  • productId (string): Product ID from your SnapPay dashboard
  • successUrl (string): URL to redirect after successful payment
  • cancelUrl (string, optional): URL to redirect on cancellation
  • priceId (string, optional): The optional price ID
Returns: CheckoutSession object with:
  • sessionId (string): Unique session identifier
  • url (string): Checkout URL for customer
  • expiresAt (string): Session expiration timestamp

Access Control

access.check

Checks if a customer has access to a specific feature based on their subscription and usage limits.
const result = await client.access.check("cus_123", "premium-features");
if (!result.ok) {
  console.error(result.error.message);
} else {
  const access = result.data;
  if (access.hasAccess) {
    const { usage, allowance } = access;
    if (usage != null && allowance != null) {
      console.log(`Access granted. ${usage}/${allowance} used`);
    } else {
      console.log("Access granted (unlimited feature)");
    }
  } else {
    console.log("Access denied. Upgrade required.");
  }
}
Parameters:
  • customerId (string): SnapPay customer ID
  • featureId (string): Feature identifier
Returns: AccessCheck object with:
  • hasAccess (boolean): Whether customer has access
  • featureId (string): Feature being checked
  • usage (number | null): Current usage (null if unlimited/no access)
  • allowance (number | null): Usage limit (null if unlimited/no access)
  • nextResetAt (number | null): Next reset timestamp in epoch seconds (null if unlimited/no access)

Usage Tracking

usage.track

Reports usage for a metered feature. This action is idempotent to prevent duplicate tracking.
const result = await client.usage.track(
  "cus_123", // customer ID
  "ai-messages", // feature ID
  1 // usage
);
if (!result.ok) {
  console.error(result.error.message);
} else {
  console.log(`Usage tracked successfully: ${result.data.usageTotal}`);
}
Parameters:
  • customerId (string): SnapPay customer ID
  • featureId (string): Feature identifier for usage tracking
  • usage (number): Usage amount to track
  • idempotencyKey (string, optional): Prevents duplicate tracking (random UUID if not set)
Returns: TrackUsageResponse object with tracking confirmation details.
  • customerId (string): The ID of the customer whose usage is being tracked.
  • featureId (string): The ID of the feature being tracked for usage.
  • usageRecorded (number): The amount of usage recorded in this operation.
  • usageTotal (number): The total usage amount after this operation.
  • timestamp (string): The timestamp when the usage was recorded.
  • idempotencyKey (string): A unique key to prevent duplicate tracking of this operation.

usage.get

Retrieves current usage details for a customer’s feature.
const result = await client.usage.get("cus_123", "ai-messages");
if (!result.ok) {
  console.error(result.error.message);
} else {
  const items = result.data;
  for (const usage of items) {
    console.log(`Total usage: ${usage.totalUsage}`);
    if (usage.remaining != null) console.log(`Remaining: ${usage.remaining}`);
    if (usage.limit != null) console.log(`Limit: ${usage.limit}`);
  }
}
Parameters:
  • customerId (string): SnapPay customer ID
  • featureId (string): Feature identifier
Returns: GetUsageResponse[] array with items containing:
  • totalUsage (number)
  • productId (string)
  • featureId (string)
  • remaining (number | null)
  • limit (number | null)
  • nextResetAt (number | null)

Real-time Event Handling

Say goodbye to webhook hell! SnapPay eliminates the complexity of managing payment webhooks by processing all provider webhooks (Stripe, PayPal, etc.) internally and delivering clean, structured events directly to your application via Server-Sent Events (SSE).

🚫 What You DON’T Need:

  • No webhook endpoints to create and maintain
  • No webhook signature verification
  • No webhook retry logic or failure handling
  • No webhook security concerns
  • No debugging webhook delivery issues

βœ… What You GET:

  • Real-time events delivered instantly to your application
  • Guaranteed delivery with automatic reconnection
  • Clean, structured data - no raw webhook payloads
  • Multiple consumption patterns to fit your architecture
  • Type-safe event objects with full IDE support

Supported Events

See the list of supported events: Server-sent Event Types

Stream Events (Async Iterator)

Simply iterate over events as they arrive - SnapPay handles all the webhook complexity behind the scenes:
import { SnapPay } from "@snappay/sdk";

async function main() {
  const client = new SnapPay();
  for await (const event of client.streamEvents()) {
    console.log(`Event: ${event.type}`);
    console.log(`ID: ${event.id}`);
    console.log(`Data:`, event.data);
  }
}

main().catch(console.error);

Event Handlers

Set up handlers for specific payment events - SnapPay converts complex webhook payloads into simple, actionable events:
import { SnapPay, SSEEventType } from "@snappay/sdk";

function handleSubscriptionUpdated(event) {
  console.log("Subscription updated:", event.data);
}

function handleAny(event) {
  console.log("Event:", event.type, event.data);
}

async function main() {
  const client = new SnapPay();
  client.onEvent(SSEEventType.SUBSCRIPTION_UPDATED, handleSubscriptionUpdated);
  client.onAnyEvent(handleAny);
  await client.startEvents();
  await new Promise((resolve) => setTimeout(resolve, 60000));
}

main().catch(console.error);

Error Handling

The SDK provides comprehensive error handling with typed exceptions:
import {
  SnapPay,
  SnapPayError,
  AuthenticationError,
  ValidationError,
  RateLimitError,
  NotFoundError,
} from "@snappay/sdk";

async function comprehensiveErrorHandling() {
  const client = new SnapPay();

  try {
    const customer = await client.customers.get("cus_123", "[email protected]");
  } catch (error) {
    if (error instanceof AuthenticationError) {
      console.log(`Invalid API key: ${error.message}`);
    } else if (error instanceof ValidationError) {
      console.log(`Invalid parameters: ${error.message}`);
    } else if (error instanceof RateLimitError) {
      console.log(`Rate limit exceeded: ${error.message}`);
    } else if (error instanceof NotFoundError) {
      console.log(`Resource not found: ${error.message}`);
    } else if (error instanceof SnapPayError) {
      console.log(`General SnapPay error: ${error.message}`);
    } else {
      console.log(`Unexpected error: ${error.message}`);
    }
  }
}

comprehensiveErrorHandling().catch(console.error);

Exception Hierarchy

SnapPayError                    // Base exception
β”œβ”€β”€ AuthenticationError          // Invalid API key or authentication
β”œβ”€β”€ ValidationError              // Invalid parameters or request data
β”œβ”€β”€ RateLimitError              // API rate limit exceeded
β”œβ”€β”€ NotFoundError               // Resource not found
└── ServerError                 // Server-side errors (5xx responses)