@ivorypay/node-sdk
v1.0.0
Published
Official Node.js SDK for the IvoryPay Merchant API
Maintainers
Readme
IvoryPay Node.js SDK
Official Node.js SDK for the IvoryPay Merchant API. Accept crypto and fiat payments, send payouts, query rates, and verify webhooks — all with full TypeScript support.
Table of Contents
- Installation
- Quick Start
- Configuration
- Authentication
- Modules
- Error Handling
- TypeScript Support
- Supported Values
- Environments
Installation
npm install @ivorypay/node-sdk
# or
yarn add @ivorypay/node-sdkQuick Start
import { IvoryPay } from '@ivorypay/node-sdk';
const ivorypay = new IvoryPay({
secretKey: process.env.IVORYPAY_SECRET_KEY,
});
// Accept a crypto payment
const { data } = await ivorypay.transactions.create({
amount: 5000,
baseFiat: 'NGN',
token: 'USDT',
channel: 'CRYPTO',
network: 'BSC_MAINNET',
reference: 'order_abc123',
email: '[email protected]',
});
console.log(data.collectionDetails); // { network, address }
console.log(data.amountInCrypto); // amount customer should send
console.log(data.expiresAt); // session expiryConfiguration
const ivorypay = new IvoryPay({
secretKey: 'sk_test_xxxxxxxxxxxx', // required
baseUrl: 'https://api.ivorypay.io/api', // optional — override for local testing
});| Option | Type | Required | Description |
| ----------- | -------- | -------- | --------------------------------------------------------------- |
| secretKey | string | Yes | Your secret API key from the IvoryPay dashboard |
| baseUrl | string | No | Override the API base URL. Defaults to https://api.ivorypay.io/api |
Authentication
IvoryPay uses secret API keys for authentication. Your key is sent directly in the Authorization header — no Bearer prefix.
Authorization: sk_test_xxxxxxxxxxxx- Keys prefixed with
sk_test_point to the TEST (sandbox) environment - Keys prefixed with
sk_live_point to the LIVE (production) environment
Security: Never expose your secret key in frontend code, version control, or logs. Always load it from environment variables.
Modules
Transactions (Accept Payments)
Create payment requests and let customers pay with crypto or fiat.
ivorypay.transactions.create(input)
// CRYPTO payment
const { data } = await ivorypay.transactions.create({
amount: 5000, // amount in baseFiat
baseFiat: 'NGN', // NGN or USD
token: 'USDT', // crypto token to accept
channel: 'CRYPTO',
network: 'BSC_MAINNET',
reference: 'order_001', // must be unique per transaction
email: '[email protected]',
});
// data.collectionDetails => { network, address }
// Share this address with your customer so they can pay
// FIAT payment
const { data } = await ivorypay.transactions.create({
amount: 5000,
baseFiat: 'NGN',
token: 'USDT',
channel: 'FIAT',
fiatCurrency: 'NGN', // currency the customer pays in
reference: 'order_002',
email: '[email protected]',
});
// data.collectionDetails => { accountName, accountNumber, bankName }
// Show these bank details to your customer for paymentInput fields:
| Field | Type | Required | Description |
| -------------- | -------- | ---------------- | ---------------------------------------------- |
| amount | number | Yes | Amount in base fiat |
| baseFiat | string | Yes | NGN or USD |
| token | string | Yes | USDT or USDC |
| channel | string | Yes | CRYPTO or FIAT |
| reference | string | Yes | Unique transaction reference |
| email | string | Yes | Customer email |
| network | string | CRYPTO only | Blockchain network |
| fiatCurrency | string | FIAT only | Fiat currency for the payment |
ivorypay.transactions.verify(reference)
Verify the status of any transaction. Useful for polling before webhooks arrive.
const { data } = await ivorypay.transactions.verify('order_001');
console.log(data.status); // PENDING | PROCESSING | CONFIRMING | SUCCESS | FAILED | EXPIRED | MISMATCHBusiness Transactions
Verify and manage transactions using your secret key for additional settlement details.
ivorypay.businessTransactions.verify(reference)
const { data } = await ivorypay.businessTransactions.verify('order_001');
console.log(data.settledAmountInCrypto);
console.log(data.receivedAmountInCrypto);
console.log(data.completedAt);ivorypay.businessTransactions.refresh(reference, fiatCurrency?)
Refresh an expired CRYPTO payment session, extending validity by 10 minutes.
const { data } = await ivorypay.businessTransactions.refresh('order_001', 'NGN');Crypto Transfer
Send crypto directly to a wallet address.
ivorypay.cryptoTransfer.initiate(input)
const { data } = await ivorypay.cryptoTransfer.initiate({
amount: 10, // amount in crypto
token: 'USDT',
network: 'BSC_MAINNET',
address: '0xRecipientWalletAddress',
reference: 'payout_001', // must be unique
});Input fields:
| Field | Type | Required | Description |
| ----------- | -------- | -------- | ----------------------------- |
| amount | number | Yes | Amount in crypto |
| token | string | Yes | Token to send |
| network | string | Yes | Blockchain network |
| address | string | Yes | Recipient wallet address |
| reference | string | Yes | Unique payout reference |
ivorypay.cryptoTransfer.getNetworks(token)
const { data } = await ivorypay.cryptoTransfer.getNetworks('USDT');
// data => ['BSC_MAINNET', 'POLYGON', ...]ivorypay.cryptoTransfer.getSupportedTokens()
const { data } = await ivorypay.cryptoTransfer.getSupportedTokens();Fiat Transfer
Send fiat to a bank account or mobile money wallet.
ivorypay.fiatTransfer.resolveAccount(input)
Always resolve the account first to verify the recipient before sending funds.
const { data } = await ivorypay.fiatTransfer.resolveAccount({
accountNumber: '0123456789',
bankCode: '058',
currency: 'NGN',
});
console.log(data.accountName); // verify this with your customerivorypay.fiatTransfer.initiate(input)
const { data } = await ivorypay.fiatTransfer.initiate({
amount: 50, // amount in crypto (debited from wallet)
token: 'USDT',
fiatCurrency: 'NGN', // currency recipient receives
payoutMethod: 'BANK_TRANSFER',
accountNumber: '0123456789',
bankCode: '058',
reference: 'payout_002',
});Input fields:
| Field | Type | Required | Description |
| --------------- | -------- | -------- | ---------------------------------------- |
| amount | number | Yes | Amount in crypto to debit |
| token | string | Yes | USDT or USDC |
| fiatCurrency | string | Yes | Fiat currency the recipient receives |
| payoutMethod | string | Yes | BANK_TRANSFER or MOBILE_MONEY |
| accountNumber | string | Yes | Recipient account number |
| bankCode | string | Yes | Bank code from getBanks() |
| reference | string | Yes | Unique payout reference |
ivorypay.fiatTransfer.getBanks()
const { data } = await ivorypay.fiatTransfer.getBanks();
// data => [{ id, name, code, country, currency }, ...]Rates
Fetch conversion rates and fee estimates before initiating a transfer. Use these to show your users the exact amounts they will send and receive.
ivorypay.rates.fiatTransfer(input)
const { data } = await ivorypay.rates.fiatTransfer({
amount: 100,
token: 'USDT',
fiatCurrency: 'NGN',
});
console.log(data.rate); // current exchange rate
console.log(data.platformFeeInFiat); // IvoryPay fee in fiat
console.log(data.amountInFiatLessFee); // recipient receives thisivorypay.rates.cryptoTransfer(input)
const { data } = await ivorypay.rates.cryptoTransfer({
amount: 10,
token: 'USDT',
network: 'BSC_MAINNET',
});
console.log(data.gasFeeInCrypto);
console.log(data.platformFeeInCrypto);ivorypay.rates.fiatCollection(input)
const { data } = await ivorypay.rates.fiatCollection({
amount: 5000,
token: 'USDT',
fiatCurrency: 'NGN',
});ivorypay.rates.cryptoCollection(input)
const { data } = await ivorypay.rates.cryptoCollection({
amount: 5000,
token: 'USDT',
fiatCurrency: 'NGN',
});Blockchain Accounts
Create permanent, dedicated blockchain deposit addresses for your customers. Any deposit to these addresses automatically credits your business wallet.
ivorypay.blockchainAccounts.create(input)
const { data } = await ivorypay.blockchainAccounts.create({
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
blockchain: 'BSC_MAINNET', // BSC_TESTNET for TEST keys
token: 'USDT',
phoneNumber: '+2348012345678', // optional
});
console.log(data.address); // permanent deposit address
console.log(data.customerId); // your reference to this customerIdempotent: Calling this with the same email + blockchain + token returns the existing address rather than creating a new one.
Input fields:
| Field | Type | Required | Description |
| ------------- | -------- | -------- | ------------------------------------- |
| firstName | string | Yes | Customer first name |
| lastName | string | Yes | Customer last name |
| email | string | Yes | Customer email (unique identifier) |
| blockchain | string | Yes | BSC_MAINNET or POLYGON |
| token | string | Yes | USDT or USDC |
| phoneNumber | string | No | Customer phone number |
Tokens
ivorypay.tokens.getSupportedTokens()
Get all tokens and networks currently enabled for your business.
const { data } = await ivorypay.tokens.getSupportedTokens();ivorypay.tokens.getNetworks(token)
const { data } = await ivorypay.tokens.getNetworks('USDT');Webhooks
IvoryPay sends webhook notifications to your registered URL when transaction events occur.
ivorypay.webhooks.verifySignature(rawBody, signature, secret)
Always verify the webhook signature before processing any event.
Important: Use the raw request body (before any JSON parsing) for verification. With Express, use
express.raw()on your webhook route.
import express from 'express';
import { IvoryPay, WebhookPayload } from '@ivorypay/node-sdk';
const ivorypay = new IvoryPay({ secretKey: process.env.IVORYPAY_SECRET_KEY });
app.post(
'/webhooks/ivorypay',
express.raw({ type: 'application/json' }),
(req, res) => {
const rawBody = req.body.toString();
const signature = req.headers['x-ivorypay-signature'] as string;
const isValid = ivorypay.webhooks.verifySignature(
rawBody,
signature,
process.env.IVORYPAY_WEBHOOK_SECRET,
);
if (!isValid) {
return res.status(401).json({ message: 'Invalid signature' });
}
const payload = ivorypay.webhooks.parse(rawBody);
switch (payload.event) {
case 'cryptoCollection.success':
// fulfill the order
await fulfillOrder(payload.data.reference);
break;
case 'fiatCollection.success':
await fulfillOrder(payload.data.reference);
break;
case 'cryptoPayout.success':
// mark payout as completed
break;
case 'fiatPayout.failed':
// handle failed payout
break;
}
res.sendStatus(200); // always return 200 to acknowledge receipt
},
);Supported webhook events:
| Event | Description |
| ------------------------------- | ----------------------------------------- |
| cryptoCollection.success | Crypto payment received successfully |
| cryptoCollection.failed | Crypto payment failed |
| cryptoCollection.mismatch | Wrong amount received |
| fiatCollection.success | Fiat payment received successfully |
| fiatCollection.failed | Fiat payment failed |
| cryptoPayout.success | Crypto transfer completed |
| cryptoPayout.failed | Crypto transfer failed |
| fiatPayout.success | Fiat transfer completed |
| fiatPayout.failed | Fiat transfer failed |
| cryptoSettlement.success | Crypto settlement completed |
| fiatSettlement.success | Fiat settlement completed |
| swap.success | Swap completed |
| swap.failed | Swap failed |
| cryptoCollectionRefund.success| Crypto collection refund sent |
| fiatCollectionRefund.success | Fiat collection refund sent |
| permanentWalletDeposit.success| Deposit to blockchain address received |
Error Handling
All SDK methods throw an IvoryPayError on failure. Always wrap your calls in try/catch.
import { IvoryPay, IvoryPayError } from '@ivorypay/node-sdk';
try {
const { data } = await ivorypay.transactions.create({ ... });
} catch (error) {
if (error instanceof IvoryPayError) {
console.error(error.message); // human-readable message
console.error(error.statusCode); // HTTP status code
console.error(error.raw); // full raw API response
}
}Common error status codes:
| Status | Meaning |
| ------ | --------------------------------------------------- |
| 400 | Bad request — check your input fields |
| 401 | Unauthorized — invalid or missing API key |
| 404 | Resource not found |
| 422 | Unprocessable — e.g. duplicate reference |
| 500 | Server error — retry with exponential backoff |
TypeScript Support
The SDK is written entirely in TypeScript and ships with full type declarations. All inputs and responses are typed.
import type {
CreateTransactionInput,
CreateTransactionResponse,
InitiateFiatTransferInput,
WebhookPayload,
WebhookEvent,
SupportedToken,
SupportedNetwork,
SupportedFiatCurrency,
TransactionStatus,
IvoryPayResponse,
} from '@ivorypay/node-sdk';Supported Values
Tokens
| Value | Description |
| ------ | --------------------- |
| USDT | Tether USD |
| USDC | USD Coin |
| BTC | Bitcoin |
| ETH | Ethereum |
| SOL | Solana |
Networks
| Value | Description |
| ------------- | ----------------------- |
| BSC_MAINNET | BNB Smart Chain |
| BSC_TESTNET | BNB Smart Chain Testnet |
| POLYGON | Polygon (MATIC) |
| ETH | Ethereum |
| TRON | Tron |
| SOLANA | Solana |
| BITCOIN | Bitcoin |
Fiat Currencies
| Value | Description |
| ----- | --------------- |
| NGN | Nigerian Naira |
| KES | Kenyan Shilling |
| GHS | Ghanaian Cedi |
| ZAR | South African Rand |
| USD | US Dollar |
Transaction Statuses
| Value | Description |
| ------------ | --------------------------------------------- |
| PENDING | Awaiting payment from customer |
| PROCESSING | Payment detected, being confirmed |
| CONFIRMING | Awaiting blockchain confirmations |
| SUCCESS | Payment confirmed and settled |
| FAILED | Payment failed |
| EXPIRED | Session expired before payment was received |
| MISMATCH | Wrong amount was sent by the customer |
Environments
| Environment | Key Prefix | Description |
| ----------- | ----------- | -------------------------------------- |
| TEST | sk_test_ | Sandbox — no real funds move |
| LIVE | sk_live_ | Production — real transactions |
Always build and test with sk_test_ keys. Switch to sk_live_ only when you are ready to go live.
License
MIT
