Skip to content

shahria7k/steadfast-courier

Repository files navigation

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: '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
});

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 request

Status

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 path
  • app.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 authentication
  • SteadfastWebhookEvent.DELIVERY_STATUS - Emitted when a delivery status update webhook is received from Steadfast
  • SteadfastWebhookEvent.TRACKING_UPDATE - Emitted when a tracking update webhook is received from Steadfast
  • SteadfastWebhookEvent.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 docs

License

MIT

Support

For API documentation and support, please visit the Steadfast Courier Portal.

About

A modern, type-safe TypeScript SDK for the Steadfast Courier Limited API with comprehensive webhook support.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors