apibill-billing-sdk
v1.1.4
Published
JavaScript/TypeScript SDK for ApiBill Client API — billing info, invoices, payments, and restriction middleware for admin panels
Maintainers
Readme
@nextive/billing-sdk
JavaScript/TypeScript SDK for ApiBill Client API. Embed billing info, invoices, payments, and restriction middleware into any admin panel.
Works with Nuxt 3/4, Vue 3 + Vuetify, React, or any JavaScript project.
Installation
# npm
npm install @nextive/billing-sdk
# yarn
yarn add @nextive/billing-sdk
# Or install from git
npm install git+https://github.com/Nextive-Solution/apibill-js-sdk.gitQuick Start
import { ApiBillClient } from '@nextive/billing-sdk'
const billing = new ApiBillClient({
siteId: 'YOUR_SITE_ID',
apiUrl: 'https://your-api.com/api',
})
// Get billing summary
const summary = await billing.getBillingSummary()
console.log(summary.billing.totalDue) // 5225.32
console.log(summary.billing.restrictionActive) // true/false
// Check restriction
const blocked = await billing.isRestricted()
// List unpaid invoices
const invoices = await billing.getInvoices('unpaid')
// Pay an invoice (redirects to bKash)
const { gatewayUrl } = await billing.payInvoice('invoice_id')
window.location.href = gatewayUrlAPI Reference
new ApiBillClient(config)
| Option | Type | Required | Description |
|---|---|---|---|
| siteId | string | Yes | Your Site ID from ApiBill admin panel |
| apiUrl | string | Yes | ApiBill API base URL (e.g. https://your-api.com/api) |
| fetch | typeof fetch | No | Custom fetch implementation (defaults to global fetch) |
| onRestriction | (summary) => void | No | Called when restrictionActive is true |
| cacheTtl | number | No | Cache TTL in ms for billing summary (default: 300000 = 5 min) |
Methods
Billing Summary
// Get full billing summary (cached for cacheTtl)
const summary = await billing.getBillingSummary()
// Force refresh (skip cache)
const fresh = await billing.getBillingSummary(true)
// Check if restricted (shorthand)
const restricted = await billing.isRestricted() // boolean
// Check restriction + trigger onRestriction callback
const restricted = await billing.checkRestriction() // boolean
// Clear cache manually
billing.clearCache()Invoices
// List all invoices (paid + unpaid + partially_paid)
const all = await billing.getInvoices()
// Filter by status
const unpaid = await billing.getInvoices('unpaid')
const paid = await billing.getInvoices('paid')
const partial = await billing.getInvoices('partially_paid')
// Get single invoice
const invoice = await billing.getInvoice('invoice_id')
console.log(invoice.invoiceNumber) // 'NS0010001'
console.log(invoice.paidAmount) // 2000
console.log(invoice.dueAmount) // 3000
console.log(invoice.payments) // PaymentRecord[]
// Get last unpaid/partially paid invoice
const lastUnpaid = await billing.getLastUnpaidInvoice()
// Pay full due amount via bKash
const { gatewayUrl, paymentId, type } = await billing.payInvoice('invoice_id')
window.location.href = gatewayUrl
// Pay a specific pending payment (partial amount set by admin)
const pending = invoice.payments.find(p => p.status === 'pending')
if (pending) {
const { gatewayUrl } = await billing.payInvoice('invoice_id', pending.paymentId)
window.location.href = gatewayUrl
}Bank Transfer Notifications
// Notify admin that a bank transfer payment has been initiated.
// Sends an email + in-app notification to all admins so they can
// verify the transfer against their bank account and mark the invoice paid.
// For a regular invoice (default type)
await billing.notifyBankTransfer('invoice_id')
// For a custom invoice
await billing.notifyBankTransfer('custom_invoice_id', 'custom_invoice')Use this after displaying bank account details to the client so the admin is proactively alerted instead of having to poll their bank account.
Custom Invoices
// List custom invoices
const custom = await billing.getCustomInvoices()
const unpaidCustom = await billing.getCustomInvoices('unpaid')
const partialCustom = await billing.getCustomInvoices('partially_paid')
// Get single custom invoice
const invoice = await billing.getCustomInvoice('custom_invoice_id')
console.log(invoice.invoiceNumber) // 'NS0010006'
console.log(invoice.paidAmount) // 5000
console.log(invoice.dueAmount) // 10000
// Pay full due via bKash
const { gatewayUrl } = await billing.payCustomInvoice('custom_invoice_id')
window.location.href = gatewayUrl
// Pay a specific pending payment
const pending = invoice.payments.find(p => p.status === 'pending')
if (pending) {
const { gatewayUrl } = await billing.payCustomInvoice('custom_invoice_id', pending.paymentId)
window.location.href = gatewayUrl
}Response Types
BillingSummaryResponse
{
site: { _id: string, domain: string }
client: { name: string, email: string, phone: string | null } | null
plan: {
freeTier: number
ratePerThousand: number
bandwidthRatePerGb: number
bandwidthFreeTierGb: number
serviceCharge: number
maintenanceCharge: number
currency: string
} | null
billing: {
totalDue: number // Combined due from invoices + custom invoices
totalPaid: number // Total already paid across partial invoices
currency: string
unpaidCount: number
partiallyPaidCount: number // Number of partially paid invoices
restrictedCount: number // Number of restricted unpaid invoices
flexibleCount: number // Number of flexible unpaid invoices
restrictionActive: boolean // true = block admin panel access
}
invoices: {
totalDue: number
unpaidCount: number
nextDueDate: string | null
unpaid: UnpaidInvoice[]
}
customInvoices: {
totalDue: number
unpaidCount: number
nextDueDate: string | null
unpaid: UnpaidCustomInvoice[]
}
}Error Handling
import { ApiBillError } from '@nextive/billing-sdk'
try {
await billing.payInvoice('id')
} catch (err) {
if (err instanceof ApiBillError) {
console.log(err.statusCode) // 400, 404, etc.
console.log(err.response) // API response body
}
}Framework Integration
Nuxt 3/4
1. Add runtime config:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
apibillSiteId: process.env.APIBILL_SITE_ID || '',
apibillApiUrl: process.env.APIBILL_API_URL || '',
},
},
})2. Create plugin:
// app/plugins/apibill.ts
import { ApiBillClient } from '@nextive/billing-sdk'
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
const billing = new ApiBillClient({
siteId: config.public.apibillSiteId as string,
apiUrl: config.public.apibillApiUrl as string,
})
return { provide: { apibill: billing } }
})3. Create restriction middleware:
// app/middleware/billing-restriction.global.ts
import { ApiBillClient } from '@nextive/billing-sdk'
const EXCLUDED_ROUTES = ['/login', '/billing', '/billing/restricted']
export default defineNuxtRouteMiddleware(async (to) => {
// Skip excluded routes
if (EXCLUDED_ROUTES.some(r => to.path === r || to.path.startsWith(r + '/'))) return
// Skip on server side
if (import.meta.server) return
const { $apibill } = useNuxtApp()
if (!$apibill) return
try {
const restricted = await ($apibill as ApiBillClient).isRestricted()
if (restricted) {
return navigateTo('/billing/restricted')
}
} catch {
// Fail open — don't block on API errors
}
})4. Use in components:
<script setup>
const { $apibill } = useNuxtApp()
const summary = await $apibill.getBillingSummary()
</script>
<template>
<div v-if="summary.billing.unpaidCount > 0" class="alert">
You have {{ summary.billing.unpaidCount }} unpaid invoice(s).
Total due: {{ summary.billing.totalDue }} {{ summary.billing.currency }}
</div>
</template>5. Create a restricted page:
<!-- app/pages/billing/restricted.vue -->
<template>
<div class="flex items-center justify-center min-h-screen">
<div class="text-center max-w-md">
<h1 class="text-2xl font-bold text-red-600">Access Restricted</h1>
<p class="mt-2 text-gray-600">
Your access has been restricted due to overdue invoices.
Please pay your outstanding invoices to restore access.
</p>
<NuxtLink to="/billing" class="mt-4 inline-block px-4 py-2 bg-primary text-white rounded">
View Invoices
</NuxtLink>
</div>
</div>
</template>Vue 3 + Vuetify (or any Vue 3 project)
1. Initialize in main.ts:
// main.ts
import { initApiBill } from '@nextive/billing-sdk/vue'
initApiBill({
siteId: import.meta.env.VITE_APIBILL_SITE_ID,
apiUrl: import.meta.env.VITE_APIBILL_API_URL,
})2. Add router guard:
// router/index.ts
import { createBillingGuard } from '@nextive/billing-sdk/vue'
const router = createRouter({ ... })
router.beforeEach(createBillingGuard({
restrictedRoute: '/billing/restricted',
excludeRoutes: ['/login', '/billing', '/billing/restricted'],
}))3. Use in components:
<script setup>
import { useApiBill } from '@nextive/billing-sdk/vue'
import { ref, onMounted } from 'vue'
const billing = useApiBill()
const summary = ref(null)
onMounted(async () => {
summary.value = await billing.getBillingSummary()
})
</script>Vanilla JavaScript / Any Framework
import { ApiBillClient } from '@nextive/billing-sdk'
const billing = new ApiBillClient({
siteId: 'YOUR_SITE_ID',
apiUrl: 'https://your-api.com/api',
onRestriction: (summary) => {
// Show modal, redirect, etc.
window.location.href = '/billing/restricted'
},
})
// Check on app load
await billing.checkRestriction()
// Get data
const summary = await billing.getBillingSummary()
const invoices = await billing.getInvoices('unpaid')Billing Page Example
Create a billing page in your admin panel to show invoices and allow payment:
<script setup>
import { ApiBillClient } from '@nextive/billing-sdk'
const billing = new ApiBillClient({
siteId: 'YOUR_SITE_ID',
apiUrl: 'https://your-api.com/api',
})
const summary = ref(null)
const invoices = ref([])
const customInvoices = ref([])
const loading = ref(true)
onMounted(async () => {
const [s, inv, cinv] = await Promise.all([
billing.getBillingSummary(),
billing.getInvoices(),
billing.getCustomInvoices(),
])
summary.value = s
invoices.value = inv
customInvoices.value = cinv
loading.value = false
})
async function pay(invoiceId, type = 'invoice') {
const { gatewayUrl } = type === 'invoice'
? await billing.payInvoice(invoiceId)
: await billing.payCustomInvoice(invoiceId)
window.location.href = gatewayUrl
}
</script>Environment Variables
| Variable | Description |
|---|---|
| APIBILL_SITE_ID or VITE_APIBILL_SITE_ID | Your Site ID from ApiBill admin panel |
| APIBILL_API_URL or VITE_APIBILL_API_URL | ApiBill API base URL |
How restrictionActive Works
- If any unpaid invoice with mode
restrictedhas its due date fully passed (after 11:59 PM),restrictionActivebecomestrue - Invoices with mode
flexiblenever trigger restriction - If an invoice has an
extendedDueDate, that date is used instead ofdueDate - The SDK caches the billing summary (default 5 min) to avoid excessive API calls
License
MIT
