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