Web

TypeScript SDK

Fully typed implementation for YardPay Pro with interfaces, enums, and generic responses. Drop these files into any TypeScript project.

Types & Interfaces

Create yardpaypro-types.ts — shared types used across all modules.

// yardpaypro-types.ts

export interface YardPayProConfig {
  apiKey: string;
  baseUrl?: string;    // default: window.location.origin
  timeout?: number;    // default: 30000
}

export class YardPayProError extends Error {
  status: number;
  code: string;
  constructor(status: number, code: string, message: string) {
    super(message);
    this.name = 'YardPayProError';
    this.status = status;
    this.code = code;
  }
}

// --- Payments ---
export interface CardInfo {
  name: string;
  cardNumber: string;
  expiryDate: string;
  cvv: string;
}

export interface BillingAddress {
  firstName: string;
  lastName: string;
  addressLine1: string;
  city: string;
  country: string;
}

export interface PayInvoiceRequest {
  invoiceId?: number;
  invoiceIdentifier?: string;
  paymentOptionId: number;
  fundingSourceId?: number;
  card?: CardInfo;
  billingAddress?: BillingAddress;
  sessionToken?: string;
}

export type ApprovalAction = 'None' | 'Redirect' | 'FormData' | 'QrCode';

export interface PaymentResponse {
  referenceNumber?: string;
  clientReferenceNumber?: string;
  invoiceIdentifier?: string;
  amountPaid?: number;
  amountDue?: number;
  feePaid?: number;
  currency?: string;
  paymentStatusId?: string;
  paymentDateTime?: string;
  paymentMethod?: string;
  isSuccess: boolean;
  approvalAction?: ApprovalAction;
  approvalDataOrUrl?: string;
  is3DSecureAuth?: boolean;
  authorizationCode?: string;
  hostMessage?: string;
}

export interface FundingSource {
  id: number;
  name: string;
  paymentOptionId: number;
  statusId: string;
  isVerified: boolean;
  maskedAccountNumber: string;
  expiryDate?: string;
}

export interface PaymentMethod {
  id: number;
  code: string;
  name: string;
  paymentMethodId: string;
  paymentProviderTypeId?: string;
  paymentChannel?: string;
  isEnabled: boolean;
  currencyCode?: string;
}

// --- Invoices ---
export type InvoiceStatus = 'Draft' | 'Pending' | 'Sent' | 'PartiallyPaid' | 'Paid' | 'Overdue' | 'Cancelled' | 'Expired';
export type InvoiceItemType = 'Product' | 'Service' | 'Subscription' | 'Fee' | 'Discount' | 'Tax';

export interface InvoiceItem {
  id?: number;
  name: string;
  description?: string;
  unitCost: number;
  quantity: number;
  discount?: number;
  taxRate?: number;
  taxAmount?: number;
  totalCost?: number;
  invoiceItemTypeId?: InvoiceItemType;
}

export interface CounterPartyInfo {
  firstName: string;
  lastName: string;
  email: string;
}

export interface Invoice {
  id: number;
  identifier: string;
  referenceNumber?: string;
  invoiceNumber?: string;
  description?: string;
  status: InvoiceStatus;
  totalDue?: number;
  totalPaid?: number;
  subTotal?: number;
  taxAmount?: number;
  totalCost: number;
  currencyCode: string;
  items?: InvoiceItem[];
  sourceInfo?: CounterPartyInfo;
  paymentDueDate?: string;
  successUrl?: string;
  cancelUrl?: string;
}

export interface CreateInvoiceRequest {
  description?: string;
  currencyCode: string;
  paymentDueDate?: string;
  notes?: string;
  items: Omit<InvoiceItem, 'id' | 'totalCost' | 'taxAmount'>[];
  sourceInfo: CounterPartyInfo;
  successUrl?: string;
  cancelUrl?: string;
}

// --- Subscriptions ---
export type SubscriptionProductType = 'Service' | 'Digital' | 'Physical';
export type SubscriptionPlanStatus = 'Active' | 'Inactive' | 'Archived';
export type SubscriptionBillingType = 'Recurring' | 'OneTime' | 'Usage';
export type TimeUnit = 'Day' | 'Week' | 'Month' | 'Year';
export type InventoryItemStatus = 'Available' | 'Rented' | 'Reserved' | 'Discontinued';

export interface SubscriptionProduct {
  id: number;
  merchantId: number;
  name: string;
  description?: string;
  subscriptionProductType: SubscriptionProductType;
}

