Official Node.js / TypeScript SDK for the PayByte Payment Gateway API — card payments for Oman merchants, processed via the National Bank of Oman.
- Zero runtime dependencies (uses native
fetchandcrypto) - TypeScript types for every resource
- Automatic retries on network errors and 5xx responses
- Automatic idempotency keys on all create calls
- Webhook signature verification
Node.js 18 or newer.
npm install paybyteimport PayByte from 'paybyte';
const paybyte = new PayByte('pb_live_YOUR_KEY_ID', 'pb_secret_YOUR_SECRET');
// 1. Create an order (amount is in baisa — 1 OMR = 1000 baisa)
const order = await paybyte.orders.create({ amount: 5000, currency: 'OMR' });
// 2. Create a checkout session and hand the token to your frontend
const session = await paybyte.checkout.createSession({ order_id: order.id });
console.log(session.session_token);Pass your API key id and secret to the constructor, or set the
PAYBYTE_KEY_ID and PAYBYTE_SECRET environment variables and construct
with no arguments:
const paybyte = new PayByte(); // reads PAYBYTE_KEY_ID / PAYBYTE_SECRETKeep the secret server-side only — never ship it to a browser.
const order = await paybyte.orders.create({
amount: 5000, // baisa
currency: 'OMR',
receipt: 'cart-1024',
customer: { email: 'buyer@example.com' },
});
const fetched = await paybyte.orders.retrieve(order.id);const session = await paybyte.checkout.createSession({
order_id: order.id,
return_url: 'https://your-site.com/thank-you',
});
// Later, to cancel an open session:
await paybyte.checkout.cancelSession(session.session_token);const payment = await paybyte.payments.retrieve('pay_abc123');
console.log(payment.status); // 'captured', 'failed', ...// Full refund
await paybyte.refunds.create({ payment_id: 'pay_abc123' });
// Partial refund (amount in baisa)
await paybyte.refunds.create({ payment_id: 'pay_abc123', amount: 2000 });Verify the X-PayByte-Signature header before trusting a webhook. Pass the
raw request body — do not parse the JSON first.
import { webhooks } from 'paybyte';
import express from 'express';
const app = express();
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
let event;
try {
event = webhooks.constructEvent(
req.body.toString(),
req.headers['x-paybyte-signature'] as string,
process.env.PAYBYTE_WEBHOOK_SECRET!,
);
} catch (err) {
return res.status(400).send('Invalid signature');
}
switch (event.type) {
case 'payment.captured':
// fulfil the order
break;
case 'refund.processed':
// update your records
break;
}
res.sendStatus(200);
});Every API error throws a typed subclass of PayByteError:
import {
PayByteError,
PayByteInvalidRequestError,
PayByteAuthenticationError,
PayByteRateLimitError,
PayByteNotFoundError,
} from 'paybyte';
try {
await paybyte.orders.create({ amount: 0, currency: 'OMR' });
} catch (err) {
if (err instanceof PayByteInvalidRequestError) {
console.error(err.code, err.message); // e.g. 'amount_too_small'
} else if (err instanceof PayByteError) {
console.error(err.statusCode, err.type, err.requestId);
}
}const paybyte = new PayByte('pb_live_...', 'pb_secret_...', {
baseUrl: 'https://api.paybyte.company', // override (e.g. for testing)
timeoutMs: 30000, // request timeout, default 30s
maxRetries: 3, // retries on 5xx/network, default 3
});create calls send an automatic Idempotency-Key so retries never create
duplicates. To control it yourself — for example to retry the same logical
operation across processes — pass one:
await paybyte.orders.create(
{ amount: 5000, currency: 'OMR' },
{ idempotencyKey: 'order-cart-1024' },
);MIT