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
fetchandAbortController - Modern browser with ES2017+ support (Chrome 60+, Firefox 55+, Safari 11+, Edge 79+)
- Also works in Node.js 18+ (native fetch)