Web

JavaScript SDK

Copy-paste implementation for integrating YardPay Pro into browser-based applications. Uses fetch with no external dependencies.

API Client

Create a file yardpaypro.js in your project. This is the base client that all modules use.

// yardpaypro.js

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

class YardPayProClient {
  constructor({ apiKey, baseUrl = window.location.origin, timeout = 30000 }) {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
    this.timeout = timeout;
  }

  async _request(method, path, { body, params } = {}) {
    let url = this.baseUrl + path;

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

    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: body ? JSON.stringify(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;

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

  get(path, params) { return this._request('GET', path, { params }); }
  post(path, body) { return this._request('POST', path, { body }); }
  put(path, body) { return this._request('PUT', path, { body }); }
  delete(path) { return this._request('DELETE', path); }
}
Payments
// payments.js

class Payments {
  constructor(client) {
    this.client = client;
  }

  /** Pay an invoice with card or saved funding source */
  async payInvoice({ invoiceId, invoiceIdentifier, paymentOptionId, fundingSourceId, card, billingAddress }) {
    return this.client.post('/api/payment/payinvoice', {
      invoiceId,
      invoiceIdentifier,
      paymentOptionId,
      fundingSourceId,
      card,
      billingAddress,
    });
  }

  /** Get available payment methods for an invoice */
  async getPaymentMethods(invoiceId) {
    return this.client.get(`/v1/invoice/${invoiceId}/PaymentMethods`);
  }

  /** List saved funding sources (cards, wallets) */
  async getFundingSources() {
    return this.client.get('/v1/FundingSource');
  }

  /** Register a new payment card */
  async registerCard({ card, name }) {
    return this.client.post('/v1/payment/RegisterCard', { card, name });
  }

  /** Verify a registered card */
  async verifyCard(fundingSourceId, verificationCode) {
    return this.client.post(`/v1/fundingSource/${fundingSourceId}/verify`, {
      VerificationCode: verificationCode,
    });
  }
}

// --- Usage ---
const client = new YardPayProClient({ apiKey: 'sk_test_YOUR_KEY' });
const payments = new Payments(client);

// Pay with a new card
const result = await payments.payInvoice({
  invoiceIdentifier: 'INV-2024-001',
  paymentOptionId: 1,
  card: {
    name: 'John Doe',
    cardNumber: '4111111111111111',
    expiryDate: '12/28',
    cvv: '123',
  },
  billingAddress: {
    firstName: 'John',
    lastName: 'Doe',
    addressLine1: '123 Main St',
    city: 'Kingston',
    country: 'JM',
  },
});

if (result.isSuccess && result.approvalAction === 'Redirect') {
  // 3D Secure — redirect user
  window.location.href = result.approvalDataOrUrl;
} else if (result.isSuccess) {
  console.log('Payment complete:', result.referenceNumber);
}
Invoices
// invoices.js

class Invoices {
  constructor(client) {
    this.client = client;
  }

  /** Get an invoice by its public reference code (no auth required) */
  async getByReference(code) {
    return this.client.get(`/v1/invoice/getByReference(code='${code}')`);
  }

  /** Get an invoice by ID */
  async getById(id, expand) {
    const params = expand ? { $expand: expand } : undefined;
    return this.client.get(`/v1/invoice/${id}`, params);
  }

  /** List invoices with OData filtering */
  async list({ filter, orderBy, top = 20, skip = 0, expand } = {}) {
    return this.client.get('/v1/invoice', {
      $filter: filter,
      $orderby: orderBy,
      $top: top,
      $skip: skip,
      $expand: expand,
    });
  }

  /** Create a new invoice */
  async create(data) {
    return this.client.post('/v1/invoice', data);
  }

  /** Get QR code URL for an invoice */
  getQrCodeUrl(identifier) {
    return `${this.client.baseUrl}/v1/invoice/qrcode/${identifier}`;
  }

  /** Check if an invoice can be paid */
  canBePaid(invoice) {
    const payable = ['Pending', 'Sent', 'PartiallyPaid', 'Overdue'];
    return payable.includes(invoice.status);
  }
}

// --- Usage ---
const invoices = new Invoices(client);

// Create an invoice
const invoice = await invoices.create({
  description: 'Website Design',
  currencyCode: 'JMD',
  paymentDueDate: '2026-04-15T00:00:00Z',
  items: [
    { name: 'Design Services', unitCost: 50000, quantity: 1, taxRate: 15, invoiceItemTypeId: 'Service' },
  ],
  sourceInfo: { firstName: 'Jane', lastName: 'Smith', email: '[email protected]' },
  successUrl: 'https://yoursite.com/thanks',
});

// Get QR code for the invoice
const qrUrl = invoices.getQrCodeUrl(invoice.identifier);
document.getElementById('qr').src = qrUrl;

// List pending invoices
const pending = await invoices.list({
  filter: "status eq 'Pending'",
  orderBy: 'createdDateTime desc',
});
Subscriptions
// subscriptions.js

class Subscriptions {
  constructor(client) {
    this.client = client;
  }

  // --- Products ---
  async listProducts({ expand, orderBy, top, skip, count } = {}) {
    return this.client.get('/v1/SubscriptionProduct', {
      $expand: expand, $orderby: orderBy, $top: top, $skip: skip, $count: count,
    });
  }
  async createProduct(data) {
    return this.client.post('/v1/SubscriptionProduct', data);
  }
  async updateProduct(id, data) {
    return this.client.put(`/v1/SubscriptionProduct/${id}`, data);
  }
  async deleteProduct(id) {
    return this.client.delete(`/v1/SubscriptionProduct/${id}`);
  }

  // --- Plans ---
  async listPlans({ filter, expand, top, skip, count } = {}) {
    return this.client.get('/v1/SubscriptionPlan', {
      $filter: filter, $expand: expand, $top: top, $skip: skip, $count: count,
    });
  }
  async createPlan(data) {
    return this.client.post('/v1/SubscriptionPlan', data);
  }
  async updatePlan(id, data) {
    return this.client.put(`/v1/SubscriptionPlan/${id}`, data);
  }
  async deletePlan(id) {
    return this.client.delete(`/v1/SubscriptionPlan/${id}`);
  }

  // --- Inventory ---
  async listInventory({ filter, orderBy, top, skip, count } = {}) {
    return this.client.get('/v1/SubscriptionInventoryItem', {
      $filter: filter, $orderby: orderBy, $top: top, $skip: skip, $count: count,
    });
  }
  async createInventoryItem(data) {
    return this.client.post('/v1/SubscriptionInventoryItem', data);
  }
  async updateInventoryItem(id, data) {
    return this.client.put(`/v1/SubscriptionInventoryItem/${id}`, data);
  }
  async deleteInventoryItem(id) {
    return this.client.delete(`/v1/SubscriptionInventoryItem/${id}`);
  }
}

// --- Usage ---
const subs = new Subscriptions(client);

const product = await subs.createProduct({
  name: 'Business Suite',
  description: 'Complete business toolkit',
  subscriptionProductType: 'Service',
});

await subs.createPlan({
  productId: product.id,
  name: 'Monthly',
  amount: '29.99',
  currency: 'USD',
  timeUnit: 'Month',
  timeInterval: 1,
  subscriptionBillingType: 'Recurring',
  status: 'Active',
});
Accounts & Transfers
// accounts.js

class Accounts {
  constructor(client) { this.client = client; }

  async list(params) { return this.client.get('/v1/account', params); }
  async getById(id) { return this.client.get(`/v1/account/${id}`); }
}

class Transfers {
  constructor(client) { this.client = client; }

  async create(data) { return this.client.post('/v1/transfer', data); }
  async list(params) { return this.client.get('/v1/transfer', params); }
  async getById(id) { return this.client.get(`/v1/transfer/${id}`); }
}

// --- Usage ---
const accounts = new Accounts(client);
const transfers = new Transfers(client);

const myAccounts = await accounts.list();
const transfer = await transfers.create({
  sourceAccountId: 1,
  destinationAccountId: 2,
  amount: 5000,
  currency: 'JMD',
  description: 'Payout',
});
Error Handling
try {
  const result = await payments.payInvoice({ ... });
} catch (err) {
  if (err instanceof YardPayProError) {
    switch (err.status) {
      case 401:
        console.error('Invalid API key');
        break;
      case 403:
        console.error('Insufficient scope:', err.code);
        break;
      case 400:
        console.error('Validation error:', err.message);
        break;
      default:
        console.error(`API error ${err.status}: ${err.message}`);
    }
  } else {
    console.error('Network error:', err.message);
  }
}
Putting It All Together
// Import your modules
// import { YardPayProClient, YardPayProError } from './yardpaypro.js';
// import { Payments } from './payments.js';
// import { Invoices } from './invoices.js';
// import { Subscriptions } from './subscriptions.js';

const client = new YardPayProClient({
  apiKey: 'sk_test_YOUR_KEY',
  // baseUrl: window.location.origin,  // default
  // timeout: 30000,                          // default
});

const payments = new Payments(client);
const invoices = new Invoices(client);
const subs = new Subscriptions(client);

// Full payment flow
const invoice = await invoices.create({
  description: 'Order #1234',
  currencyCode: 'JMD',
  items: [{ name: 'Widget', unitCost: 100, quantity: 2, invoiceItemTypeId: 'Product' }],
  sourceInfo: { firstName: 'Test', lastName: 'User', email: '[email protected]' },
});

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

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

console.log('Paid:', payment.referenceNumber);
Requirements
  • No external dependencies — uses native fetch and AbortController
  • Modern browser with ES2017+ support (Chrome 60+, Firefox 55+, Safari 11+, Edge 79+)
  • Also works in Node.js 18+ (native fetch)