bog-payments-sdk
v0.1.0
Published
Unofficial TypeScript SDK for the Bank of Georgia (BOG) E-Commerce Payments API
Downloads
38
Maintainers
Readme
bog-payments-sdk
Unofficial TypeScript SDK for the Bank of Georgia (BOG) E-Commerce Payments API.
Covers:
- OAuth2 client-credentials authentication (token fetch + caching + auto-refresh)
- Creating orders (
POST /payments/v1/ecommerce/orders) - Fetching payment/receipt details (
GET /payments/v1/receipt/:order_id) - Verifying and parsing async payment callbacks (RSA/SHA256 signature check)
Install
npm install bog-payments-sdkUsage
import { BogClient } from "bog-payments-sdk";
const bog = new BogClient({
clientId: process.env.BOG_CLIENT_ID!,
clientSecret: process.env.BOG_CLIENT_SECRET!,
});
const order = await bog.orders.createOrder({
callback_url: "https://example.com/bog/callback",
external_order_id: "id123",
purchase_units: {
currency: "GEL",
total_amount: 1,
basket: [{ product_id: "product123", quantity: 1, unit_price: 1 }],
},
redirect_urls: {
success: "https://example.com/success",
fail: "https://example.com/fail",
},
});
// Redirect the customer here to complete payment:
order._links.redirect.href;Fetching payment details
const details = await bog.orders.getPaymentDetails(order.id);
details.order_status.key; // "completed" | "rejected" | ...Handling callbacks
Verify the Callback-Signature header against the raw, unparsed request body
before trusting the payload. Use your framework's raw-body middleware (do not let
it be re-serialized — field order must be preserved).
import { parseVerifiedCallback } from "bog-payments-sdk";
// Express example, with a raw-body parser mounted only on this route:
app.post("/bog/callback", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.header("Callback-Signature");
if (!signature) return res.sendStatus(400);
try {
const callback = parseVerifiedCallback(req.body, signature);
// callback.body.order_id, callback.body.order_status, ...
} catch {
return res.sendStatus(400);
}
res.sendStatus(200);
});If you only need a boolean check (e.g. you're parsing the body separately), use
verifyCallbackSignature(rawBody, signature) instead.
Idempotency, locale, and theme
createOrder accepts a third options argument for the optional request headers:
await bog.orders.createOrder(request, {
idempotencyKey: crypto.randomUUID(),
acceptLanguage: "en",
theme: "dark",
});Buy Now Pay Later / Installment plan modal
The installment plan "loan calculator" modal (BOG.Calculator.open(...)) is a separate
browser widget, loaded directly on your page — it is not part of this SDK:
<script src="https://webstatic.bog.ge/bog-sdk/bog-sdk.js?version=2&client_id={client_id}"></script>This SDK covers the backend leg: once the customer picks an installment plan in the
modal, its onRequest(selected, successCb, closeCb) callback fires with
{ amount, month, discount_code }. POST that to your backend, create the order via
createLoanOrder, and return the resulting order id so the modal can continue:
// Frontend
BOG.Calculator.open({
amount: 500,
onRequest: (selected, successCb, closeCb) => {
fetch("/api/bog/loan-order", {
method: "POST",
body: JSON.stringify(selected),
})
.then((res) => res.json())
.then((data) => successCb(data.orderId))
.catch(() => closeCb());
},
onComplete: ({ redirectUrl }) => {
// customer is auto-redirected unless you return false here
},
});// Backend route (e.g. POST /api/bog/loan-order)
const order = await bog.orders.createLoanOrder(
selected, // { amount, month, discount_code } from the modal
{
callback_url: "https://example.com/bog/callback",
purchase_units: {
basket: [{ product_id: "product123", quantity: 1, unit_price: selected.amount }],
},
redirect_urls: {
success: "https://example.com/success",
fail: "https://example.com/fail",
},
},
);
res.json({ orderId: order.id });createLoanOrder sets config.loan = { type: discount_code, month } and defaults
payment_method to ["bog_loan"] and purchase_units.total_amount to selected.amount
— pass payment_method: ["bnpl"] in the request to use the Buy Now Pay Later plan instead,
or override any other field as needed.
Google Pay™ on your own webpage
If you render the Google Pay button on your own webpage (instead of redirecting to the
bank's hosted payment page), configure Google's
PaymentRequest with:
{
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "georgiancard",
"gatewayMerchantId": "BCR2DN4TXKPITITV"
}
}Once the customer authorizes the payment, Google's SDK returns an encrypted payment
token (paymentMethodData.tokenizationData.token). Pass it — full and unmodified — to
createGooglePayOrder:
const order = await bog.orders.createGooglePayOrder(
googlePayToken, // raw token string from the Google Pay SDK response
{
callback_url: "https://example.com/bog/callback",
purchase_units: {
currency: "GEL",
total_amount: 1,
basket: [{ product_id: "product123", quantity: 1, unit_price: 1 }],
},
},
);
if (order._links.redirect) {
// 3DS authentication is required — redirect the customer to complete it
order._links.redirect.href;
} else {
// payment is already finalized
order.status;
order.order_details;
}createGooglePayOrder sets payment_method: ["google_pay"] and
config.google_pay = { external: true, google_pay_token: googlePayToken }. The response's
_links.redirect is only present when 3DS authentication is required; otherwise the order
completes immediately and status/order_details describe the result.
Response codes
payment_detail.code/code_description (and actions[].code/code_description) are
bank-defined codes. The SDK ships lookup tables and helpers so you don't have to hardcode
them:
import {
isSuccessfulPaymentCode,
getPaymentResponseCodeDescription,
getActionResponseCodeDescription,
} from "bog-payments-sdk";
const details = await bog.orders.getPaymentDetails(orderId);
isSuccessfulPaymentCode(details.payment_detail?.code); // true for code "100"
getPaymentResponseCodeDescription(details.payment_detail?.code); // { en, ka } or undefined
details.actions?.forEach((action) => {
getActionResponseCodeDescription(action.code); // { en, ka } or undefined, e.g. for refund failures
});PAYMENT_RESPONSE_CODES and ACTION_RESPONSE_CODES are also exported directly if you need
the full maps (e.g. to render a description in the customer's own response, server-side
logging, etc).
Error handling
BogAuthError— thrown when the OAuth token request fails.BogApiError— thrown when an Orders API call returns a non-2xx response. Carriesstatus,body, and (when present)requestId.
Custom endpoints / sandbox
new BogClient({
clientId,
clientSecret,
tokenUrl: "https://oauth2.bog.ge/auth/realms/bog/protocol/openid-connect/token",
apiBaseUrl: "https://api.bog.ge/payments/v1",
});License
MIT
