API Reference
The BoomPay SDK contract, read directly from the BoomDotMarket/BoomPay source — endpoints, methods, the payment lifecycle, and exactly how the return signature is verified.
Package name correction. The repo's README tells you to run npm install boompay-sdk. That package does not exist on npm. The SDK is actually published as boom-pay-sdk (note the hyphens) — confirmed against the npm registry, currently at 2.0.2. Every install command on this site uses the correct, real name.
How the payment lifecycle works
BoomPay is a redirect-based gateway settling in a single cryptocurrency, Boomcoin (BMC). There is no card field and no inline widget to embed — your server creates a payment intent, sends the shopper to a hosted link to approve it from their Boom wallet, and then verifies a signed return to your own success or failure URL before marking the order paid. Everything below this point is in service of that one loop.
Authentication & environments
Every request authenticates with a single API key, sent as the x-api-key header. There is no OAuth flow, no client secret, and no signing of outgoing requests — only of the return callback (see Verifying the return). The key itself determines which wallet payments settle into, since wallets are tied 1:1 to an API key and created from the Boom mobile app, not the SDK.
| Environment | Base URL | When to use it |
|---|---|---|
| Sandbox | https://sapi.boom.market |
Set sandbox: true. Use for all development and the platform sandbox/test modes referenced throughout these docs. |
| Production | https://api.boom.market |
Default when sandbox is omitted or false. Real BMC moves here. |
Install & initialize
For any Node.js backend (the Shopify, BigCommerce, Wix, Ecwid, and custom-checkout integrations on this site all start here):
npm install boom-pay-sdk
const BoomPay = require('boom-pay-sdk');
const boomPay = new BoomPay({
apiKey: process.env.BOOMPAY_API_KEY,
sandbox: process.env.NODE_ENV !== 'production', // optional, defaults to false
});
Or with TypeScript / ES modules:
import BoomPay from 'boom-pay-sdk';
const boomPay = new BoomPay({ apiKey: process.env.BOOMPAY_API_KEY!, sandbox: true });
The constructor throws synchronously (not a rejected promise) if you omit the options object or the apiKey field — wrap construction in your app's normal startup error handling, not a request handler's try/catch.
REST endpoints (language-agnostic)
For every platform on this site that isn't Node.js, the plugin talks to these two resources directly over HTTPS. This is the same surface the JS SDK calls internally — there is no hidden functionality the SDK has that a direct REST call doesn't.
| Method & path | Purpose | Auth |
|---|---|---|
POST /v1/boompay/paymentIntent |
Create a payment intent. | x-api-key header |
GET /v1/boompay/paymentIntent/{id} |
Retrieve a payment intent by UUID. | x-api-key header |
GET /v1/boompay/wallet |
Retrieve the default wallet tied to this API key. | x-api-key header |
Create a payment intent
const payment = await boomPay.payments.createIntent({
amount: 5,
successUrl: 'https://your-store.com/boompay/return?status=success',
failureUrl: 'https://your-store.com/boompay/return?status=failure',
label: 'Order #1042',
metadata: { orderId: '1042', customerId: 'cus_88f1' },
});
// payment.link -> redirect the shopper here
// payment.id -> store this against the order; you'll need it to verify the return
| Field | Type | Required | Notes |
|---|---|---|---|
amount |
number | Yes | Denominated in BMC. There is no currency field — it was removed in v2.0.0 alongside multi-currency wallets. Convert fiat to a BMC amount yourself before calling this. |
successUrl |
string (URL) | Yes | Must parse as a valid URL or the call throws client-side before any network request is made. |
failureUrl |
string (URL) | Yes | Same validation as successUrl. |
label |
string | Yes | Shown to the shopper on BoomPay's hosted payment page. |
metadata |
object | No | Round-tripped back to you untouched on getPayment(). This is where every integration on this site stashes its own order ID. |
The returned PaymentIntentInstance:
| Field | Type | Notes |
|---|---|---|
id |
string (UUID) | Pass this to getPayment() later. |
link |
string (URL) | BoomPay's hosted payment page. Redirect the shopper's browser here — this is the entire checkout UI. |
walletAddress |
string | The merchant wallet the funds settle into. |
amount |
number | Echoes what you sent. |
label, metadata |
string, object | Echo what you sent. |
state |
string | See payment state below — the SDK types this loosely. |
createdAt, paidAt |
string (ISO timestamp) | paidAt is empty/absent until the shopper pays. |
isSent |
boolean | Internal delivery flag; not generally something you need to branch on. |
All required-field and URL-format validation happens synchronously, before any HTTP request is sent. A missing label or a malformed successUrl throws immediately rather than rejecting a promise — so a plain try/catch around the call catches both the validation throw and any later network/API error.
Retrieve a payment
const payment = await boomPay.payments.getPayment('8f2c1a90-...-41ab');
if (payment.state === 'paid' || payment.paidAt) {
// fulfil the order
}
getPayment() validates that the id you pass is a syntactically valid UUID before making a request, and throws Invalid id, expected an UUID. if not.
A note on payment state
The SDK types state as a plain string, not an enum — the source doesn't pin down the exact set of values, so this site doesn't invent one either. In practice you will see something like a pending value before payment and a paid-style value after, but treat the literal string as informational rather than something to hardcode a switch statement against. The more robust check used throughout every integration on this site is whichever is simplest for that platform: branch on which URL BoomPay returned the shopper to (successUrl vs failureUrl) and then confirm with a fresh getPayment() call rather than pattern-matching state directly.
Retrieve the default wallet
const wallet = await boomPay.wallets.getDefaultWallet();
// { address: '0x...', balance: 128.4 }
Wallets are created and managed from the Boom mobile app, not the SDK — createWallet() and getWallet() existed in v1.0.0 and were removed in the v2.0.0 migration to one BMC wallet per merchant. getDefaultWallet() is read-only and mostly useful for a balance check or for confirming which address you expect funds to land in.
Verifying the return
This is the part every integration on this site has to get right, so it's worth being precise about a detail the README glosses over: this is not an asynchronous server-to-server webhook. It's a signed redirect. BoomPay sends the shopper's browser back to whichever of successUrl / failureUrl applies, with two query string parameters appended:
| Query parameter | Meaning |
|---|---|
paymentIntentId |
The id of the intent that resolved. |
X-Boom-Signature |
An HMAC signature, despite the header-style name — it arrives as a query parameter, not an HTTP header. |
In Express, the SDK exposes this as middleware you mount directly on your success/failure route:
app.get('/boompay/return', boomPay.webhooks(), (req, res) => {
// Only reached if the signature was valid.
const paymentIntentId = req.query.paymentIntentId;
// ... look up the order by paymentIntentId, call getPayment(), fulfil it
res.redirect('/order-confirmation');
});
boomPay.webhooks() takes no arguments that affect behaviour — the API key it checks against was already bound when you called new BoomPay({ apiKey }). You may see older examples passing { apiKey: '...' } into .webhooks() itself; that argument is silently ignored by the current source, so don't rely on it.
For every non-Express platform on this site, here is the exact scheme to reimplement by hand:
signature_we_expect = base64( HMAC_SHA1( key = apiKey, message = paymentIntentId ) )
is_valid = constant_time_equals(
received_signature.replace(" ", "+"), // some query-string parsers turn "+" into a space
signature_we_expect
)
The +-to-space replacement matters: base64 signatures can contain literal + characters, and some URL decoders turn an unencoded + into a space. The official SDK works around this by replacing whitespace back to + before comparing — every PHP/manual implementation on this site does the same thing. Always compare with a constant-time / timing-safe comparison, never == or === on raw strings.
Error handling
A non-2xx response throws a RestException (extends Error) with a status field (the HTTP status code) and a message drawn from the response body, plus optional key / id fields when the API provides them. Every method also accepts an optional trailing Node-style callback if you'd rather not use promises:
try {
const wallet = await boomPay.wallets.getDefaultWallet();
} catch (error) {
console.error(error.status, error.message);
}
// or, callback style:
boomPay.wallets.getDefaultWallet((error, wallet) => {
if (error) { /* ... */ return; }
console.log(wallet);
});
The underlying HTTP client automatically retries up to 3 times with up to a 3 second delay specifically on 429 Too Many Requests responses, and uses a 30 second request timeout by default. You don't need to implement your own retry loop around these calls.
Currency
The published type definitions export a broader CurrencyIso union (BMC, EUR, USD, GBP, NGN, INR, XOF, ZAR, GHS, THB, IDR, BRL, MAD, TRY, ILS) but, as of v2.0.0, no public method actually accepts a currency parameter — it's vestigial in the current surface. Every amount is BMC. There is no exchange-rate or FX-conversion endpoint in this API, so if your store prices in fiat, converting to a BMC-equivalent amount before calling createIntent() is on you.
Security notes
- The API key must only ever live in server-side code or environment variables — never in a theme file, a storefront
<script>, a mobile app bundle, or a Squarespace code block. Every integration on this site keeps it server-side. - Always verify the return signature server-side before trusting
paymentIntentId; don't fulfil an order purely because the browser landed on your success URL. - Treat
metadataas data you wrote, not data to trust blindly back — it's round-tripped verbatim, so validate it against your own order records rather than acting on it directly.
Changelog, summarized
| Version | What changed |
|---|---|
2.0.0 (2024-01-29) |
Migrated from multi-currency, multi-wallet support to a single BMC wallet per merchant. createIntent() no longer takes walletAddress or currency. Added wallets.getDefaultWallet(); removed createWallet() and getWallet(). |
1.0.0 (2023-06-16) |
Initial public release: multiple wallets per currency, payment intents tied to a specific wallet, payment retrieval. |
Read the full source at github.com/BoomDotMarket/BoomPay.