export interface SubscriptionPlan {
  id: number;
  merchantId: number;
  productId: number;
  productName?: string;
  name: string;
  description?: string;
  status: SubscriptionPlanStatus;
  amount: string;
  currency: string;
  timeUnit: TimeUnit;
  timeInterval: number;
  subscriptionBillingType: SubscriptionBillingType;
}

export interface SubscriptionInventoryItem {
  id: number;
  productId: number;
  productName?: string;
  serialNumber?: string;
  status: InventoryItemStatus;
}

// --- OData ---
export interface ODataParams {
  $filter?: string;
  $orderby?: string;
  $top?: number;
  $skip?: number;
  $expand?: string;
  $select?: string;
  $count?: boolean;
}
API Client

Create yardpaypro-client.ts — the typed HTTP client.

// yardpaypro-client.ts

import { YardPayProConfig, YardPayProError } from './yardpaypro-types';

export class YardPayProClient {
  private apiKey: string;
  private baseUrl: string;
  private timeout: number;

  constructor(config: YardPayProConfig) {
    this.apiKey = config.apiKey;
    this.baseUrl = config.baseUrl ?? window.location.origin;
    this.timeout = config.timeout ?? 30000;
  }

  async request<T>(method: string, path: string, options?: {
    body?: unknown;
    params?: Record<string, string | number | boolean | undefined>;
  }): Promise<T> {
    let url = this.baseUrl + path;

    if (options?.params) {
      const qs = new URLSearchParams();
      Object.entries(options.params).forEach(([k, v]) => {
        if (v !== undefined && v !== null) qs.append(k, String(v));
      });
      const str = qs.toString();
      if (str) url += '?' + str;
    }

    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeout);

    try {
      const res = await fetch(url, {
        method,
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': this.apiKey,
        },
        body: options?.body ? JSON.stringify(options.body) : undefined,
        signal: controller.signal,
      });

      clearTimeout(timer);

      if (!res.ok) {
        const err = await res.json().catch(() => ({}));
        throw new YardPayProError(res.status, err.code ?? 'api_error', err.message ?? res.statusText);
      }

      if (res.status === 204) return null as T;

      const data = await res.json();
      return (data.value !== undefined ? data.value : data) as T;
    } catch (err) {
      clearTimeout(timer);
      if (err instanceof YardPayProError) throw err;
      if ((err as Error).name === 'AbortError') {
        throw new YardPayProError(0, 'timeout', 'Request timed out');
      }
      throw err;
    }
  }

  get<T>(path: string, params?: Record<string, string | number | boolean | undefined>) {
    return this.request<T>('GET', path, { params });
  }
  post<T>(path: string, body: unknown) {
    return this.request<T>('POST', path, { body });
  }
  put<T>(path: string, body: unknown) {
    return this.request<T>('PUT', path, { body });
  }
  delete(path: string) {
    return this.request<void>('DELETE', path);
  }
}
Service Modules

Create yardpaypro-services.ts — typed wrappers for each API area.

// yardpaypro-services.ts

import { YardPayProClient } from './yardpaypro-client';
import type {
  PayInvoiceRequest, PaymentResponse, FundingSource, PaymentMethod,
  Invoice, CreateInvoiceRequest, ODataParams,
  SubscriptionProduct, SubscriptionPlan, SubscriptionInventoryItem,
} from './yardpaypro-types';

// --- Payments ---
export class PaymentsService {
  constructor(private client: YardPayProClient) {}

  payInvoice(data: PayInvoiceRequest) {
    return this.client.post<PaymentResponse>('/api/payment/payinvoice', data);
  }
  getPaymentMethods(invoiceId: number) {
    return this.client.get<PaymentMethod[]>(`/v1/invoice/${invoiceId}/PaymentMethods`);
  }
  getFundingSources() {
    return this.client.get<FundingSource[]>('/v1/FundingSource');
  }
  registerCard(data: { card: { name: string; cardNumber: string; expiryDate: string; cvv: string }; name: string }) {
    return this.client.post<{ fundingSourceId: number; paymentResponse: PaymentResponse }>('/v1/payment/RegisterCard', data);
  }
  verifyCard(fundingSourceId: number, code: string) {
    return this.client.post<void>(`/v1/fundingSource/${fundingSourceId}/verify`, { VerificationCode: code });
  }
}

// --- Invoices ---
export class InvoicesService {
  constructor(private client: YardPayProClient) {}

