Skip to main content

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:

  • LocationsApi is the primary replacement for location CRUD and status operations.
  • OrganizationsApi owns organization-scoped resources and credential profiles.
  • MerchantsApi remains as a deprecated alias for legacy integrations.
  • Existing merchantId request fields still carry the concrete location id on the wire.

Safe migration posture:

  • prefer client.locations and client.organizations in new code
  • treat client.merchants as a compatibility bridge only
  • keep legacy merchantId wording 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

ClientBase URLAPI ModulesUse Case
GatewayAdminClientapi.peakgateway.co17 (transactions, merchants, settlements, subscriptions, users, reports, ...)Portal admin, backend management
GatewayPayClientpay.peakgateway.co6 (transactions, checkoutSessions, tokens, wallet, hostedPayments, subscriptions)Checkout flows, payment processing

Not Included

OmittedReasonWhere It Lives
React hooks / UI componentsKept SDK framework-agnostic; frontends wire their own statewebsites/admin-portal/, websites/checkout/
TransIT API clientInternal library for gateway microservices onlylibs/transit-client/
XTMS API clientInternal library for Merchant Onboarding Service onlylibs/xtms-client/

3. Distribution

PropertyValue
Package@gateway/sdk
Registrynpm
LanguageTypeScript 5.9+
ModuleESM ("type": "module")
DependenciesNone (zero runtime dependencies)
RuntimesNode.js 18+, Deno, Cloudflare Workers, modern browsers
Buildtsc (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 MethodUse CaseClient Config
Client credentials (clientId + clientSecret)Server-to-server (Node.js backends, cron jobs){ clientId, clientSecret }
Firebase token providerFrontend apps (admin-portal, checkout, merchant-dashboard){ tokenProvider: () => getIdToken() }
Custom token providerAny 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 ClassTriggerKey Properties
GatewayErrorBase class for all SDK errorsmessage, cause
AuthenticationError401/403 responsesmessage, cause
RateLimitError429 responsesretryAfterSeconds
NetworkErrorConnection failures, timeoutsmessage, cause
ServerError5xx responsesstatusCode
ValidationError422 responsesfieldErrors: Record<string, string>
NotFoundError404 responsesmessage

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

SettingDefaultDescription
readTimeoutMs30000Per-request timeout (via AbortSignal.timeout)
maxRetries3Max retry attempts for retryable failures
connectTimeoutMs5000Reserved 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 unified GatewayClient
  • Discriminated unions instead of sealed classes for result/event types
  • Promise<T> instead of Kotlin coroutines (suspend functions)
  • Native fetch instead of Ktor HTTP client
  • Web Crypto API instead of platform-specific HMAC implementations