TypeScript SDK
1. Overview
The Gateway TypeScript SDK enables clients (web frontends, Node.js backends, e-commerce integrations) to communicate with the Peak Gateway API. Built as a zero-dependency ESM package, the SDK provides Promise-based async APIs that work in Node.js, Deno, Cloudflare Workers, and modern browsers.
The SDK exposes two client classes that target different Gateway services:
GatewayAdminClient— Full admin/portal operations (management API). Used by portal frontends and backend admin tools.GatewayPayClient— Payment-facing operations (online transactions API). Used by checkout flows, e-commerce backends, and machine integrations.
Consumers: Portal frontends, merchant-dashboard, checkout flows, Node.js backends, e-commerce integrations
Organization / Location rename
The TypeScript SDK now exposes the organization/location split directly:
LocationsApiis the primary replacement for location CRUD and status operations.OrganizationsApiowns organization-scoped resources and credential profiles.MerchantsApiremains as a deprecated alias for legacy integrations.- Existing
merchantIdrequest fields still carry the concrete location id on the wire.
Safe migration posture:
- prefer
client.locationsandclient.organizationsin new code - treat
client.merchantsas a compatibility bridge only - keep legacy
merchantIdwording only where the API field itself is still named that way
Migration notes live in SDK v2 Migration Guide. The access-model summary is in Organizations and Locations.
2. Module Architecture
sdks/typescript/gateway-sdk/
└── src/
├── index.ts # Barrel export (re-exports all public API)
├── gateway-admin-client.ts # Admin client (17 API modules)
├── gateway-pay-client.ts # Pay client (6 API modules)
├── gateway-config.ts # Configuration types and resolver
├── gateway-error.ts # Error class hierarchy
├── api/
│ ├── transactions-api.ts # Sale, auth, void, refund, capture, query
│ ├── checkout-sessions-api.ts # Hosted checkout sessions
│ ├── tokens-api.ts # Payment token management
│ ├── wallet-api.ts # Apple Pay / Google Pay
│ ├── merchants-api.ts # Merchant CRUD
│ ├── subscriptions-api.ts # Recurring billing
│ ├── settlements-api.ts # Settlement batches
│ ├── api-keys-api.ts # API key management
│ ├── webhooks-api.ts # Webhook deliveries and events
│ ├── webhook-events-api.ts # Persisted event log, replay, retention, DLQ retry
│ ├── users-api.ts # User CRUD
│ ├── me-api.ts # Current user profile
│ ├── oauth-clients-api.ts # OAuth client management
│ ├── clients-api.ts # Client registration
│ ├── saml-providers-api.ts # SAML SSO providers
│ ├── hosted-payments-api.ts # Hosted buttons and iframes
│ ├── audit-log-api.ts # Audit log queries
│ ├── dashboard-api.ts # Dashboard metrics
│ ├── reports-api.ts # Daily, monthly, custom reports
│ └── provisioning-api.ts # Device provisioning jobs
├── models/
│ └── index.ts # All DTOs, enums, interfaces
├── webhook/
│ ├── webhook-verifier.ts # HMAC-SHA256 signature verification
│ └── webhook-event.ts # Discriminated union for event types
└── internal/
├── http-client.ts # fetch wrapper with retry and error mapping
└── auth-manager.ts # OAuth token lifecycle and caching
Client Summary
| Client | Base URL | API Modules | Use Case |
|---|---|---|---|
GatewayAdminClient | api.peakgateway.co | 17 (transactions, merchants, settlements, subscriptions, users, reports, ...) | Portal admin, backend management |
GatewayPayClient | pay.peakgateway.co | 6 (transactions, checkoutSessions, tokens, wallet, hostedPayments, subscriptions) | Checkout flows, payment processing |
Not Included
| Omitted | Reason | Where It Lives |
|---|---|---|
| React hooks / UI components | Kept SDK framework-agnostic; frontends wire their own state | websites/admin-portal/, websites/checkout/ |
| TransIT API client | Internal library for gateway microservices only | libs/transit-client/ |
| XTMS API client | Internal library for Merchant Onboarding Service only | libs/xtms-client/ |
3. Distribution
| Property | Value |
|---|---|
| Package | @gateway/sdk |
| Registry | npm |
| Language | TypeScript 5.9+ |
| Module | ESM ("type": "module") |
| Dependencies | None (zero runtime dependencies) |
| Runtimes | Node.js 18+, Deno, Cloudflare Workers, modern browsers |
| Build | tsc (publishes to npm via GitHub Actions) |
Dependency Setup
npm install @gateway/sdk
import { GatewayAdminClient, GatewayPayClient } from '@gateway/sdk'
4. Usage Examples
Elements SetupIntent Helper
The browser Elements helper for setup-intent confirmation is documented separately in Confirm Card Setup With Elements.
Initialization (Server-Side, OAuth2)
import { GatewayAdminClient } from '@gateway/sdk'
const client = new GatewayAdminClient({
clientId: 'client_your_app',
clientSecret: 'sk_live_xxxxxxxxxxxx',
environment: 'production',
connectTimeoutMs: 5000,
readTimeoutMs: 30000,
})
Initialization (Frontend, Firebase Token)
import { GatewayPayClient } from '@gateway/sdk'
import { getAuth } from 'firebase/auth'
const auth = getAuth()
const client = new GatewayPayClient({
environment: 'production',
tokenProvider: async () => {
const user = auth.currentUser
return user ? await user.getIdToken() : null
},
})
Process Sale (Server-Side, Card-Not-Present)
import { CardDataSource, IndustryType } from '@gateway/sdk'
const result = await client.transactions.sale({
amount: 2500,
currency: 'USD',
cardDataSource: CardDataSource.MANUAL,
industryType: IndustryType.ECOMMERCE,
metadata: { orderId: 'web-12345' },
})
switch (result.kind) {
case 'approved':
console.log(`Approved: ${result.approvalCode}`)
console.log(`Transaction ID: ${result.transactionId}`)
break
case 'declined':
console.log(`Declined: ${result.responseMessage}`)
break
case 'error':
console.log(`Error: ${result.message}`)
break
}
Checkout Session (Hosted Payments)
const session = await client.checkoutSessions.create({
amount: 5000,
currency: 'USD',
merchantId: 'loc_abc123', // legacy field name; pass the concrete location id
successUrl: 'https://merchant.com/success',
cancelUrl: 'https://merchant.com/cancel',
metadata: { orderId: 'web-67890' },
})
// Redirect customer to session.checkoutUrl
Void / Refund
// Void
const voidResult = await client.transactions.void('txn_abc123')
// Refund (partial)
const refundResult = await client.transactions.refund('txn_abc123', 1500)
Query Transactions
import { TransactionStatus } from '@gateway/sdk'
const transactions = await client.transactions.list(
'loc_abc123', // merchantId (wire field), using the location id
TransactionStatus.APPROVED, // status
'2026-03-01', // from
'2026-03-03', // to
50, // limit
)
for (const txn of transactions) {
console.log(`${txn.transactionId}: ${txn.amount} - ${txn.status}`)
}
Subscriptions
// Create
const subscription = await client.subscriptions.create({
merchantId: 'loc_abc123', // legacy field name; pass the concrete location id
customerId: 'cust_xyz',
amount: 1999,
currency: 'USD',
interval: 'monthly',
metadata: { plan: 'pro' },
})
// Pause / Resume / Cancel
await client.subscriptions.pause(subscription.subscriptionId)
await client.subscriptions.resume(subscription.subscriptionId)
await client.subscriptions.cancel(subscription.subscriptionId)
// Billing history
const history = await client.subscriptions.billingHistory(subscription.subscriptionId)
Webhook Event Operations
const admin = new GatewayAdminClient({
environment: 'production',
tokenProvider: async () => await firebaseUser.getIdToken(),
})
const details = await admin.webhookEvents.getDetails('evt_123')
// Replay only failed / DLQ deliveries for the event.
await admin.webhookEvents.replayFailedDeliveries(details.event.id)
// Or retry one specific DLQ delivery row.
await admin.webhookEvents.retryDeliveryFromDlq('del_456')
const retention = await admin.webhookEvents.findRetentionConfigForOrganization('org_123')
console.log(retention?.deliveryDays)
Webhook Verification
import express from 'express'
import { WebhookVerifier } from '@gateway/sdk'
const app = express()
const verifier = new WebhookVerifier('whsec_xxxxxxxxxxxx')
// Use express.text() so req.body is the raw string (not parsed JSON)
app.post('/webhooks', express.text({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['x-gateway-signature'] as string
const timestamp = req.headers['x-gateway-timestamp'] as string
const delivery = await verifier.verifyDelivery(req.body, signature, timestamp, req.headers)
const event = delivery.event
// Use correlationId when present to tie receiver logs back to gateway traces.
console.log('gatewayWebhookCorrelationId', delivery.correlationId)
switch (event.eventType) {
case 'transaction.completed':
handleCompletion(event.transaction)
break
case 'batch.settled':
handleSettlement(event.merchantId, event.netAmount)
break
case 'payment.failed':
handleFailure(event.transaction)
break
}
res.sendStatus(200)
})
Express Backend Pattern
import express from 'express'
import { GatewayAdminClient, CardDataSource, IndustryType } from '@gateway/sdk'
const app = express()
const gateway = new GatewayAdminClient({
clientId: process.env.GATEWAY_CLIENT_ID,
clientSecret: process.env.GATEWAY_CLIENT_SECRET,
environment: 'production',
})
app.post('/api/charge', async (req, res) => {
const result = await gateway.transactions.sale({
amount: req.body.amount,
currency: 'USD',
cardDataSource: CardDataSource.INTERNET,
industryType: IndustryType.ECOMMERCE,
merchantId: req.body.merchantId,
metadata: { orderId: req.body.orderId },
})
if (result.kind === 'approved') {
res.json({ success: true, transactionId: result.transactionId })
} else {
res.status(400).json({ success: false, message: result.responseMessage })
}
})
// Graceful shutdown
process.on('SIGTERM', () => gateway.close())
5. Authentication
The SDK authenticates using OAuth2 client credentials issued by the Gateway Auth Service, or via a custom token provider (typically Firebase Auth).
| Auth Method | Use Case | Client Config |
|---|---|---|
Client credentials (clientId + clientSecret) | Server-to-server (Node.js backends, cron jobs) | { clientId, clientSecret } |
| Firebase token provider | Frontend apps (admin-portal, checkout, merchant-dashboard) | { tokenProvider: () => getIdToken() } |
| Custom token provider | Any external auth system | { tokenProvider: () => fetchMyToken() } |
| App Check token (optional) | Firebase App Check enforcement | { appCheckTokenProvider: () => getAppCheckToken() } |
When using OAuth2 client credentials, access tokens are cached and automatically refreshed before expiry (with a 60-second buffer). When using a custom tokenProvider, the provider is called for each request (no SDK-side caching). In both modes, if a request receives a 401 response, the SDK transparently refreshes the token and retries the request once.
6. Error Handling
import {
AuthenticationError,
RateLimitError,
NetworkError,
ServerError,
ValidationError,
NotFoundError,
} from '@gateway/sdk'
try {
const result = await client.transactions.sale(request)
} catch (error) {
if (error instanceof AuthenticationError) {
// Invalid client credentials or expired token
} else if (error instanceof RateLimitError) {
// Retry after error.retryAfterSeconds
} else if (error instanceof NetworkError) {
// No connectivity — SDK automatically retries with exponential backoff
} else if (error instanceof ServerError) {
// 5xx from gateway — check error.statusCode
} else if (error instanceof ValidationError) {
// Invalid request parameters — check error.fieldErrors
} else if (error instanceof NotFoundError) {
// Resource not found (404)
}
}
Error Hierarchy
| Error Class | Trigger | Key Properties |
|---|---|---|
GatewayError | Base class for all SDK errors | message, cause |
AuthenticationError | 401/403 responses | message, cause |
RateLimitError | 429 responses | retryAfterSeconds |
NetworkError | Connection failures, timeouts | message, cause |
ServerError | 5xx responses | statusCode |
ValidationError | 422 responses | fieldErrors: Record<string, string> |
NotFoundError | 404 responses | message |
7. Architecture Notes
Zero Dependencies
The SDK has no runtime dependencies. It uses:
fetch— Native HTTP client (available in Node.js 18+, Deno, browsers, Cloudflare Workers)Web Crypto API— HMAC-SHA256 for webhook signature verification (available in all modern runtimes)AbortSignal.timeout— Request timeouts (available in Node.js 18+)
Retry and Timeout Behavior
| Setting | Default | Description |
|---|---|---|
readTimeoutMs | 30000 | Per-request timeout (via AbortSignal.timeout) |
maxRetries | 3 | Max retry attempts for retryable failures |
connectTimeoutMs | 5000 | Reserved for future use (not currently enforced by the HTTP layer) |
Retries use exponential backoff (250ms base, doubling per attempt). Only 5xx server errors and network failures are retried. Auth errors (401/403), validation errors (422), rate limits (429), and not-found errors (404) are never retried.
Discriminated Unions
Where the Kotlin SDK uses sealed classes, the TypeScript SDK uses discriminated unions with a kind or eventType field:
// Transaction results — discriminated by 'kind'
type TransactionResult =
| TransactionResultApproved // kind: 'approved'
| TransactionResultDeclined // kind: 'declined'
| TransactionResultError // kind: 'error'
// Webhook events — discriminated by 'eventType'
type WebhookEvent =
| TransactionCompletedEvent // eventType: 'transaction.completed'
| TransactionFailedEvent // eventType: 'transaction.failed'
| BatchSettledEvent // eventType: 'batch.settled'
| PaymentFailedEvent // eventType: 'payment.failed'
What's Shared with the Kotlin SDK
- All DTOs and request/response models (same JSON shape)
- API endpoint paths and REST conventions
- Error semantics (same HTTP status → error type mapping)
- Webhook signature verification (same HMAC-SHA256 algorithm)
- OAuth2 client credentials flow (same token endpoint)
- Retry and timeout logic (same exponential backoff strategy)
TypeScript-Specific
- Two client classes (
GatewayAdminClient+GatewayPayClient) instead of one unifiedGatewayClient - Discriminated unions instead of sealed classes for result/event types
Promise<T>instead of Kotlin coroutines (suspendfunctions)- Native
fetchinstead of Ktor HTTP client - Web Crypto API instead of platform-specific HMAC implementations