pathao-merchant-sdk 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +144 -68
- package/README.md +397 -471
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/webhooks.d.mts +27 -2
- package/dist/webhooks.d.ts +27 -2
- package/dist/webhooks.js +11 -6
- package/dist/webhooks.js.map +1 -1
- package/dist/webhooks.mjs +11 -6
- package/dist/webhooks.mjs.map +1 -1
- package/package.json +3 -8
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Pathao Merchant
|
|
1
|
+
# Pathao Merchant SDK
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/pathao-merchant-sdk)
|
|
4
4
|
[](https://www.npmjs.com/package/pathao-merchant-sdk)
|
|
@@ -6,48 +6,36 @@
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://github.com/sifat07/pathao-merchant-sdk/actions)
|
|
8
8
|
|
|
9
|
-
An **unofficial** TypeScript SDK for
|
|
9
|
+
An **unofficial** TypeScript SDK for the [Pathao Courier Merchant API](https://merchant.pathao.com/developer). Provides a type-safe interface for order management, store management, price calculation, location lookup, and webhook handling.
|
|
10
10
|
|
|
11
|
-
> **Disclaimer
|
|
11
|
+
> **Disclaimer:** This is a community-maintained package, not an official Pathao product. It is not affiliated with or endorsed by Pathao.
|
|
12
12
|
|
|
13
13
|
## Table of Contents
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
- [Requirements](#requirements)
|
|
16
16
|
- [Installation](#installation)
|
|
17
17
|
- [Quick Start](#quick-start)
|
|
18
18
|
- [Configuration](#configuration)
|
|
19
|
-
- [Environment Variables](#environment-variables)
|
|
20
|
-
- [What You Can Do](#what-you-can-do)
|
|
21
19
|
- [API Reference](#api-reference)
|
|
22
|
-
- [
|
|
20
|
+
- [Order Management](#order-management)
|
|
21
|
+
- [Bulk Orders](#bulk-orders)
|
|
22
|
+
- [Store Management](#store-management)
|
|
23
|
+
- [Price Calculation](#price-calculation)
|
|
24
|
+
- [Location Services](#location-services)
|
|
25
|
+
- [Validation Helpers](#validation-helpers)
|
|
23
26
|
- [Error Handling](#error-handling)
|
|
24
27
|
- [Webhooks](#webhooks)
|
|
25
|
-
- [
|
|
26
|
-
- [Official Documentation](#official-documentation)
|
|
28
|
+
- [TypeScript Types](#typescript-types)
|
|
27
29
|
- [Contributing](#contributing)
|
|
28
|
-
- [Development](#development)
|
|
29
30
|
- [License](#license)
|
|
30
|
-
- [Support](#support)
|
|
31
31
|
- [Changelog](#changelog)
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- 🚀 **Full TypeScript Support** - Complete type definitions for all API responses
|
|
36
|
-
- 🔐 **Automatic Authentication** - Handles OAuth2 token management and refresh
|
|
37
|
-
- 📦 **Order Management** - Create, track, and manage delivery orders
|
|
38
|
-
- 🏪 **Store Management** - Create and manage pickup/service points
|
|
39
|
-
- 💰 **Price Calculation** - Get accurate delivery charges before creating orders
|
|
40
|
-
- 🌍 **Location Services** - Access cities, zones, and areas data
|
|
41
|
-
- 🔔 **Webhook Support** - Verify and handle inbound Pathao webhook events
|
|
42
|
-
- ♻️ **Retry & Circuit Breaker** - Automatic retry with backoff, circuit breaker for resilience
|
|
43
|
-
- ⚡ **Built with Axios** - Reliable HTTP client with request/response interceptors
|
|
44
|
-
- 🛡️ **Error Handling** - Comprehensive error handling with detailed error messages
|
|
45
|
-
- 📚 **Well Documented** - Extensive documentation and examples
|
|
33
|
+
---
|
|
46
34
|
|
|
47
35
|
## Requirements
|
|
48
36
|
|
|
49
|
-
- Node.js >= 18
|
|
50
|
-
- TypeScript >= 4.9 (peer dependency
|
|
37
|
+
- Node.js >= 18
|
|
38
|
+
- TypeScript >= 4.9 (peer dependency)
|
|
51
39
|
|
|
52
40
|
## Installation
|
|
53
41
|
|
|
@@ -61,55 +49,70 @@ pnpm add pathao-merchant-sdk
|
|
|
61
49
|
|
|
62
50
|
## Quick Start
|
|
63
51
|
|
|
52
|
+
Use the sandbox credentials below to get started immediately. For production, get your credentials from the [Pathao Merchant Dashboard](https://merchant.pathao.com/developer) under **API Credentials**.
|
|
53
|
+
|
|
54
|
+
**Sandbox credentials (publicly provided by Pathao for testing):**
|
|
55
|
+
|
|
56
|
+
| Field | Value |
|
|
57
|
+
| -------------- | ------------------------------------------ |
|
|
58
|
+
| `baseURL` | `https://courier-api-sandbox.pathao.com` |
|
|
59
|
+
| `clientId` | `7N1aMJQbWm` |
|
|
60
|
+
| `clientSecret` | `wRcaibZkUdSNz2EI9ZyuXLlNrnAv0TdPUPXMnD39` |
|
|
61
|
+
| `username` | `test@pathao.com` |
|
|
62
|
+
| `password` | `lovePathao` |
|
|
63
|
+
|
|
64
64
|
```typescript
|
|
65
|
-
import { PathaoApiService, DeliveryType, ItemType } from
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
password: 'your-password'
|
|
65
|
+
import { PathaoApiService, DeliveryType, ItemType } from "pathao-merchant-sdk";
|
|
66
|
+
|
|
67
|
+
const pathao = PathaoApiService.fromConfig({
|
|
68
|
+
baseURL: "https://courier-api-sandbox.pathao.com",
|
|
69
|
+
clientId: "7N1aMJQbWm",
|
|
70
|
+
clientSecret: "wRcaibZkUdSNz2EI9ZyuXLlNrnAv0TdPUPXMnD39",
|
|
71
|
+
username: "test@pathao.com",
|
|
72
|
+
password: "lovePathao",
|
|
74
73
|
});
|
|
75
74
|
|
|
76
|
-
// Create a delivery order
|
|
77
75
|
const order = await pathao.createOrder({
|
|
78
|
-
store_id:
|
|
79
|
-
recipient_name:
|
|
80
|
-
recipient_phone:
|
|
81
|
-
recipient_address:
|
|
76
|
+
store_id: 12345,
|
|
77
|
+
recipient_name: "John Doe",
|
|
78
|
+
recipient_phone: "01712345678",
|
|
79
|
+
recipient_address: "House 10, Road 5, Dhanmondi, Dhaka",
|
|
82
80
|
delivery_type: DeliveryType.NORMAL,
|
|
83
81
|
item_type: ItemType.PARCEL,
|
|
84
82
|
item_quantity: 1,
|
|
85
|
-
item_weight:
|
|
86
|
-
amount_to_collect: 500
|
|
83
|
+
item_weight: 0.5,
|
|
84
|
+
amount_to_collect: 500,
|
|
87
85
|
});
|
|
88
86
|
|
|
89
|
-
console.log(
|
|
87
|
+
console.log("Consignment ID:", order.data.consignment_id);
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Configuration
|
|
93
|
+
|
|
94
|
+
### Environments
|
|
95
|
+
|
|
96
|
+
| | Sandbox | Production |
|
|
97
|
+
| ----------- | ---------------------------------------- | ------------------------------- |
|
|
98
|
+
| `baseURL` | `https://courier-api-sandbox.pathao.com` | `https://api-hermes.pathao.com` |
|
|
99
|
+
| Credentials | From merchant dashboard (sandbox tab) | From merchant dashboard |
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
Obtain your `client_id`, `client_secret`, username, and password from the **API Credentials** section of the [Pathao Merchant Dashboard](https://merchant.pathao.com/developer).
|
|
102
|
+
|
|
103
|
+
### Environment Variables
|
|
104
|
+
|
|
105
|
+
Copy `env.example` to `.env`:
|
|
95
106
|
|
|
96
107
|
```bash
|
|
97
108
|
cp env.example .env
|
|
98
|
-
npm install dotenv --save-dev # or yarn add -D dotenv / pnpm add -D dotenv
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
import 'dotenv/config';
|
|
103
109
|
```
|
|
104
110
|
|
|
105
|
-
Required and optional variables:
|
|
106
|
-
|
|
107
111
|
```env
|
|
108
|
-
#
|
|
109
|
-
PATHAO_BASE_URL=https://courier-api-sandbox.pathao.com
|
|
110
|
-
# PATHAO_BASE_URL=https://api-hermes.pathao.com
|
|
112
|
+
# Choose one:
|
|
113
|
+
PATHAO_BASE_URL=https://courier-api-sandbox.pathao.com
|
|
114
|
+
# PATHAO_BASE_URL=https://api-hermes.pathao.com
|
|
111
115
|
|
|
112
|
-
# Authentication (required)
|
|
113
116
|
PATHAO_CLIENT_ID=your-client-id
|
|
114
117
|
PATHAO_CLIENT_SECRET=your-client-secret
|
|
115
118
|
PATHAO_USERNAME=your-username
|
|
@@ -119,103 +122,65 @@ PATHAO_PASSWORD=your-password
|
|
|
119
122
|
PATHAO_TIMEOUT=30000
|
|
120
123
|
```
|
|
121
124
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- Create, price, and track delivery orders
|
|
125
|
-
- Manage stores (pickup/service points)
|
|
126
|
-
- Look up cities, zones, and areas
|
|
127
|
-
- Validate phone, address, weight, and recipient inputs
|
|
128
|
-
- Automatically handle OAuth2 authentication and token refresh
|
|
129
|
-
|
|
130
|
-
## API Reference
|
|
131
|
-
|
|
132
|
-
### Configuration
|
|
125
|
+
If you use `dotenv`, load it before initializing the SDK:
|
|
133
126
|
|
|
134
127
|
```typescript
|
|
135
|
-
|
|
136
|
-
clientId: string; // Your Pathao API client ID
|
|
137
|
-
clientSecret: string; // Your Pathao API client secret
|
|
138
|
-
username: string; // Your Pathao API username
|
|
139
|
-
password: string; // Your Pathao API password
|
|
140
|
-
baseURL: string; // API base URL (required)
|
|
141
|
-
timeout?: number; // Request timeout in ms (default: 30000)
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
#### Environment Variables
|
|
146
|
-
|
|
147
|
-
The SDK automatically reads the variables listed in the [Environment Variables](#environment-variables) section when present, and falls back to the values you pass in the config.
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// Option 1: All from environment variables
|
|
151
|
-
const pathao = new PathaoApiService({});
|
|
152
|
-
|
|
153
|
-
// Option 2: Mix of config and environment variables
|
|
154
|
-
const pathao = new PathaoApiService({
|
|
155
|
-
baseURL: 'https://api-hermes.pathao.com', // This overrides PATHAO_BASE_URL
|
|
156
|
-
clientId: 'your-client-id', // This overrides PATHAO_CLIENT_ID
|
|
157
|
-
// Other credentials will be taken from environment variables
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Option 3: All from config (environment variables as fallback)
|
|
161
|
-
const pathao = new PathaoApiService({
|
|
162
|
-
baseURL: process.env.PATHAO_BASE_URL || 'https://api-hermes.pathao.com',
|
|
163
|
-
clientId: process.env.PATHAO_CLIENT_ID || 'your-client-id',
|
|
164
|
-
clientSecret: process.env.PATHAO_CLIENT_SECRET || 'your-client-secret',
|
|
165
|
-
username: process.env.PATHAO_USERNAME || 'your-username',
|
|
166
|
-
password: process.env.PATHAO_PASSWORD || 'your-password',
|
|
167
|
-
});
|
|
128
|
+
import "dotenv/config";
|
|
168
129
|
```
|
|
169
130
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
The SDK provides convenient factory methods for common initialization patterns:
|
|
131
|
+
### Factory Methods
|
|
173
132
|
|
|
174
133
|
```typescript
|
|
175
|
-
//
|
|
134
|
+
// From environment variables
|
|
176
135
|
const pathao = PathaoApiService.fromEnv();
|
|
177
136
|
|
|
178
|
-
//
|
|
137
|
+
// From environment with options
|
|
179
138
|
const pathao = PathaoApiService.fromEnv({
|
|
180
|
-
debug: true,
|
|
181
|
-
circuitBreaker: {
|
|
182
|
-
threshold: 10, // Number of failures before opening circuit (default: 5)
|
|
183
|
-
timeout: 120000 // Timeout before attempting to close circuit (default: 60000ms)
|
|
184
|
-
}
|
|
139
|
+
debug: true,
|
|
140
|
+
circuitBreaker: { threshold: 10, timeout: 120_000 },
|
|
185
141
|
});
|
|
186
142
|
|
|
187
|
-
//
|
|
143
|
+
// From explicit config
|
|
188
144
|
const pathao = PathaoApiService.fromConfig({
|
|
189
|
-
baseURL:
|
|
190
|
-
clientId:
|
|
191
|
-
clientSecret:
|
|
192
|
-
username:
|
|
193
|
-
password:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
145
|
+
baseURL: "https://api-hermes.pathao.com",
|
|
146
|
+
clientId: "your-client-id",
|
|
147
|
+
clientSecret: "your-client-secret",
|
|
148
|
+
username: "your-username",
|
|
149
|
+
password: "your-password",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Named constructors (pre-fill the base URL)
|
|
153
|
+
const pathao = PathaoApiService.sandbox({
|
|
154
|
+
clientId,
|
|
155
|
+
clientSecret,
|
|
156
|
+
username,
|
|
157
|
+
password,
|
|
158
|
+
});
|
|
159
|
+
const pathao = PathaoApiService.production({
|
|
160
|
+
clientId,
|
|
161
|
+
clientSecret,
|
|
162
|
+
username,
|
|
163
|
+
password,
|
|
198
164
|
});
|
|
199
165
|
```
|
|
200
166
|
|
|
201
|
-
|
|
167
|
+
### Options
|
|
202
168
|
|
|
203
169
|
```typescript
|
|
204
170
|
const pathao = new PathaoApiService(config, {
|
|
205
|
-
debug: false,
|
|
171
|
+
debug: false, // Log all HTTP requests/responses (default: false)
|
|
206
172
|
circuitBreaker: {
|
|
207
|
-
threshold: 5,
|
|
208
|
-
timeout:
|
|
209
|
-
}
|
|
173
|
+
threshold: 5, // Failures before opening circuit (default: 5)
|
|
174
|
+
timeout: 60_000, // Ms before attempting to close circuit (default: 60000)
|
|
175
|
+
},
|
|
210
176
|
});
|
|
211
177
|
```
|
|
212
178
|
|
|
213
|
-
|
|
179
|
+
Configuration validation is **deferred** to the first API call — constructing the SDK never throws.
|
|
214
180
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
```
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## API Reference
|
|
219
184
|
|
|
220
185
|
### Order Management
|
|
221
186
|
|
|
@@ -223,30 +188,74 @@ When `debug` is enabled, the SDK logs all HTTP requests and responses:
|
|
|
223
188
|
|
|
224
189
|
```typescript
|
|
225
190
|
const order = await pathao.createOrder({
|
|
226
|
-
store_id:
|
|
227
|
-
merchant_order_id:
|
|
228
|
-
recipient_name:
|
|
229
|
-
recipient_phone:
|
|
230
|
-
recipient_secondary_phone:
|
|
231
|
-
recipient_address:
|
|
232
|
-
recipient_city: 1, // Optional
|
|
233
|
-
recipient_zone: 1, // Optional
|
|
234
|
-
recipient_area: 1, // Optional
|
|
235
|
-
delivery_type: DeliveryType.NORMAL, //
|
|
236
|
-
item_type: ItemType.PARCEL, // 1
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
amount_to_collect: 500 // COD amount
|
|
191
|
+
store_id: 12345, // Required — your store ID
|
|
192
|
+
merchant_order_id: "ORDER-001", // Optional — your internal tracking ID
|
|
193
|
+
recipient_name: "John Doe", // Required — 3–100 characters
|
|
194
|
+
recipient_phone: "01712345678", // Required — 11 digits, starts with 01
|
|
195
|
+
recipient_secondary_phone: "01812345678", // Optional
|
|
196
|
+
recipient_address: "House 10, Road 5, Dhanmondi, Dhaka", // Required — 10–220 chars
|
|
197
|
+
recipient_city: 1, // Optional — auto-detected if omitted
|
|
198
|
+
recipient_zone: 1, // Optional — auto-detected if omitted
|
|
199
|
+
recipient_area: 1, // Optional — auto-detected if omitted
|
|
200
|
+
delivery_type: DeliveryType.NORMAL, // Required — NORMAL (48) or ON_DEMAND (12)
|
|
201
|
+
item_type: ItemType.PARCEL, // Required — DOCUMENT (1) or PARCEL (2)
|
|
202
|
+
item_quantity: 1, // Required
|
|
203
|
+
item_weight: 0.5, // Required — 0.5–10 kg
|
|
204
|
+
item_description: "Cotton shirt", // Optional
|
|
205
|
+
special_instruction: "Call before delivery", // Optional
|
|
206
|
+
amount_to_collect: 500, // Required — COD amount; 0 for prepaid
|
|
242
207
|
});
|
|
208
|
+
|
|
209
|
+
// Response
|
|
210
|
+
console.log(order.data.consignment_id); // Pathao tracking ID
|
|
211
|
+
console.log(order.data.merchant_order_id);
|
|
212
|
+
console.log(order.data.order_status); // "Pending"
|
|
213
|
+
console.log(order.data.delivery_fee); // number
|
|
243
214
|
```
|
|
244
215
|
|
|
245
216
|
#### Get Order Status
|
|
246
217
|
|
|
247
218
|
```typescript
|
|
248
|
-
const
|
|
249
|
-
|
|
219
|
+
const info = await pathao.getOrderStatus("DL121224VS8TTJ");
|
|
220
|
+
|
|
221
|
+
console.log(info.data.consignment_id);
|
|
222
|
+
console.log(info.data.order_status);
|
|
223
|
+
console.log(info.data.order_status_slug);
|
|
224
|
+
console.log(info.data.updated_at); // "YYYY-MM-DD HH:MM:SS"
|
|
225
|
+
console.log(info.data.invoice_id); // string | null
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Bulk Orders
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const result = await pathao.createBulkOrder([
|
|
232
|
+
{
|
|
233
|
+
store_id: 12345,
|
|
234
|
+
recipient_name: "Alice",
|
|
235
|
+
recipient_phone: "01712345678",
|
|
236
|
+
recipient_address: "House 10, Road 5, Dhanmondi, Dhaka",
|
|
237
|
+
delivery_type: DeliveryType.NORMAL,
|
|
238
|
+
item_type: ItemType.PARCEL,
|
|
239
|
+
item_quantity: 1,
|
|
240
|
+
item_weight: 0.5,
|
|
241
|
+
amount_to_collect: 300,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
store_id: 12345,
|
|
245
|
+
recipient_name: "Bob",
|
|
246
|
+
recipient_phone: "01812345678",
|
|
247
|
+
recipient_address: "House 3, Road 14, Gulshan, Dhaka",
|
|
248
|
+
delivery_type: DeliveryType.NORMAL,
|
|
249
|
+
item_type: ItemType.PARCEL,
|
|
250
|
+
item_quantity: 2,
|
|
251
|
+
item_weight: 1.0,
|
|
252
|
+
amount_to_collect: 800,
|
|
253
|
+
},
|
|
254
|
+
]);
|
|
255
|
+
|
|
256
|
+
// Bulk order creation is asynchronous — response is HTTP 202
|
|
257
|
+
console.log(result.code); // 202
|
|
258
|
+
console.log(result.data); // true
|
|
250
259
|
```
|
|
251
260
|
|
|
252
261
|
### Store Management
|
|
@@ -255,453 +264,370 @@ console.log('Order status:', status.data.order_status);
|
|
|
255
264
|
|
|
256
265
|
```typescript
|
|
257
266
|
const store = await pathao.createStore({
|
|
258
|
-
name:
|
|
259
|
-
contact_name:
|
|
260
|
-
contact_number:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
name: "My Dhaka Store", // Required — 3–50 characters
|
|
268
|
+
contact_name: "Store Manager", // Required — 3–50 characters
|
|
269
|
+
contact_number: "01712345678", // Required — 11 digits, starts with 01
|
|
270
|
+
secondary_contact: "01812345678", // Optional
|
|
271
|
+
otp_number: "01712345678", // Optional — OTP delivery number
|
|
272
|
+
address: "House 10, Road 5, Dhanmondi, Dhaka", // Required — 15–120 chars
|
|
273
|
+
city_id: 1, // Required
|
|
274
|
+
zone_id: 1, // Required
|
|
275
|
+
area_id: 37, // Required
|
|
265
276
|
});
|
|
277
|
+
|
|
278
|
+
// Store requires Pathao approval (~1 hour) before it can be used
|
|
279
|
+
console.log(store.data.store_name);
|
|
266
280
|
```
|
|
267
281
|
|
|
268
282
|
#### Get Stores
|
|
269
283
|
|
|
270
284
|
```typescript
|
|
271
|
-
const stores = await pathao.getStores();
|
|
272
|
-
|
|
285
|
+
const stores = await pathao.getStores(); // first page
|
|
286
|
+
const stores = await pathao.getStores(2); // specific page
|
|
287
|
+
|
|
288
|
+
// Paginated response
|
|
289
|
+
stores.data.data.forEach((s) => {
|
|
290
|
+
console.log(s.store_id, s.store_name, s.is_active);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// Auto-fetch all pages
|
|
294
|
+
const allStores = await pathao.getStoresAll();
|
|
273
295
|
```
|
|
274
296
|
|
|
275
297
|
### Price Calculation
|
|
276
298
|
|
|
277
299
|
```typescript
|
|
278
300
|
const price = await pathao.calculatePrice({
|
|
279
|
-
store_id:
|
|
301
|
+
store_id: 12345,
|
|
280
302
|
item_type: ItemType.PARCEL,
|
|
281
|
-
item_weight: 1.0,
|
|
282
303
|
delivery_type: DeliveryType.NORMAL,
|
|
304
|
+
item_weight: 0.5,
|
|
283
305
|
recipient_city: 1,
|
|
284
|
-
recipient_zone: 1
|
|
306
|
+
recipient_zone: 1,
|
|
285
307
|
});
|
|
286
308
|
|
|
287
|
-
console.log(
|
|
288
|
-
console.log(
|
|
289
|
-
console.log(
|
|
309
|
+
console.log(price.data.price); // base price
|
|
310
|
+
console.log(price.data.discount);
|
|
311
|
+
console.log(price.data.final_price); // price to display to customer
|
|
312
|
+
console.log(price.data.cod_enabled); // 0 | 1
|
|
313
|
+
console.log(price.data.cod_percentage); // e.g. 0.01
|
|
290
314
|
```
|
|
291
315
|
|
|
292
316
|
### Location Services
|
|
293
317
|
|
|
294
|
-
#### Get Cities
|
|
295
|
-
|
|
296
318
|
```typescript
|
|
319
|
+
// Cities
|
|
297
320
|
const cities = await pathao.getCities();
|
|
298
|
-
|
|
299
|
-
```
|
|
321
|
+
// [{ city_id: 1, city_name: "Dhaka" }, ...]
|
|
300
322
|
|
|
301
|
-
|
|
323
|
+
// Zones within a city
|
|
324
|
+
const zones = await pathao.getZones(1);
|
|
325
|
+
// [{ zone_id: 298, zone_name: "60 feet" }, ...]
|
|
302
326
|
|
|
303
|
-
|
|
304
|
-
const areas = await pathao.getAreas();
|
|
305
|
-
|
|
327
|
+
// Areas within a zone
|
|
328
|
+
const areas = await pathao.getAreas(298);
|
|
329
|
+
// [{ area_id: 37, area_name: "Bonolota", home_delivery_available: true, pickup_available: true }, ...]
|
|
306
330
|
```
|
|
307
331
|
|
|
308
332
|
### Validation Helpers
|
|
309
333
|
|
|
310
|
-
|
|
334
|
+
All helpers are static and can be used before constructing the SDK:
|
|
311
335
|
|
|
312
336
|
```typescript
|
|
313
|
-
import { PathaoApiService } from
|
|
314
|
-
|
|
315
|
-
// Validate phone number
|
|
316
|
-
const isValidPhone = PathaoApiService.validatePhoneNumber('01712345678'); // true
|
|
317
|
-
|
|
318
|
-
// Format phone number
|
|
319
|
-
const formattedPhone = PathaoApiService.formatPhoneNumber('01712345678'); // '01712345678'
|
|
320
|
-
|
|
321
|
-
// Validate address
|
|
322
|
-
const isValidAddress = PathaoApiService.validateAddress('123 Main Street'); // true
|
|
337
|
+
import { PathaoApiService } from "pathao-merchant-sdk";
|
|
323
338
|
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
## Enums
|
|
332
|
-
|
|
333
|
-
### DeliveryType
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
enum DeliveryType {
|
|
337
|
-
NORMAL = 48, // Normal delivery
|
|
338
|
-
ON_DEMAND = 12 // On-demand delivery
|
|
339
|
-
}
|
|
339
|
+
PathaoApiService.validatePhoneNumber("01712345678"); // true — 11 digits, starts with 01
|
|
340
|
+
PathaoApiService.validateContactNumber("01712345678"); // true — same rules
|
|
341
|
+
PathaoApiService.validateAddress("House 10, Road 5, Dhanmondi, Dhaka"); // true — 10–220 chars
|
|
342
|
+
PathaoApiService.validateStoreAddress("House 10, Road 5, Dhanmondi"); // true — 15–120 chars
|
|
343
|
+
PathaoApiService.validateWeight(0.5); // true — 0.5–10 kg
|
|
344
|
+
PathaoApiService.validateRecipientName("John Doe"); // true — 3–100 chars
|
|
345
|
+
PathaoApiService.validateStoreName("My Store"); // true — 3–50 chars
|
|
340
346
|
```
|
|
341
347
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
enum ItemType {
|
|
346
|
-
DOCUMENT = 1, // Document
|
|
347
|
-
PARCEL = 2 // Parcel
|
|
348
|
-
}
|
|
349
|
-
```
|
|
348
|
+
---
|
|
350
349
|
|
|
351
350
|
## Error Handling
|
|
352
351
|
|
|
353
|
-
|
|
352
|
+
All API errors are thrown as `PathaoApiError`:
|
|
354
353
|
|
|
355
354
|
```typescript
|
|
356
|
-
import { PathaoApiService, PathaoApiError } from
|
|
357
|
-
|
|
358
|
-
const pathao = new PathaoApiService({
|
|
359
|
-
clientId: process.env.PATHAO_CLIENT_ID,
|
|
360
|
-
clientSecret: process.env.PATHAO_CLIENT_SECRET,
|
|
361
|
-
username: process.env.PATHAO_USERNAME,
|
|
362
|
-
password: process.env.PATHAO_PASSWORD
|
|
363
|
-
});
|
|
355
|
+
import { PathaoApiService, PathaoApiError } from "pathao-merchant-sdk";
|
|
364
356
|
|
|
365
357
|
try {
|
|
366
358
|
const order = await pathao.createOrder(orderData);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
console.error(
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
message: error.message, // Error message
|
|
376
|
-
errors: error.errors, // Field-level errors
|
|
377
|
-
validation: error.validation // Validation errors
|
|
378
|
-
});
|
|
379
|
-
} else {
|
|
380
|
-
console.error('Unexpected error:', error.message);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
if (err instanceof PathaoApiError) {
|
|
361
|
+
console.error("HTTP status:", err.status); // e.g. 422
|
|
362
|
+
console.error("Pathao code:", err.code); // Pathao internal error code
|
|
363
|
+
console.error("Type:", err.type); // e.g. "ValidationException"
|
|
364
|
+
console.error("Message:", err.message);
|
|
365
|
+
console.error("Field errors:", err.errors); // { field: "message" }
|
|
366
|
+
console.error("Validation:", err.validation);
|
|
381
367
|
}
|
|
382
368
|
}
|
|
383
369
|
```
|
|
384
370
|
|
|
385
|
-
###
|
|
371
|
+
### Common error scenarios
|
|
386
372
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
373
|
+
| Status | Cause |
|
|
374
|
+
| ------ | ------------------------------------------------------------ |
|
|
375
|
+
| 400 | Bad request / missing required fields |
|
|
376
|
+
| 401 | Invalid or expired credentials |
|
|
377
|
+
| 422 | Validation failure — check `err.errors` for field details |
|
|
378
|
+
| 429 | Rate limited — SDK retries automatically after `Retry-After` |
|
|
379
|
+
| 503 | Circuit breaker open — too many consecutive failures |
|
|
393
380
|
|
|
394
|
-
|
|
381
|
+
---
|
|
395
382
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
```typescript
|
|
399
|
-
// This won't throw immediately
|
|
400
|
-
const pathao = new PathaoApiService({});
|
|
383
|
+
## Webhooks
|
|
401
384
|
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
await pathao.getStores();
|
|
405
|
-
} catch (error) {
|
|
406
|
-
if (error instanceof PathaoApiError) {
|
|
407
|
-
console.error('Configuration error:', error.validation);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
```
|
|
385
|
+
The webhooks module is a **separate entry point** with zero runtime dependencies (Node.js built-ins only).
|
|
411
386
|
|
|
412
|
-
|
|
387
|
+
### How Pathao webhooks work
|
|
413
388
|
|
|
414
|
-
|
|
389
|
+
1. Pathao sends a POST request with a JSON payload to your URL.
|
|
390
|
+
2. The `X-PATHAO-Signature` header contains your configured webhook secret verbatim.
|
|
391
|
+
3. Your endpoint must respond within 10 seconds with an `X-Pathao-Merchant-Webhook-Integration-Secret` header whose value equals your webhook secret.
|
|
392
|
+
4. The HTTP status code should be 2xx.
|
|
415
393
|
|
|
416
|
-
|
|
394
|
+
### Setup requirements
|
|
417
395
|
|
|
418
|
-
|
|
396
|
+
- Your URL must be publicly reachable over HTTPS with a valid SSL certificate.
|
|
397
|
+
- Configure your webhook URL and note the secret from the [Pathao Merchant Dashboard](https://merchant.pathao.com/developer).
|
|
398
|
+
- Store the secret in an environment variable (e.g. `PATHAO_WEBHOOK_SECRET`).
|
|
419
399
|
|
|
420
|
-
|
|
400
|
+
### Import
|
|
421
401
|
|
|
422
402
|
```typescript
|
|
403
|
+
// ESM / TypeScript
|
|
423
404
|
import {
|
|
424
405
|
PathaoWebhookHandler,
|
|
425
|
-
constructEvent,
|
|
426
|
-
verifySignature,
|
|
427
406
|
PathaoWebhookEvent,
|
|
428
|
-
|
|
429
|
-
|
|
407
|
+
constructEvent,
|
|
408
|
+
PathaoWebhookError,
|
|
409
|
+
} from "pathao-merchant-sdk/webhooks";
|
|
430
410
|
|
|
431
|
-
```javascript
|
|
432
411
|
// CommonJS
|
|
433
|
-
const { PathaoWebhookHandler } = require(
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### Quick verification
|
|
437
|
-
|
|
438
|
-
```typescript
|
|
439
|
-
import { verifySignature } from 'pathao-merchant-sdk/webhooks';
|
|
440
|
-
|
|
441
|
-
const isValid = verifySignature(
|
|
442
|
-
req.headers['x-pathao-signature'],
|
|
443
|
-
process.env.PATHAO_WEBHOOK_SECRET!,
|
|
444
|
-
);
|
|
412
|
+
const { PathaoWebhookHandler } = require("pathao-merchant-sdk/webhooks");
|
|
445
413
|
```
|
|
446
414
|
|
|
447
|
-
###
|
|
415
|
+
### Express integration
|
|
448
416
|
|
|
449
417
|
```typescript
|
|
450
|
-
import
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
req.body, // raw Buffer — do NOT pre-parse
|
|
456
|
-
req.headers,
|
|
457
|
-
process.env.PATHAO_WEBHOOK_SECRET!,
|
|
458
|
-
);
|
|
459
|
-
console.log('Event:', payload.event, payload.data);
|
|
460
|
-
res.sendStatus(200);
|
|
461
|
-
} catch (err) {
|
|
462
|
-
if (err instanceof PathaoWebhookError) {
|
|
463
|
-
res.status(400).send(err.message);
|
|
464
|
-
} else {
|
|
465
|
-
res.sendStatus(500);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### Express middleware
|
|
472
|
-
|
|
473
|
-
```typescript
|
|
474
|
-
import { PathaoWebhookHandler, PathaoWebhookEvent } from 'pathao-merchant-sdk/webhooks';
|
|
418
|
+
import express from "express";
|
|
419
|
+
import {
|
|
420
|
+
PathaoWebhookHandler,
|
|
421
|
+
PathaoWebhookEvent,
|
|
422
|
+
} from "pathao-merchant-sdk/webhooks";
|
|
475
423
|
|
|
424
|
+
const app = express();
|
|
476
425
|
const handler = new PathaoWebhookHandler(process.env.PATHAO_WEBHOOK_SECRET!);
|
|
477
426
|
|
|
478
|
-
// Listen for specific events (fully typed payload)
|
|
479
427
|
handler.on(PathaoWebhookEvent.ORDER_DELIVERED, (payload) => {
|
|
480
|
-
console.log(
|
|
428
|
+
console.log(
|
|
429
|
+
"Delivered:",
|
|
430
|
+
payload.consignment_id,
|
|
431
|
+
"Collected:",
|
|
432
|
+
payload.collected_amount,
|
|
433
|
+
);
|
|
481
434
|
});
|
|
482
435
|
|
|
483
|
-
handler.on(PathaoWebhookEvent.
|
|
484
|
-
console.log(
|
|
436
|
+
handler.on(PathaoWebhookEvent.ORDER_PAID, (payload) => {
|
|
437
|
+
console.log("Invoice:", payload.invoice_id);
|
|
485
438
|
});
|
|
486
439
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
console.log('Any event:', payload.event, payload.data);
|
|
440
|
+
handler.on("error", (err) => {
|
|
441
|
+
console.error("Webhook error:", err.message);
|
|
490
442
|
});
|
|
491
443
|
|
|
492
|
-
// Handle errors (invalid signature, bad JSON, etc.)
|
|
493
|
-
handler.on('error', (err) => {
|
|
494
|
-
console.error('Webhook error:', err.message);
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
// Mount — must use express.raw() BEFORE this middleware
|
|
498
444
|
app.post(
|
|
499
|
-
|
|
500
|
-
express.
|
|
445
|
+
"/webhooks/pathao",
|
|
446
|
+
express.json(),
|
|
501
447
|
handler.expressMiddleware(),
|
|
448
|
+
(req, res) => {
|
|
449
|
+
// expressMiddleware() sets the required secret header automatically.
|
|
450
|
+
// It also handles the handshake event internally (returns 202).
|
|
451
|
+
// For all other events the payload is on req.pathaoWebhook.
|
|
452
|
+
res.sendStatus(200);
|
|
453
|
+
},
|
|
502
454
|
);
|
|
503
|
-
|
|
504
|
-
// Access the parsed payload downstream
|
|
505
|
-
app.post('/webhook/pathao', express.raw({ type: 'application/json' }), handler.expressMiddleware(), (req, res) => {
|
|
506
|
-
console.log(req.pathaoWebhook); // typed PathaoWebhookPayload
|
|
507
|
-
res.sendStatus(200);
|
|
508
|
-
});
|
|
509
455
|
```
|
|
510
456
|
|
|
511
|
-
###
|
|
457
|
+
### Framework-agnostic middleware
|
|
512
458
|
|
|
513
459
|
```typescript
|
|
514
460
|
const handler = new PathaoWebhookHandler(process.env.PATHAO_WEBHOOK_SECRET!);
|
|
515
461
|
const middleware = handler.middleware();
|
|
516
462
|
|
|
517
|
-
//
|
|
518
|
-
const
|
|
519
|
-
if (error) {
|
|
520
|
-
console.error('Bad webhook:', error.message);
|
|
521
|
-
} else {
|
|
522
|
-
console.log('Event:', payload!.event);
|
|
523
|
-
}
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
### Supported event types
|
|
463
|
+
// In any async handler (Fastify, Hono, plain http, etc.)
|
|
464
|
+
const instructions = await middleware(rawBody);
|
|
527
465
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
| `ORDER_ACCEPTED` | `order.accepted` |
|
|
532
|
-
| `ORDER_PICKUP_REQUESTED` | `order.pickup_requested` |
|
|
533
|
-
| `ORDER_PICKED` | `order.picked` |
|
|
534
|
-
| `ORDER_IN_TRANSIT` | `order.in_transit` |
|
|
535
|
-
| `ORDER_DELIVERED` | `order.delivered` |
|
|
536
|
-
| `ORDER_CANCELLED` | `order.cancelled` |
|
|
537
|
-
| `ORDER_HOLD` | `order.hold` |
|
|
538
|
-
| `ORDER_RETURN_REQUESTED` | `order.return_requested` |
|
|
539
|
-
| `ORDER_RETURN_PICKUP_REQUESTED` | `order.return_pickup_requested` |
|
|
540
|
-
| `ORDER_RETURN_PICKED` | `order.return_picked` |
|
|
541
|
-
| `ORDER_RETURN_IN_TRANSIT` | `order.return_in_transit` |
|
|
542
|
-
| `ORDER_PARTIAL_DELIVERED` | `order.partial_delivered` |
|
|
543
|
-
| `ORDER_DELIVERY_FAILED` | `order.delivery_failed` |
|
|
544
|
-
| `ORDER_ON_HOLD` | `order.on_hold` |
|
|
545
|
-
| `ORDER_PAID` | `order.paid` |
|
|
546
|
-
| `ORDER_PAID_RETURN` | `order.paid_return` |
|
|
547
|
-
| `ORDER_RETURNED` | `order.returned` |
|
|
548
|
-
| `ORDER_EXCHANGED` | `order.exchanged` |
|
|
549
|
-
| `STORE_CREATED` | `store.created` |
|
|
550
|
-
| `STORE_UPDATED` | `store.updated` |
|
|
551
|
-
|
|
552
|
-
### TypeScript types
|
|
553
|
-
|
|
554
|
-
All event payloads are fully typed. Access them via `WebhookEventPayloadMap`:
|
|
466
|
+
for (const [key, value] of Object.entries(instructions.headers)) {
|
|
467
|
+
reply.header(key, value); // always set — the secret header is required for every response
|
|
468
|
+
}
|
|
555
469
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
PathaoWebhookEvent,
|
|
560
|
-
OrderDeliveredPayload,
|
|
561
|
-
} from 'pathao-merchant-sdk/webhooks';
|
|
470
|
+
if (instructions.error) {
|
|
471
|
+
return reply.status(400).send({ error: instructions.error.message });
|
|
472
|
+
}
|
|
562
473
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
};
|
|
474
|
+
if (instructions.payload?.event === "webhook_integration") {
|
|
475
|
+
return reply.status(202).send();
|
|
476
|
+
}
|
|
567
477
|
|
|
568
|
-
//
|
|
569
|
-
|
|
478
|
+
// instructions.payload is typed as PathaoWebhookPayload
|
|
479
|
+
console.log(instructions.payload?.event);
|
|
480
|
+
return reply.status(200).send({ received: true });
|
|
570
481
|
```
|
|
571
482
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
The SDK automatically handles OAuth2 authentication and token refresh. You only need to provide your credentials once during initialization:
|
|
483
|
+
### Parse and verify manually
|
|
575
484
|
|
|
576
485
|
```typescript
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
486
|
+
import {
|
|
487
|
+
constructEvent,
|
|
488
|
+
PathaoWebhookError,
|
|
489
|
+
} from "pathao-merchant-sdk/webhooks";
|
|
490
|
+
|
|
491
|
+
app.post("/webhooks/pathao", express.json(), (req, res) => {
|
|
492
|
+
res.setHeader(
|
|
493
|
+
"X-Pathao-Merchant-Webhook-Integration-Secret",
|
|
494
|
+
process.env.PATHAO_WEBHOOK_SECRET!,
|
|
495
|
+
);
|
|
496
|
+
try {
|
|
497
|
+
const payload = constructEvent(req.body);
|
|
498
|
+
console.log("Event:", payload.event);
|
|
499
|
+
res.sendStatus(200);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (err instanceof PathaoWebhookError) {
|
|
502
|
+
res.status(400).send(err.message);
|
|
503
|
+
} else {
|
|
504
|
+
res.sendStatus(500);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
582
507
|
});
|
|
583
508
|
```
|
|
584
509
|
|
|
585
|
-
|
|
510
|
+
### Supported event types
|
|
586
511
|
|
|
587
|
-
|
|
512
|
+
All 24 event types from the Pathao dashboard:
|
|
513
|
+
|
|
514
|
+
| Enum constant | Event string | Key payload fields |
|
|
515
|
+
| --------------------------------- | --------------------------------- | ---------------------------------------------------------------------------- |
|
|
516
|
+
| `ORDER_CREATED` | `order.created` | `consignment_id`, `store_id`, `delivery_fee` |
|
|
517
|
+
| `ORDER_UPDATED` | `order.updated` | `consignment_id`, `store_id`, `delivery_fee` |
|
|
518
|
+
| `ORDER_PICKUP_REQUESTED` | `order.pickup-requested` | `consignment_id`, `store_id`, `delivery_fee` |
|
|
519
|
+
| `ORDER_ASSIGNED_FOR_PICKUP` | `order.assigned-for-pickup` | `consignment_id`, `store_id` |
|
|
520
|
+
| `ORDER_PICKED` | `order.picked` | `consignment_id`, `store_id` |
|
|
521
|
+
| `ORDER_PICKUP_FAILED` | `order.pickup-failed` | `consignment_id`, `store_id` |
|
|
522
|
+
| `ORDER_PICKUP_CANCELLED` | `order.pickup-cancelled` | `consignment_id`, `store_id` |
|
|
523
|
+
| `ORDER_AT_THE_SORTING_HUB` | `order.at-the-sorting-hub` | `consignment_id`, `store_id` |
|
|
524
|
+
| `ORDER_IN_TRANSIT` | `order.in-transit` | `consignment_id`, `store_id` |
|
|
525
|
+
| `ORDER_RECEIVED_AT_LAST_MILE_HUB` | `order.received-at-last-mile-hub` | `consignment_id`, `store_id` |
|
|
526
|
+
| `ORDER_ASSIGNED_FOR_DELIVERY` | `order.assigned-for-delivery` | `consignment_id`, `store_id` |
|
|
527
|
+
| `ORDER_DELIVERED` | `order.delivered` | `consignment_id`, `store_id`, `collected_amount` |
|
|
528
|
+
| `ORDER_PARTIAL_DELIVERY` | `order.partial-delivery` | `consignment_id`, `collected_amount`, `reason?` |
|
|
529
|
+
| `ORDER_RETURNED` | `order.returned` | `consignment_id`, `reason?` |
|
|
530
|
+
| `ORDER_DELIVERY_FAILED` | `order.delivery-failed` | `consignment_id`, `reason?` |
|
|
531
|
+
| `ORDER_ON_HOLD` | `order.on-hold` | `consignment_id`, `reason?` |
|
|
532
|
+
| `ORDER_PAID` | `order.paid` | `consignment_id`, `invoice_id` |
|
|
533
|
+
| `ORDER_PAID_RETURN` | `order.paid-return` | `consignment_id`, `collected_amount`, `reason?` |
|
|
534
|
+
| `ORDER_EXCHANGED` | `order.exchanged` | `consignment_id`, `collected_amount`, `reason?` |
|
|
535
|
+
| `ORDER_RETURN_ID_CREATED` | `order.return-id-created` | `consignment_id`, `return_consignment_id`, `return_type`, `collected_amount` |
|
|
536
|
+
| `ORDER_RETURN_IN_TRANSIT` | `order.return-in-transit` | `consignment_id`, `return_consignment_id`, `return_type`, `collected_amount` |
|
|
537
|
+
| `ORDER_RETURNED_TO_MERCHANT` | `order.returned-to-merchant` | `consignment_id`, `return_consignment_id`, `return_type`, `collected_amount` |
|
|
538
|
+
| `STORE_CREATED` | `store.created` | `store_id`, `store_name`, `store_address`, `is_active` |
|
|
539
|
+
| `STORE_UPDATED` | `store.updated` | `store_id`, `store_name`, `store_address`, `is_active` |
|
|
540
|
+
|
|
541
|
+
All payloads also include `updated_at` (MySQL datetime) and `timestamp` (ISO 8601).
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## TypeScript Types
|
|
588
546
|
|
|
589
547
|
```typescript
|
|
590
|
-
import {
|
|
548
|
+
import type {
|
|
549
|
+
PathaoConfig,
|
|
550
|
+
PathaoOrderRequest,
|
|
551
|
+
PathaoOrderResponse,
|
|
552
|
+
PathaoStoreRequest,
|
|
553
|
+
PathaoStore,
|
|
554
|
+
PathaoPriceRequest,
|
|
555
|
+
PathaoPriceResponse,
|
|
556
|
+
PathaoOrderStatusResponse,
|
|
557
|
+
DeliveryType,
|
|
558
|
+
ItemType,
|
|
559
|
+
} from "pathao-merchant-sdk";
|
|
591
560
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
561
|
+
import type {
|
|
562
|
+
PathaoWebhookPayload,
|
|
563
|
+
WebhookEventPayloadMap,
|
|
564
|
+
OrderDeliveredPayload,
|
|
565
|
+
OrderReturnIdCreatedPayload,
|
|
566
|
+
PathaoWebhookEvent,
|
|
567
|
+
} from "pathao-merchant-sdk/webhooks";
|
|
599
568
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
const price = await pathao.calculatePrice({
|
|
603
|
-
store_id: 123,
|
|
604
|
-
item_type: ItemType.PARCEL,
|
|
605
|
-
item_weight: 1.0,
|
|
606
|
-
delivery_type: DeliveryType.NORMAL,
|
|
607
|
-
recipient_city: 1,
|
|
608
|
-
recipient_zone: 1,
|
|
609
|
-
recipient_area: 1
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
console.log('Estimated cost:', price.data.total_charge);
|
|
613
|
-
|
|
614
|
-
// 2. Create the order
|
|
615
|
-
const order = await pathao.createOrder({
|
|
616
|
-
store_id: 123,
|
|
617
|
-
merchant_order_id: `ORDER-${Date.now()}`,
|
|
618
|
-
recipient_name: 'John Doe',
|
|
619
|
-
recipient_phone: '01712345678',
|
|
620
|
-
recipient_address: '123 Main Street, Dhanmondi, Dhaka',
|
|
621
|
-
delivery_type: DeliveryType.NORMAL,
|
|
622
|
-
item_type: ItemType.PARCEL,
|
|
623
|
-
item_quantity: 1,
|
|
624
|
-
item_weight: 1.0,
|
|
625
|
-
amount_to_collect: 500
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
console.log('Order created successfully:', {
|
|
629
|
-
consignmentId: order.data.consignment_id,
|
|
630
|
-
invoiceId: order.data.invoice_id,
|
|
631
|
-
status: order.data.status
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
// 3. Track the order
|
|
635
|
-
const status = await pathao.getOrderStatus(order.data.consignment_id);
|
|
636
|
-
console.log('Current status:', status.data.status);
|
|
637
|
-
|
|
638
|
-
} catch (error) {
|
|
639
|
-
console.error('Delivery order failed:', error.message);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
569
|
+
// Access a specific payload type via the map
|
|
570
|
+
type PaidPayload = WebhookEventPayloadMap[PathaoWebhookEvent.ORDER_PAID];
|
|
642
571
|
```
|
|
643
572
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
This SDK is based on the official Pathao Courier Merchant API documentation. For complete API reference and details:
|
|
647
|
-
|
|
648
|
-
- **[Official API Documentation](./docs/official-pathao-api-documentation.md)** - Complete Pathao API guide
|
|
649
|
-
- **[API Reference](./docs/pathao-api-reference.txt)** - Original API reference document
|
|
650
|
-
- **[Pathao Merchant Portal](https://merchant.pathao.com)** - Official merchant dashboard
|
|
573
|
+
---
|
|
651
574
|
|
|
652
575
|
## Contributing
|
|
653
576
|
|
|
654
|
-
Contributions are welcome
|
|
577
|
+
Contributions are welcome. Please open an issue first for significant changes.
|
|
578
|
+
|
|
579
|
+
1. Fork the repo
|
|
580
|
+
2. Create a feature branch
|
|
581
|
+
3. Run `pnpm test` and `pnpm run type-check` before submitting
|
|
655
582
|
|
|
656
583
|
## Development
|
|
657
584
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
585
|
+
```bash
|
|
586
|
+
pnpm install
|
|
587
|
+
pnpm run build # compile CJS + ESM + .d.ts
|
|
588
|
+
pnpm test # run Jest test suite
|
|
589
|
+
pnpm run type-check # tsc --noEmit
|
|
590
|
+
pnpm run lint # ESLint
|
|
591
|
+
```
|
|
662
592
|
|
|
663
593
|
## License
|
|
664
594
|
|
|
665
|
-
|
|
595
|
+
MIT — see [LICENSE](LICENSE).
|
|
666
596
|
|
|
667
597
|
## Support
|
|
668
598
|
|
|
669
|
-
|
|
599
|
+
Open an issue on [GitHub](https://github.com/sifat07/pathao-merchant-sdk/issues).
|
|
670
600
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
This is an **unofficial** SDK and is not affiliated with or endorsed by Pathao. Use at your own risk. The maintainers are not responsible for any issues that may arise from using this package.
|
|
601
|
+
---
|
|
674
602
|
|
|
675
603
|
## Changelog
|
|
676
604
|
|
|
605
|
+
### 2.2.0 — 2026-04-15
|
|
606
|
+
|
|
607
|
+
- Added 3 missing webhook event types from official dashboard docs: `order.return-id-created`, `order.return-in-transit`, `order.returned-to-merchant` with full `ReturnOrderWebhookPayload` type
|
|
608
|
+
- Fixed tsconfig: added `node` and `jest` to `types` so `Buffer`/`EventEmitter` resolve correctly
|
|
609
|
+
- Fixed webhook header handling and improved event processing robustness
|
|
610
|
+
|
|
677
611
|
### 2.1.0
|
|
678
|
-
|
|
679
|
-
-
|
|
680
|
-
- `
|
|
612
|
+
|
|
613
|
+
- Added `pathao-merchant-sdk/webhooks` sub-path entry point
|
|
614
|
+
- `PathaoWebhookHandler` — EventEmitter with typed `on()` overloads for all event types
|
|
615
|
+
- `constructEvent()` standalone helper
|
|
681
616
|
- Express middleware and generic async middleware
|
|
682
|
-
- Constant-time signature comparison via `crypto.timingSafeEqual`
|
|
683
|
-
- Fixed case-insensitive header lookup for `X-PATHAO-Signature`
|
|
684
617
|
|
|
685
618
|
### 2.0.x
|
|
686
|
-
|
|
687
|
-
-
|
|
688
|
-
-
|
|
689
|
-
-
|
|
690
|
-
-
|
|
691
|
-
-
|
|
692
|
-
-
|
|
693
|
-
- `
|
|
694
|
-
- `
|
|
619
|
+
|
|
620
|
+
- Factory methods: `fromEnv()`, `fromConfig()`, `sandbox()`, `production()`
|
|
621
|
+
- Debug logging (`debug` option) — `Authorization` header redacted
|
|
622
|
+
- Configurable circuit breaker (throws `PathaoApiError` code 503 when open)
|
|
623
|
+
- Retry logic: 429 reads `Retry-After`, 5xx exponential backoff (max 2 retries)
|
|
624
|
+
- Deferred config validation — constructor never throws
|
|
625
|
+
- HTTPS enforcement in `validateConfiguration()`
|
|
626
|
+
- `User-Agent: pathao-merchant-sdk node/<version>` header
|
|
627
|
+
- `getStores(page?)` pagination parameter
|
|
695
628
|
- `is_active` and `cod_enabled` typed as `0 | 1`
|
|
696
|
-
- Fixed shell injection in `scripts/release.js`
|
|
697
|
-
- CI/CD: replaced deprecated actions, added version-existence check before publish
|
|
629
|
+
- Fixed shell injection in `scripts/release.js`
|
|
698
630
|
|
|
699
631
|
### 1.0.0
|
|
700
|
-
|
|
701
|
-
-
|
|
702
|
-
- TypeScript support
|
|
703
|
-
- Automatic authentication
|
|
704
|
-
- Order management
|
|
705
|
-
- Store management
|
|
706
|
-
- Price calculation
|
|
707
|
-
- Location services
|
|
632
|
+
|
|
633
|
+
- Initial release — order management, store management, price calculation, location services, automatic OAuth2
|