Documentation Index
Fetch the complete documentation index at: https://align.tolbel.com/llms.txt
Use this file to discover all available pages before exploring further.
Error Types
The SDK exports two main error classes:
import { AlignError, AlignValidationError } from "@tolbel/align";
AlignError
Thrown when the API returns an error response (4xx or 5xx status codes).
class AlignError extends Error {
readonly status: number; // HTTP status code
readonly code?: string; // Error code from API
readonly requestId?: string; // Request ID for debugging
readonly body?: unknown; // Additional error details
}
AlignValidationError
Thrown when request data fails local validation before being sent to the API.
class AlignValidationError extends Error {
readonly errors: Record<string, string[]>; // Map of field names to error messages
}
Basic Error Handling
Always wrap API calls in try-catch blocks:
import Align, { AlignError, AlignValidationError } from "@tolbel/align";
const align = new Align({
apiKey: process.env.ALIGN_API_KEY!,
environment: "sandbox",
});
async function createCustomer() {
try {
const customer = await align.customers.create({
email: "[email protected]",
type: "individual",
first_name: "Alice",
last_name: "Smith",
});
return customer;
} catch (error) {
if (error instanceof AlignValidationError) {
// Local validation failed
console.error("Validation failed:");
Object.entries(error.errors).forEach(([field, messages]) => {
console.error(` ${field}: ${messages.join(", ")}`);
});
} else if (error instanceof AlignError) {
// API returned an error
console.error(`API Error [${error.status}]: ${error.message}`);
console.error(`Request ID: ${error.requestId}`);
} else {
// Network or unexpected error
throw error;
}
}
}
const { default: Align, AlignError, AlignValidationError } = require("@tolbel/align");
const align = new Align({
apiKey: process.env.ALIGN_API_KEY,
environment: "sandbox",
});
async function createCustomer() {
try {
const customer = await align.customers.create({
email: "[email protected]",
type: "individual",
first_name: "Alice",
last_name: "Smith",
});
return customer;
} catch (error) {
if (error instanceof AlignValidationError) {
console.error("Validation failed:", error.errors);
} else if (error instanceof AlignError) {
console.error(`API Error [${error.status}]: ${error.message}`);
} else {
throw error;
}
}
}
Common Error Scenarios
Duplicate Email (409 Conflict)
Thrown when trying to create a customer with an email that already exists.try {
await align.customers.create({
email: "[email protected]",
type: "individual",
first_name: "Alice",
last_name: "Smith",
});
} catch (error) {
if (error instanceof AlignError && error.status === 409) {
// Email already exists - find the existing customer
const existing = await align.customers.list("[email protected]");
console.log("Found existing customer:", existing.items[0].customer_id);
}
}
Invalid API Key (401 Unauthorized)
Thrown when the API key is invalid or missing.try {
await align.customers.list();
} catch (error) {
if (error instanceof AlignError && error.status === 401) {
console.error("Invalid API key. Check your ALIGN_API_KEY environment variable.");
}
}
Never log or expose your API key in error messages!
Thrown when the requested resource doesn’t exist.try {
const customer = await align.customers.get("non-existent-id");
} catch (error) {
if (error instanceof AlignError && error.status === 404) {
console.error("Customer not found");
}
}
Caught before the API call when request data is invalid.try {
await align.customers.create({
email: "not-an-email", // Invalid email format
type: "individual",
// Missing first_name and last_name
});
} catch (error) {
if (error instanceof AlignValidationError) {
// error.errors = {
// "email": ["Invalid email address"],
// "first_name": ["Required"],
// "last_name": ["Required"]
// }
}
}
Rate Limiting (429 Too Many Requests)
Thrown when you’ve exceeded the API rate limit.try {
await align.customers.list();
} catch (error) {
if (error instanceof AlignError && error.status === 429) {
// Wait and retry
// Check body for specific retry details if available
const retryAfter = 60;
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
// Retry the request
}
}
The SDK has built-in retry logic with exponential backoff. Most transient errors are automatically retried.
Error Handling Patterns
Centralized Error Handler
Create a reusable error handler for consistent error management:
import { AlignError, AlignValidationError } from "@tolbel/align";
type ErrorResult =
| { type: "validation"; errors: Record<string, string[]> }
| { type: "api"; status: number; message: string }
| { type: "network"; message: string }
| { type: "unknown"; error: unknown };
function handleAlignError(error: unknown): ErrorResult {
if (error instanceof AlignValidationError) {
return {
type: "validation",
errors: error.errors,
};
}
if (error instanceof AlignError) {
return {
type: "api",
status: error.status,
message: error.message,
};
}
if (error instanceof Error && error.message.includes("fetch")) {
return {
type: "network",
message: "Network error. Check your internet connection.",
};
}
return {
type: "unknown",
error,
};
}
// Usage
try {
await align.customers.create(data);
} catch (error) {
const result = handleAlignError(error);
switch (result.type) {
case "validation":
return { success: false, errors: result.errors };
case "api":
return { success: false, message: result.message };
case "network":
return { success: false, message: "Please try again later" };
default:
throw error;
}
}
Retry with Backoff
For critical operations, implement custom retry logic:
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
let lastError: unknown;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (error instanceof AlignError) {
// Don't retry client errors (4xx) except rate limiting
if (error.status && error.status < 500 && error.status !== 429) {
throw error;
}
}
// Exponential backoff
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw lastError;
}
// Usage
const customer = await withRetry(() =>
align.customers.create({
email: "[email protected]",
type: "individual",
first_name: "Alice",
last_name: "Smith",
})
);
Logging Errors
Enable SDK logging for debugging:
const align = new Align({
apiKey: process.env.ALIGN_API_KEY!,
environment: "sandbox",
enableLogging: true, // Enable pino logging
});
The SDK uses pino for logging. Set
LOG_LEVEL environment variable to control log verbosity.
Best Practices
Always Use Try-Catch
Wrap all API calls in try-catch blocks to prevent unhandled promise
rejections.
Check Error Types
Use instanceof to distinguish between validation errors and API errors.
Log Appropriately
Log errors for debugging but never log sensitive data like API keys.
User-Friendly Messages
Transform technical errors into user-friendly messages for your UI.