A modern, type-safe TypeScript SDK for the Steadfast Courier Limited API with comprehensive webhook support.
- ✅ Full TypeScript Support - Complete type definitions for all API endpoints
- ✅ Webhook Handling - Built-in webhook handlers for Express, Fastify, and generic frameworks
- ✅ Input Validation - Automatic validation of request parameters
- ✅ Error Handling - Custom error classes with detailed error messages
- ✅ Framework Agnostic - Works with any Node.js framework
- ✅ Tree-shakeable - Optimized for bundle size
- ✅ Well Documented - Comprehensive documentation and examples
# npm
npm install steadfast-courier
# yarn
yarn add steadfast-courier
# pnpm
pnpm add steadfast-courierIf you're using TypeScript and importing from 'steadfast-courier/webhooks', you must update your tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "node16" // or "nodenext" or "bundler"
}
}Without this, you'll get: Cannot find module 'steadfast-courier/webhooks'
See TypeScript Support section for more details.
import { SteadfastClient } from 'steadfast-courier';
// Initialize the client
const client = new SteadfastClient({
apiKey: 'your-api-key',
secretKey: 'your-secret-key',
});
// Create an order
const order = await client.orders.createOrder({
invoice: 'INV-12345',
recipient_name: 'John Doe',
recipient_phone: '01234567890',
recipient_address: '123 Main St, Dhaka-1209',
cod_amount: 1000,
note: 'Handle with care',
});
console.log(`Order created: ${order.consignment.tracking_code}`);
// Check delivery status
const status = await client.status.getStatusByTrackingCode('15BAEB8A');
console.log(`Status: ${status.delivery_status}`);
// Get current balance
const balance = await client.balance.getBalance();
console.log(`Current balance: ${balance.current_balance} BDT`);| Service | Method | Description | Parameters | Returns |
|---|---|---|---|---|
| Orders | createOrder |
Create a single order | CreateOrderRequest |
CreateOrderResponse |
createBulkOrders |
Create multiple orders (max 500) | BulkOrderItem[] |
BulkOrderResponse[] |
|
| Status | getStatusByConsignmentId |
Get status by consignment ID | consignmentId: number |
DeliveryStatusResponse |
getStatusByInvoice |
Get status by invoice number | invoice: string |
DeliveryStatusResponse |
|
getStatusByTrackingCode |
Get status by tracking code | trackingCode: string |
DeliveryStatusResponse |
|
| Balance | getBalance |
Get current account balance | - | BalanceResponse |
| Returns | createReturnRequest |
Create a return request | CreateReturnRequestRequest |
CreateReturnRequestResponse |
getReturnRequest |
Get a single return request | id: number |
GetReturnRequestResponse |
|
getReturnRequests |
Get all return requests | - | GetReturnRequestsResponse[] |
|
| Payments | getPayments |
Get all payments | - | GetPaymentsResponse |
getPayment |
Get payment with consignments | paymentId: number |
GetPaymentResponse |
|
| Police Stations | getPoliceStations |
Get all police stations | - | PoliceStation[] |
| Utility | Description | Framework | Returns |
|---|---|---|---|
createSteadfastExpressWebhookHandler |
Express.js middleware for webhooks | Express | (req, res, next) => Promise<void> |
createSteadfastFastifyWebhookHandler |
Fastify route handler for webhooks | Fastify | (req, reply) => Promise<void> |
createSteadfastGenericWebhookHandler |
Generic handler for any framework | Any | (req, res) => Promise<void> |
SteadfastWebhookHandler |
Core webhook handler class | Any | Class instance |
| Method | Description | Parameters | Returns |
|---|---|---|---|
handle |
Process webhook payload | body: unknown, authHeader?: string |
Promise<WebhookResponse> |
onDeliveryStatus |
Set handler for delivery status webhooks | handler: (payload) => void |
void |
onTrackingUpdate |
Set handler for tracking update webhooks | handler: (payload) => void |
void |
on |
Listen to webhook events (EventEmitter) | event: SteadfastWebhookEvent, listener |
this |
| Error Class | Description | Properties |
|---|---|---|
SteadfastError |
Base error class for all Steadfast errors | message: string, statusCode?: number, code?: string |
SteadfastApiError |
API request/response errors | message: string, statusCode: number, response?: unknown |
SteadfastValidationError |
Input validation errors | message: string, field?: string |
SteadfastAuthenticationError |
Authentication errors | message: string |
SteadfastWebhookError |
Webhook processing errors | message: string |
| Category | Name | Description |
|---|---|---|
| Enums | SteadfastWebhookNotificationType |
Webhook notification types (DELIVERY_STATUS, TRACKING_UPDATE) |
SteadfastWebhookEvent |
Webhook event names (WEBHOOK, DELIVERY_STATUS, TRACKING_UPDATE, ERROR) |
|
SteadfastWebhookDeliveryStatus |
Delivery status values for webhooks (PENDING, DELIVERED, PARTIAL_DELIVERED, CANCELLED, UNKNOWN) |
|
DeliveryStatus |
Delivery status values (PENDING, DELIVERED, CANCELLED, etc.) |
|
ReturnStatus |
Return request status values (PENDING, APPROVED, COMPLETED, etc.) |
|
DeliveryType |
Delivery type values (HOME_DELIVERY, POINT_DELIVERY) |
|
| Request Types | CreateOrderRequest |
Order creation request payload |
CreateReturnRequestRequest |
Return request creation payload | |
| Response Types | CreateOrderResponse |
Order creation response |
DeliveryStatusResponse |
Delivery status response | |
BalanceResponse |
Balance check response | |
WebhookResponse |
Webhook processing response | |
| Webhook Types | DeliveryStatusWebhook |
Delivery status webhook payload |
TrackingUpdateWebhook |
Tracking update webhook payload | |
WebhookPayload |
Union type for all webhook payloads |
| Function | Description | Parameters | Throws |
|---|---|---|---|
validateInvoice |
Validate invoice format (alpha-numeric with hyphens/underscores) | invoice: string |
SteadfastValidationError |
validateRecipientName |
Validate recipient name (max 100 chars) | name: string |
SteadfastValidationError |
validateRecipientAddress |
Validate recipient address (max 250 chars) | address: string |
SteadfastValidationError |
validatePhoneNumber |
Validate phone number (11 digits) | phone: string, fieldName?: string |
SteadfastValidationError |
validateCodAmount |
Validate COD amount (>= 0) | amount: number |
SteadfastValidationError |
validateEmail |
Validate email format (optional) | email: string | undefined |
SteadfastValidationError |
| Function | Description | Parameters | Returns |
|---|---|---|---|
extractBearerToken |
Extract Bearer token from Authorization header | authHeader: string | undefined | null |
string |
verifyBearerToken |
Verify Bearer token using timing-safe comparison | receivedToken: string, expectedToken: string |
boolean |
parseWebhookPayload |
Parse and validate webhook payload | data: unknown |
WebhookPayload |
createSuccessResponse |
Create webhook success response | - | WebhookSuccessResponse |
createErrorResponse |
Create webhook error response | message: string |
WebhookErrorResponse |
isDeliveryStatusWebhook |
Type guard for delivery status webhooks | payload: WebhookPayload |
payload is DeliveryStatusWebhook |
isTrackingUpdateWebhook |
Type guard for tracking update webhooks | payload: WebhookPayload |
payload is TrackingUpdateWebhook |
const order = await client.orders.createOrder({
invoice: 'INV-12345', // Required: Unique invoice ID
recipient_name: 'John Doe', // Required: Max 100 characters
recipient_phone: '01234567890', // Required: 11 digits
recipient_address: '123 Main St, Dhaka-1209', // Required: Max 250 characters
cod_amount: 1000, // Required: Must be >= 0
alternative_phone: '01987654321', // Optional: 11 digits
recipient_email: 'john@example.com', // Optional
note: 'Delivery instructions', // Optional
item_description: 'Electronics', // Optional
total_lot: 1, // Optional
delivery_type: 0, // Optional: 0 = home delivery, 1 = point delivery
});const orders = [
{
invoice: 'INV-001',
recipient_name: 'John Doe',
recipient_phone: '01234567890',
recipient_address: '123 Main St',
cod_amount: 1000,
},
{
invoice: 'INV-002',
recipient_name: 'Jane Smith',
recipient_phone: '01987654321',
recipient_address: '456 Oak Ave',
cod_amount: 2000,
},
];
const results = await client.orders.createBulkOrders(orders);
// Maximum 500 orders per requestconst status = await client.status.getStatusByConsignmentId(1424107);const status = await client.status.getStatusByInvoice('INV-12345');const status = await client.status.getStatusByTrackingCode('15BAEB8A');const balance = await client.balance.getBalance();const returnRequest = await client.returns.createReturnRequest({
consignment_id: 1424107, // Or use invoice or tracking_code
reason: 'Customer requested return',
});const returnRequest = await client.returns.getReturnRequest(1);const returnRequests = await client.returns.getReturnRequests();const payments = await client.payments.getPayments();const payment = await client.payments.getPayment(1);const policeStations = await client.policeStations.getPoliceStations();The SDK provides comprehensive webhook handling utilities to help you build webhook endpoints quickly.
Recommended: Use handler instance directly
import express from 'express';
import { SteadfastWebhookHandler } from 'steadfast-courier/webhooks';
const app = express();
app.use(express.json());
// Create handler instance and set up callbacks
const webhookHandler = new SteadfastWebhookHandler({
apiKey: 'your-api-key',
});
webhookHandler.onDeliveryStatus(async (payload) => {
console.log('Delivery status updated:', payload);
// Handle delivery status update
// e.g., update database, send notification, etc.
});
webhookHandler.onTrackingUpdate(async (payload) => {
console.log('Tracking updated:', payload);
// Handle tracking update
});
// Use the handler directly as Express route handler
// Note: We use app.post() instead of app.use() because:
// - Webhooks are POST requests only (not GET, PUT, DELETE, etc.)
// - app.post() handles only POST requests to this specific path
// - app.use() would handle ALL HTTP methods, which is unnecessary and less secure
app.post('/steadfast-webhook', webhookHandler.express());Why app.post() instead of app.use()?
app.post('/path', handler)- Handles only POST requests to that specific pathapp.use('/path', handler)- Handles ALL HTTP methods (GET, POST, PUT, DELETE, etc.) to that path and sub-paths
For webhooks, you want to:
- ✅ Only accept POST requests (webhooks are POST-only)
- ✅ Handle a specific endpoint (not all routes)
- ✅ Reject other HTTP methods (security best practice)
If you use app.use('/steadfast-webhook', ...), it would also respond to GET, PUT, DELETE requests, which is unnecessary and potentially a security issue.
If you really need app.use() (e.g., for a prefix that handles multiple routes), you can:
// This would handle POST /webhooks/steadfast, POST /webhooks/other, etc.
app.use('/webhooks', (req, res, next) => {
if (req.method === 'POST' && req.path === '/steadfast') {
return webhookHandler.express()(req, res, next);
}
next();
});But for a single webhook endpoint, app.post() is the recommended approach.
Alternative: Using adapter function
import express from 'express';
import { createSteadfastExpressWebhookHandler } from 'steadfast-courier/webhooks';
const app = express();
app.use(express.json());
// Simple usage without callbacks
const webhookHandler = createSteadfastExpressWebhookHandler({
apiKey: 'your-api-key',
});
app.post('/steadfast-webhook', webhookHandler);Recommended: Use handler instance directly
import Fastify from 'fastify';
import { SteadfastWebhookHandler } from 'steadfast-courier/webhooks';
const fastify = Fastify();
// Create handler instance and set up callbacks
const webhookHandler = new SteadfastWebhookHandler({
apiKey: 'your-api-key',
});
webhookHandler.onDeliveryStatus(async (payload) => {
console.log('Delivery status updated:', payload);
});
// Use the handler directly as Fastify route handler
fastify.post('/steadfast-webhook', webhookHandler.fastify());Alternative: Using adapter function
import Fastify from 'fastify';
import { createSteadfastFastifyWebhookHandler } from 'steadfast-courier/webhooks';
const fastify = Fastify();
const webhookHandler = createSteadfastFastifyWebhookHandler({
apiKey: 'your-api-key',
});
fastify.post('/steadfast-webhook', webhookHandler);
```typescript
import Fastify from 'fastify';
import { createSteadfastFastifyWebhookHandler } from 'steadfast-courier/webhooks';
const fastify = Fastify();
const webhookHandler = createSteadfastFastifyWebhookHandler({
apiKey: 'your-api-key',
});
fastify.post('/webhook', webhookHandler);Recommended: Use handler instance directly
import { SteadfastWebhookHandler } from 'steadfast-courier/webhooks';
// Create handler instance and set up callbacks
const webhookHandler = new SteadfastWebhookHandler({
apiKey: 'your-api-key',
});
webhookHandler.onDeliveryStatus(async (payload) => {
console.log('Delivery status updated:', payload);
});
// Use with any framework
app.post('/steadfast-webhook', async (req, res) => {
await webhookHandler.generic()(req, res);
});Alternative: Using adapter function
import { createSteadfastGenericWebhookHandler } from 'steadfast-courier/webhooks';
const handler = createSteadfastGenericWebhookHandler({
apiKey: 'your-api-key',
});
// Use with any framework
app.post('/steadfast-webhook', async (req, res) => {
await handler(req, res);
});
```typescript
import { createSteadfastGenericWebhookHandler } from 'steadfast-courier/webhooks';
const handler = createSteadfastGenericWebhookHandler({
apiKey: 'your-api-key',
});
// Use with any framework
app.post('/webhook', async (req, res) => {
await handler(req, res);
});import { SteadfastWebhookHandler, SteadfastWebhookEvent } from 'steadfast-courier/webhooks';
const handler = new SteadfastWebhookHandler({
apiKey: 'your-api-key',
});
// Set up event listeners using SteadfastWebhookEvent enum
handler.on(SteadfastWebhookEvent.WEBHOOK, (payload) => {
console.log('Received webhook:', payload);
});
handler.on(SteadfastWebhookEvent.DELIVERY_STATUS, (payload) => {
console.log('Delivery status:', payload);
});
handler.on(SteadfastWebhookEvent.TRACKING_UPDATE, (payload) => {
console.log('Tracking update:', payload);
});
handler.on(SteadfastWebhookEvent.ERROR, (error) => {
console.error('Webhook error:', error);
});
// Process webhook
const result = await handler.handle(request.body, request.headers.authorization);
if (result.status === 'success') {
// Webhook processed successfully
} else {
// Handle error
console.error(result.message);
}The SteadfastWebhookHandler emits events that you can listen to using the SteadfastWebhookEvent enum:
SteadfastWebhookEvent.WEBHOOK- Emitted for any Steadfast webhook payload after successful parsing and authenticationSteadfastWebhookEvent.DELIVERY_STATUS- Emitted when a delivery status update webhook is received from SteadfastSteadfastWebhookEvent.TRACKING_UPDATE- Emitted when a tracking update webhook is received from SteadfastSteadfastWebhookEvent.ERROR- Emitted when an error occurs during Steadfast webhook processing
import { SteadfastWebhookHandler, SteadfastWebhookEvent } from 'steadfast-courier/webhooks';
const handler = new SteadfastWebhookHandler({ apiKey: 'your-api-key' });
// Listen to all webhooks
handler.on(SteadfastWebhookEvent.WEBHOOK, (payload) => {
console.log('Any Steadfast webhook received:', payload);
});
// Listen to specific webhook types
handler.on(SteadfastWebhookEvent.DELIVERY_STATUS, (payload) => {
// payload is typed as DeliveryStatusWebhook
console.log('Status:', payload.status);
console.log('COD Amount:', payload.cod_amount);
});
handler.on(SteadfastWebhookEvent.TRACKING_UPDATE, (payload) => {
// payload is typed as TrackingUpdateWebhook
console.log('Tracking message:', payload.tracking_message);
});
// Handle errors
handler.on(SteadfastWebhookEvent.ERROR, (error) => {
console.error('Steadfast webhook processing error:', error);
});The SDK provides TypeScript types for webhook payloads:
import type {
DeliveryStatusWebhook,
TrackingUpdateWebhook,
WebhookPayload,
} from 'steadfast-courier';
import { SteadfastWebhookDeliveryStatus } from 'steadfast-courier';
// Type-safe webhook handling
handler.onDeliveryStatus((payload: DeliveryStatusWebhook) => {
// payload is fully typed
console.log(payload.consignment_id);
console.log(payload.cod_amount);
// payload.status is typed as SteadfastWebhookDeliveryStatus enum
console.log(payload.status); // Type: SteadfastWebhookDeliveryStatus
// Use enum for type-safe comparisons
if (payload.status === SteadfastWebhookDeliveryStatus.DELIVERED) {
console.log('Order delivered!');
} else if (payload.status === SteadfastWebhookDeliveryStatus.CANCELLED) {
console.log('Order cancelled');
}
// Available enum values:
// - SteadfastWebhookDeliveryStatus.PENDING
// - SteadfastWebhookDeliveryStatus.DELIVERED
// - SteadfastWebhookDeliveryStatus.PARTIAL_DELIVERED
// - SteadfastWebhookDeliveryStatus.CANCELLED
// - SteadfastWebhookDeliveryStatus.UNKNOWN
});The SDK provides custom error classes for better error handling:
import {
SteadfastError,
SteadfastApiError,
SteadfastValidationError,
SteadfastAuthenticationError,
} from 'steadfast-courier';
try {
await client.orders.createOrder(orderData);
} catch (error) {
if (error instanceof SteadfastValidationError) {
console.error('Validation error:', error.message);
console.error('Field:', error.field);
} else if (error instanceof SteadfastApiError) {
console.error('API error:', error.message);
console.error('Status code:', error.statusCode);
} else if (error instanceof SteadfastError) {
console.error('Steadfast error:', error.message);
}
}The SDK is written in TypeScript and provides full type definitions.
If you encounter module resolution errors when importing from 'steadfast-courier/webhooks', ensure your tsconfig.json uses one of these moduleResolution settings:
"node16"(recommended for Node.js projects)"nodenext"(recommended for modern Node.js projects)"bundler"(recommended for bundler-based projects)
Example tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "node16"
// ... other options
}
}The SDK provides full type definitions:
import type {
CreateOrderRequest,
CreateOrderResponse,
DeliveryStatusResponse,
WebhookPayload,
} from 'steadfast-courier';
// All types are exported and available
const orderRequest: CreateOrderRequest = {
// TypeScript will autocomplete and validate
};# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Lint
npm run lint
# Format code
npm run format
# Generate documentation
npm run docsMIT
For API documentation and support, please visit the Steadfast Courier Portal.