DottsPay
Guides

Node SDK

@dottspay/node is the official library for Node.js. It has no dependencies, uses the built-in fetch, ships full TypeScript types, and verifies webhook signatures for you.

Install

Shell
npm install @dottspay/node

Requires Node 18 or later. The package is ESM.

Create a client

dottspay.js
import { DottsPay } from '@dottspay/node'

export const dottspay = new DottsPay(process.env.DOTTSPAY_SECRET_KEY)

console.log(dottspay.mode) // 'test' or 'live', from the key

The constructor takes your secret key and an optional options object:

baseUrl
Defaulthttps://dottspay.hiddekellabs.com
What it doesRoot URL of the API server. /api/v1 is added for you.
timeout
Default30000
What it doesRequest timeout in milliseconds.
fetch
DefaultglobalThis.fetch
What it doesA custom fetch, useful in tests.

Passing a public key (pk_…) or anything that is not a secret key throws straight away, so a misconfigured environment fails loudly.

Methods

Every method returns a promise. Single objects resolve to the object itself, without the { status, message, data } envelope. List methods resolve to { data, meta: { page, perPage, total } }.

checkout.create(params, { idempotencyKey })
EndpointPOST /checkout/sessions
ReturnsCheckoutSession
checkout.retrieve(id)
EndpointGET /checkout/sessions/{id}
ReturnsCheckoutSession
transactions.list(params)
EndpointGET /transactions
ReturnsPage<Transaction>
transactions.verify(reference)
EndpointGET /transactions/{reference}
ReturnsTransaction
refunds.create(params, { idempotencyKey })
EndpointPOST /refunds
ReturnsRefund
paymentLinks.list(params)
EndpointGET /payment-links
ReturnsPage<PaymentLink>
paymentLinks.create(params, { idempotencyKey })
EndpointPOST /payment-links
ReturnsPaymentLink
paymentLinks.retrieve(id)
EndpointGET /payment-links/{id}
ReturnsPaymentLink
paymentLinks.update(id, params)
EndpointPATCH /payment-links/{id}
ReturnsPaymentLink
customers.list(params)
EndpointGET /customers
ReturnsPage<Customer>
banks.list(currency)
EndpointGET /banks
ReturnsBank[]
banks.resolve(accountNumber, bankCode)
EndpointGET /banks/resolve
Returns{ account_name }
balance.retrieve()
EndpointGET /balance
ReturnsBalance[]

Parameter names match the API exactly, so the API reference doubles as SDK reference.

Take a payment

JavaScript
const session = await dottspay.checkout.create(
  {
    amount: 500000, // ₦5,000 in kobo
    email: 'ada@example.com',
    callback_url: 'https://yourshop.com/payment/callback',
    metadata: { order_id: 'ord_1042' },
  },
  { idempotencyKey: 'order-1042' },
)

// Later, when the customer returns with ?reference=dp_...
const tx = await dottspay.transactions.verify(reference)
if (tx.status === 'success' && tx.amount === 500000) {
  // give value
}

Refund part of a payment

JavaScript
const refund = await dottspay.refunds.create(
  { reference: 'dp_Hk2pQx9LmT4sWb7NcY', amount: 200000, reason: 'One item returned' },
  { idempotencyKey: 'refund-ord_1042-1' },
)
console.log(refund.status) // 'pending'
JavaScript
const link = await dottspay.paymentLinks.create({
  title: 'Small chops tray',
  amount: 2500000,
  stock_limit: 50,
})
console.log(link.url)

await dottspay.paymentLinks.update(link.id, { active: false })

Page through transactions

JavaScript
let page = 1
while (true) {
  const { data, meta } = await dottspay.transactions.list({
    status: 'success',
    from: new Date('2026-10-01'), // Date objects or ISO strings
    perPage: 100,
    page,
  })
  for (const tx of data) console.log(tx.reference, tx.net)
  if (page * meta.perPage >= meta.total) break
  page++
}

Confirm a bank account

JavaScript
const banks = await dottspay.banks.list('NGN')
const { account_name } = await dottspay.banks.resolve('0123456789', '058')

Errors

Any failed call throws a DottsPayError with the HTTP status, the API's code, and a readable message. See the error codes.

JavaScript
import { DottsPayError } from '@dottspay/node'

try {
  await dottspay.refunds.create({ reference: 'dp_Hk2pQx9LmT4sWb7NcY' })
} catch (err) {
  if (err instanceof DottsPayError) {
    console.log(err.status) // 422
    console.log(err.code) // 'validation_error'
    console.log(err.message)
  } else {
    throw err
  }
}

When a request never gets a response, status is 0 and code is network_error or timeout. The SDK does not retry on its own. If you retry a create call, pass the same idempotencyKey so it cannot happen twice.

Webhooks

The webhook helpers are static, so you can use them without a client. Pass the raw body as a string or Buffer.

  • DottsPay.webhooks.verify(rawBody, signature, secret) returns true or false.
  • DottsPay.webhooks.constructEvent(rawBody, signature, secret) verifies, then returns the parsed, typed event. It throws a DottsPayError with code invalid_signature if the signature does not match.
JavaScript
app.post('/webhooks/dottspay', express.raw({ type: 'application/json' }), (req, res) => {
  let event
  try {
    event = DottsPay.webhooks.constructEvent(
      req.body,
      req.get('X-DottsPay-Signature'),
      process.env.DOTTSPAY_WEBHOOK_SECRET,
    )
  } catch {
    return res.sendStatus(400)
  }
  res.sendStatus(200)
  // event.event is 'charge.success' | 'charge.failed' | 'refund.created' | 'payout.paid' | 'payout.failed'
})

More detail, including PHP, is in the webhooks guide.

TypeScript

Every object, parameter and event is typed. Import the types you need:

TypeScript
import type { Transaction, CheckoutSession, Refund, PaymentLink, WebhookEvent } from '@dottspay/node'

function onEvent(event: WebhookEvent) {
  if (event.event === 'charge.success') {
    const tx: Transaction = event.data // narrowed by the event name
  }
}