  getByReference(code: string) {
    return this.client.get<Invoice>(`/v1/invoice/getByReference(code='${code}')`);
  }
  getById(id: number, expand?: string) {
    return this.client.get<Invoice>(`/v1/invoice/${id}`, expand ? { $expand: expand } : undefined);
  }
  list(params?: ODataParams) {
    return this.client.get<Invoice[]>('/v1/invoice', params as Record<string, string | number | boolean | undefined>);
  }
  create(data: CreateInvoiceRequest) {
    return this.client.post<Invoice>('/v1/invoice', data);
  }
  getQrCodeUrl(identifier: string) {
    return `/v1/invoice/qrcode/${identifier}`;
  }
}

// --- Subscriptions ---
export class SubscriptionsService {
  constructor(private client: YardPayProClient) {}

  listProducts(params?: ODataParams) {
    return this.client.get<SubscriptionProduct[]>('/v1/SubscriptionProduct', params as Record<string, string | number | boolean | undefined>);
  }
  createProduct(data: Partial<SubscriptionProduct>) {
    return this.client.post<SubscriptionProduct>('/v1/SubscriptionProduct', data);
  }
  updateProduct(id: number, data: Partial<SubscriptionProduct>) {
    return this.client.put<SubscriptionProduct>(`/v1/SubscriptionProduct/${id}`, data);
  }
  deleteProduct(id: number) {
    return this.client.delete(`/v1/SubscriptionProduct/${id}`);
  }

  listPlans(params?: ODataParams) {
    return this.client.get<SubscriptionPlan[]>('/v1/SubscriptionPlan', params as Record<string, string | number | boolean | undefined>);
  }
  createPlan(data: Partial<SubscriptionPlan>) {
    return this.client.post<SubscriptionPlan>('/v1/SubscriptionPlan', data);
  }
  updatePlan(id: number, data: Partial<SubscriptionPlan>) {
    return this.client.put<SubscriptionPlan>(`/v1/SubscriptionPlan/${id}`, data);
  }
  deletePlan(id: number) {
    return this.client.delete(`/v1/SubscriptionPlan/${id}`);
  }

  listInventory(params?: ODataParams) {
    return this.client.get<SubscriptionInventoryItem[]>('/v1/SubscriptionInventoryItem', params as Record<string, string | number | boolean | undefined>);
  }
  createInventoryItem(data: Partial<SubscriptionInventoryItem>) {
    return this.client.post<SubscriptionInventoryItem>('/v1/SubscriptionInventoryItem', data);
  }
  updateInventoryItem(id: number, data: Partial<SubscriptionInventoryItem>) {
    return this.client.put<SubscriptionInventoryItem>(`/v1/SubscriptionInventoryItem/${id}`, data);
  }
  deleteInventoryItem(id: number) {
    return this.client.delete(`/v1/SubscriptionInventoryItem/${id}`);
  }
}
Usage
import { YardPayProClient } from './yardpaypro-client';
import { YardPayProError } from './yardpaypro-types';
import { PaymentsService, InvoicesService, SubscriptionsService } from './yardpaypro-services';

const client = new YardPayProClient({ apiKey: 'sk_test_YOUR_KEY' });
const payments = new PaymentsService(client);
const invoices = new InvoicesService(client);
const subs = new SubscriptionsService(client);

// Create invoice → pay it → handle 3DS
const invoice = await invoices.create({
  description: 'Order #1234',
  currencyCode: 'JMD',
  items: [{ name: 'Widget', unitCost: 100, quantity: 2 }],
  sourceInfo: { firstName: 'Test', lastName: 'User', email: '[email protected]' },
});

const methods = await payments.getPaymentMethods(invoice.id);
const cardMethod = methods.find(m => m.paymentMethodId === 'CreditCard')!;

try {
  const result = await payments.payInvoice({
    invoiceIdentifier: invoice.identifier,
    paymentOptionId: cardMethod.id,
    card: { name: 'Test User', cardNumber: '4111111111111111', expiryDate: '12/28', cvv: '123' },
  });

  if (result.isSuccess && result.approvalAction === 'Redirect') {
    window.location.href = result.approvalDataOrUrl!; // 3D Secure
  } else if (result.isSuccess) {
    console.log('Paid:', result.referenceNumber);
  }
} catch (err) {
  if (err instanceof YardPayProError) {
    console.error(`[${err.status}] ${err.code}: ${err.message}`);
  }
}
Requirements
  • TypeScript 4.7+ (for satisfies and module resolution)
  • No external dependencies — uses native fetch
  • Works in browser and Node.js 18+
  • Compatible with React, Vue, Angular, Svelte, and any TypeScript project