steadfast-courier
v1.0.9
Published
TypeScript SDK for Steadfast Courier Limited API with webhook support
Maintainers
Readme
Steadfast Courier SDK
A modern, type-safe TypeScript SDK for the Steadfast Courier Limited API with comprehensive webhook support.
Features
- ✅ 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
Installation
# npm
npm install steadfast-courier
# yarn
yarn add steadfast-courier
# pnpm
pnpm add steadfast-courier⚠️ TypeScript Configuration Required
If 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.
Quick Start
Basic Usage
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`);API Reference
Complete API Methods Table
| 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[] |
Webhook Utilities Table
| 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 |
Webhook Handler Methods
| 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 Classes Table
| 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 |
Type Definitions & Enums
| 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 |
Validation Utilities
| 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 |
Webhook Utility Functions
| 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 |
API Reference
Orders
Create Single Order
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: '[email protected]', // Optional
note: 'Delivery instructions', // Optional
item_description: 'Electronics', // Optional
total_lot: 1, // Optional
delivery_type: 0, // Optional: 0 = home delivery, 1 = point delivery
});Create Bulk Orders
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 requestStatus
Get Status by Consignment ID
const status = await client.status.getStatusByConsignmentId(1424107);Get Status by Invoice
const status = await client.status.getStatusByInvoice('INV-12345');Get Status by Tracking Code
const status = await client.status.getStatusByTrackingCode('15BAEB8A');Balance
const balance = await client.balance.getBalance();Returns
Create Return Request
const returnRequest = await client.returns.createReturnRequest({
consignment_id: 1424107, // Or use invoice or tracking_code
reason: 'Customer requested return',
});Get Return Request
const returnRequest = await client.returns.getReturnRequest(1);Get All Return Requests
const returnRequests = await client.returns.getReturnRequests();Payments
Get All Payments
const payments = await client.payments.getPayments();Get Single Payment with Consignments
const payment = await client.payments.getPayment(1);Police Stations
const policeStations = await client.policeStations.getPoliceStations();Webhook Integration
The SDK provides comprehensive webhook handling utilities to help you build webhook endpoints quickly.
Express.js Example
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);Fastify Example
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);Generic Framework Example
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);
});Manual Webhook Handling
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);
}Webhook Events
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);
});Webhook Payload Types
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
});Error Handling
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);
}
}TypeScript Support
The SDK is written in TypeScript and provides full type definitions.
Module Resolution
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
}
}Type Definitions
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
};Development
# 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 docsLicense
MIT
Support
For API documentation and support, please visit the Steadfast Courier Portal.
