@waffo/waffo-integrate 1.0.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/LICENSE +21 -0
- package/README.md +98 -0
- package/SKILL.md +462 -0
- package/bin/install.js +85 -0
- package/docs/INDEX.md +50 -0
- package/package.json +29 -0
- package/references/api-contract.md +539 -0
- package/references/go.md +688 -0
- package/references/java.md +615 -0
- package/references/node.md +576 -0
package/docs/INDEX.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Waffo Integration Knowledge Base
|
|
2
|
+
|
|
3
|
+
Extended documentation for common scenarios, troubleshooting, and best practices when integrating Waffo Payment SDK.
|
|
4
|
+
|
|
5
|
+
> **For AI assistants**: When a developer's question is not covered by `SKILL.md` or `references/`, search this index for relevant articles and read the linked document.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## FAQ
|
|
10
|
+
|
|
11
|
+
| Topic | Document | Description |
|
|
12
|
+
|-------|----------|-------------|
|
|
13
|
+
| _Coming soon_ | | |
|
|
14
|
+
|
|
15
|
+
<!-- Example:
|
|
16
|
+
| Subscription billing retry | [faq/subscription-retry.md](faq/subscription-retry.md) | How Waffo handles failed recurring payments and retry logic |
|
|
17
|
+
| Apple Pay integration | [faq/applepay-setup.md](faq/applepay-setup.md) | Domain verification, merchant ID setup, and sandbox testing |
|
|
18
|
+
-->
|
|
19
|
+
|
|
20
|
+
## Troubleshooting
|
|
21
|
+
|
|
22
|
+
| Symptom | Document | Description |
|
|
23
|
+
|---------|----------|-------------|
|
|
24
|
+
| _Coming soon_ | | |
|
|
25
|
+
|
|
26
|
+
<!-- Example:
|
|
27
|
+
| A0003 error on subscription create | [troubleshooting/a0003-missing-fields.md](troubleshooting/a0003-missing-fields.md) | Required fields that openapi.json doesn't mark as required |
|
|
28
|
+
| Webhook not received | [troubleshooting/webhook-not-received.md](troubleshooting/webhook-not-received.md) | Common causes: URL not public, signature mismatch, firewall |
|
|
29
|
+
-->
|
|
30
|
+
|
|
31
|
+
## Best Practices
|
|
32
|
+
|
|
33
|
+
| Topic | Document | Description |
|
|
34
|
+
|-------|----------|-------------|
|
|
35
|
+
| _Coming soon_ | | |
|
|
36
|
+
|
|
37
|
+
<!-- Example:
|
|
38
|
+
| Idempotency design | [best-practices/idempotency.md](best-practices/idempotency.md) | Request ID generation, retry strategy, deduplication |
|
|
39
|
+
| Multi-currency checkout | [best-practices/multi-currency.md](best-practices/multi-currency.md) | orderCurrency vs userCurrency, FX handling |
|
|
40
|
+
-->
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Contributing
|
|
45
|
+
|
|
46
|
+
To add a new article:
|
|
47
|
+
|
|
48
|
+
1. Create a `.md` file in the appropriate subdirectory (`faq/`, `troubleshooting/`, `best-practices/`)
|
|
49
|
+
2. Add an entry to the table above with a link and one-line description
|
|
50
|
+
3. Submit a PR
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@waffo/waffo-integrate",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Claude Code / Cursor skill for integrating Waffo Payment SDK (Node.js / Java / Go)",
|
|
5
|
+
"bin": {
|
|
6
|
+
"waffo-integrate": "./bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"SKILL.md",
|
|
11
|
+
"references/",
|
|
12
|
+
"docs/"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"waffo",
|
|
16
|
+
"payment",
|
|
17
|
+
"sdk",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"cursor",
|
|
20
|
+
"skill",
|
|
21
|
+
"integration"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/waffo-com/waffo-integrate.git"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"author": "Waffo"
|
|
29
|
+
}
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# Waffo API Contract Reference
|
|
2
|
+
|
|
3
|
+
Source: `openapi.json` (authoritative). All field names are camelCase JSON.
|
|
4
|
+
|
|
5
|
+
## Response Envelope
|
|
6
|
+
|
|
7
|
+
All responses: `{ code: string, msg: string, data: <DataSchema> }`
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Order Module
|
|
12
|
+
|
|
13
|
+
### Order Create — `POST /api/v1/order/create`
|
|
14
|
+
|
|
15
|
+
**Request** (`AcqOrderCreateRequest`):
|
|
16
|
+
- `paymentRequestId`: string (required) — max 32, idempotent key
|
|
17
|
+
- `merchantOrderId`: string (required) — max 64
|
|
18
|
+
- `orderCurrency`: string (required) — max 12, e.g. "IDR"
|
|
19
|
+
- `orderAmount`: string (required) — max 24
|
|
20
|
+
- `userCurrency`: string — max 12, cross-currency only
|
|
21
|
+
- `orderDescription`: string (required) — max 128
|
|
22
|
+
- `orderRequestedAt`: string/date-time (required)
|
|
23
|
+
- `orderExpiredAt`: string/date-time
|
|
24
|
+
- `successRedirectUrl`: string — max 512
|
|
25
|
+
- `failedRedirectUrl`: string — max 512
|
|
26
|
+
- `cancelRedirectUrl`: string — max 512
|
|
27
|
+
- `notifyUrl`: string (required) — max 256
|
|
28
|
+
- `extendInfo`: string — max 128, JSON
|
|
29
|
+
- `merchantInfo`: MerchantInfo (required)
|
|
30
|
+
- `userInfo`: OrderUserInfo (required)
|
|
31
|
+
- `goodsInfo`: OrderGoodsInfo
|
|
32
|
+
- `paymentInfo`: OrderPaymentInfo (required)
|
|
33
|
+
- `cardInfo`: CardInfo
|
|
34
|
+
- `paymentTokenData`: string — max 8192, ApplePay/GooglePay
|
|
35
|
+
- `riskData`: OrderRiskData
|
|
36
|
+
- `addressInfo`: OrderAddressInfo
|
|
37
|
+
|
|
38
|
+
**Response** (`AcqOrderCreatedResponse`):
|
|
39
|
+
- `paymentRequestId`: string (required)
|
|
40
|
+
- `merchantOrderId`: string (required)
|
|
41
|
+
- `acquiringOrderId`: string (required)
|
|
42
|
+
- `orderStatus`: string (required) — "PAY_IN_PROGRESS" | "AUTHORIZATION_REQUIRED" | "AUTHED_WAITING_CAPTURE" | "PAY_SUCCESS" | "ORDER_CLOSE"
|
|
43
|
+
- `orderAction`: string — JSON with actionType, webUrl, deeplinkUrl, actionData
|
|
44
|
+
|
|
45
|
+
### Order Inquiry — `POST /api/v1/order/inquiry`
|
|
46
|
+
|
|
47
|
+
**Request** (`AcqOrderInquiryRequest`): provide one of:
|
|
48
|
+
- `paymentRequestId`: string
|
|
49
|
+
- `acquiringOrderId`: string
|
|
50
|
+
|
|
51
|
+
**Response** (`AcqOrderInquiry`):
|
|
52
|
+
- `paymentRequestId`: string (required)
|
|
53
|
+
- `merchantOrderId`: string (required)
|
|
54
|
+
- `acquiringOrderId`: string (required)
|
|
55
|
+
- `orderStatus`: string (required) — same enum as Create
|
|
56
|
+
- `orderAction`: string
|
|
57
|
+
- `orderCurrency`: string (required)
|
|
58
|
+
- `orderAmount`: string (required)
|
|
59
|
+
- `finalDealAmount`: string (required)
|
|
60
|
+
- `orderDescription`: string (required)
|
|
61
|
+
- `merchantInfo`: MerchantInfo
|
|
62
|
+
- `userInfo`: OrderUserInfo
|
|
63
|
+
- `goodsInfo`: OrderGoodsInfo
|
|
64
|
+
- `paymentInfo`: OrderPaymentInfo
|
|
65
|
+
- `addressInfo`: OrderAddressInfo
|
|
66
|
+
- `orderRequestedAt`: string
|
|
67
|
+
- `orderExpiredAt`: string
|
|
68
|
+
- `orderUpdatedAt`: string
|
|
69
|
+
- `orderCompletedAt`: string
|
|
70
|
+
- `refundExpiryAt`: string
|
|
71
|
+
- `cancelRedirectUrl`: string
|
|
72
|
+
- `orderFailedReason`: string — JSON
|
|
73
|
+
- `extendInfo`: string
|
|
74
|
+
- `userCurrency`: string
|
|
75
|
+
- `subscriptionInfo`: SubscriptionInfo
|
|
76
|
+
|
|
77
|
+
### Order Cancel — `POST /api/v1/order/cancel`
|
|
78
|
+
|
|
79
|
+
**Request** (`AcqOrderCancelRequest`): provide paymentRequestId or acquiringOrderId:
|
|
80
|
+
- `paymentRequestId`: string — max 32
|
|
81
|
+
- `acquiringOrderId`: string — max 32
|
|
82
|
+
- `merchantId`: string (required) — max 64
|
|
83
|
+
- `orderRequestedAt`: string/date-time (required)
|
|
84
|
+
|
|
85
|
+
**Response** (`AcqOrderCancelResponse`):
|
|
86
|
+
- `paymentRequestId`: string (required)
|
|
87
|
+
- `merchantOrderId`: string (required)
|
|
88
|
+
- `acquiringOrderId`: string (required)
|
|
89
|
+
- `orderStatus`: string (required) — "ORDER_CLOSE"
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 2. Refund Module
|
|
94
|
+
|
|
95
|
+
### Order Refund — `POST /api/v1/order/refund`
|
|
96
|
+
|
|
97
|
+
**Request** (`AcqOrderRefundRequest`):
|
|
98
|
+
- `refundRequestId`: string (required) — max 32, idempotent key
|
|
99
|
+
- `acquiringOrderId`: string (required) — max 32
|
|
100
|
+
- `merchantRefundOrderId`: string — max 64
|
|
101
|
+
- `merchantId`: string (required) — max 64
|
|
102
|
+
- `requestedAt`: string/date-time (required)
|
|
103
|
+
- `refundAmount`: string (required) — min 1 char
|
|
104
|
+
- `refundReason`: string (required) — max 256
|
|
105
|
+
- `refundNotifyUrl`: string — max 256
|
|
106
|
+
- `extendInfo`: string — max 128, JSON
|
|
107
|
+
- `refundSource`: string
|
|
108
|
+
- `userInfo`: RefundOrderUserInfo
|
|
109
|
+
|
|
110
|
+
**Response** (`AcqOrderRefundResponse`):
|
|
111
|
+
- `refundRequestId`: string (required)
|
|
112
|
+
- `merchantRefundOrderId`: string
|
|
113
|
+
- `acquiringOrderId`: string (required)
|
|
114
|
+
- `acquiringRefundOrderId`: string (required)
|
|
115
|
+
- `refundAmount`: string (required)
|
|
116
|
+
- `refundStatus`: string (required) — "REFUND_IN_PROGRESS" | "ORDER_PARTIALLY_REFUNDED" | "ORDER_FULLY_REFUNDED" | "ORDER_REFUND_FAILED"
|
|
117
|
+
- `remainingRefundAmount`: string (required)
|
|
118
|
+
- `refundSource`: string (required) — "MERCHANT" | "RDR" | "ETHOCA"
|
|
119
|
+
|
|
120
|
+
### Refund Inquiry — `POST /api/v1/refund/inquiry`
|
|
121
|
+
|
|
122
|
+
**Request** (`AcqOrderRefundInquiryRequest`): provide one of:
|
|
123
|
+
- `refundRequestId`: string
|
|
124
|
+
- `acquiringRefundOrderId`: string
|
|
125
|
+
|
|
126
|
+
**Response** (`AcqOrderRefundInquiry`):
|
|
127
|
+
- `refundRequestId`: string (required)
|
|
128
|
+
- `merchantRefundOrderId`: string
|
|
129
|
+
- `acquiringOrderId`: string (required)
|
|
130
|
+
- `acquiringRefundOrderId`: string (required)
|
|
131
|
+
- `origPaymentRequestId`: string (required)
|
|
132
|
+
- `refundAmount`: string (required)
|
|
133
|
+
- `refundStatus`: string (required) — same enum as Refund
|
|
134
|
+
- `refundReason`: string (required)
|
|
135
|
+
- `refundRequestedAt`: string (required)
|
|
136
|
+
- `refundUpdatedAt`: string (required)
|
|
137
|
+
- `refundFailedReason`: string — JSON
|
|
138
|
+
- `extendInfo`: string
|
|
139
|
+
- `userCurrency`: string
|
|
140
|
+
- `finalDealAmount`: string (required)
|
|
141
|
+
- `remainingRefundAmount`: string (required)
|
|
142
|
+
- `userInfo`: RefundOrderUserInfo
|
|
143
|
+
- `refundCompletedAt`: string
|
|
144
|
+
- `refundSource`: string — "MERCHANT" | "RDR" | "ETHOCA"
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 3. Subscription Module
|
|
149
|
+
|
|
150
|
+
> **IMPORTANT**: Subscription uses `currency`/`amount`; Order uses `orderCurrency`/`orderAmount`. Subscription uses `requestedAt`; Order uses `orderRequestedAt`.
|
|
151
|
+
|
|
152
|
+
### Subscription Create — `POST /api/v1/subscription/create`
|
|
153
|
+
|
|
154
|
+
**Request** (`AcqSubscriptionCreateRequest`):
|
|
155
|
+
- `subscriptionRequest`: string (required) — max 32, idempotent key
|
|
156
|
+
- `merchantSubscriptionId`: string (required) — max 64
|
|
157
|
+
- `currency`: string (required) — max 12
|
|
158
|
+
- `amount`: string (required) — max 24
|
|
159
|
+
- `userCurrency`: string — max 12
|
|
160
|
+
- `productInfo`: ProductInfo (required)
|
|
161
|
+
- `merchantInfo`: MerchantInfo (required)
|
|
162
|
+
- `userInfo`: UserInfo (required)
|
|
163
|
+
- `goodsInfo`: GoodsInfo
|
|
164
|
+
- `addressInfo`: AddressInfo
|
|
165
|
+
- `paymentInfo`: PaymentInfo (required — productName, payMethodName required)
|
|
166
|
+
- `requestedAt`: string/date-time (required)
|
|
167
|
+
- `successRedirectUrl`: string (required) — max 512
|
|
168
|
+
- `failedRedirectUrl`: string (required) — max 512
|
|
169
|
+
- `cancelRedirectUrl`: string (required) — max 512
|
|
170
|
+
- `notifyUrl`: string (required) — max 256
|
|
171
|
+
- `subscriptionManagementUrl`: string (required) — max 256
|
|
172
|
+
- `extendInfo`: string — max 256, JSON
|
|
173
|
+
- `orderExpiredAt`: string/date-time
|
|
174
|
+
- `riskData`: RiskData
|
|
175
|
+
- `acqAgreement`: MerchantAcqProductAgreementEntity
|
|
176
|
+
|
|
177
|
+
**Response** (`AcqSubscriptionCreateResponse`):
|
|
178
|
+
- `subscriptionRequest`: string
|
|
179
|
+
- `merchantSubscriptionId`: string
|
|
180
|
+
- `subscriptionId`: string
|
|
181
|
+
- `payMethodSubscriptionId`: string
|
|
182
|
+
- `subscriptionStatus`: string — "AUTHORIZATION_REQUIRED" | "IN_PROGRESS" | "ACTIVE" | "CLOSE" | "MERCHANT_CANCELLED" | "USER_CANCELLED" | "CHANNEL_CANCELLED" | "EXPIRED"
|
|
183
|
+
- `subscriptionAction`: string — JSON with webUrl
|
|
184
|
+
|
|
185
|
+
### Subscription Inquiry — `POST /api/v1/subscription/inquiry`
|
|
186
|
+
|
|
187
|
+
**Request** (`SubscriptionInquiryRequest`):
|
|
188
|
+
- `subscriptionRequest`: string — max 32
|
|
189
|
+
- `subscriptionId`: string — max 64
|
|
190
|
+
- `paymentDetails`: integer — 0 (default) or 1
|
|
191
|
+
|
|
192
|
+
**Response** (`SubscriptionInquiryResponse`):
|
|
193
|
+
- `subscriptionRequest`: string
|
|
194
|
+
- `merchantSubscriptionId`: string
|
|
195
|
+
- `subscriptionId`: string
|
|
196
|
+
- `payMethodSubscriptionId`: string
|
|
197
|
+
- `subscriptionStatus`: string — same enum as Create
|
|
198
|
+
- `subscriptionAction`: string
|
|
199
|
+
- `currency`: string
|
|
200
|
+
- `userCurrency`: string
|
|
201
|
+
- `amount`: string
|
|
202
|
+
- `productInfo`: ProductInfo
|
|
203
|
+
- `merchantInfo`: MerchantInfo
|
|
204
|
+
- `userInfo`: UserInfo
|
|
205
|
+
- `paymentInfo`: PaymentInfo
|
|
206
|
+
- `requestedAt`: string
|
|
207
|
+
- `updatedAt`: string
|
|
208
|
+
- `failedReason`: string — JSON
|
|
209
|
+
- `subscriptionManagementUrl`: string
|
|
210
|
+
- `extendInfo`: string
|
|
211
|
+
- `paymentDetails`: PaymentDetail[]
|
|
212
|
+
- `goodsInfo`: GoodsInfo
|
|
213
|
+
- `addressInfo`: AddressInfo
|
|
214
|
+
|
|
215
|
+
### Subscription Cancel — `POST /api/v1/subscription/cancel`
|
|
216
|
+
|
|
217
|
+
**Request** (`SubscriptionCancelRequest`):
|
|
218
|
+
- `subscriptionId`: string (required) — max 64
|
|
219
|
+
- `merchantId`: string (required) — max 64
|
|
220
|
+
- `requestedAt`: string/date-time (required)
|
|
221
|
+
|
|
222
|
+
**Response** (`SubscriptionCancelResponse`):
|
|
223
|
+
- `merchantSubscriptionId`: string
|
|
224
|
+
- `subscriptionRequest`: string
|
|
225
|
+
- `subscriptionId`: string
|
|
226
|
+
- `orderStatus`: string — "CLOSE" | "MERCHANT_CANCELLED" | "CHANNEL_CANCELLED" | "EXPIRED"
|
|
227
|
+
|
|
228
|
+
### Subscription Manage — `POST /api/v1/subscription/manage`
|
|
229
|
+
|
|
230
|
+
**Request** (`SubscriptionManageRequest`):
|
|
231
|
+
- `subscriptionId`: string — max 64
|
|
232
|
+
- `subscriptionRequest`: string — max 64
|
|
233
|
+
|
|
234
|
+
**Response** (`SubscriptionManageResponse`):
|
|
235
|
+
- `subscriptionRequest`: string
|
|
236
|
+
- `merchantSubscriptionId`: string
|
|
237
|
+
- `subscriptionId`: string
|
|
238
|
+
- `managementUrl`: string
|
|
239
|
+
- `expiredAt`: string — ISO 8601
|
|
240
|
+
- `subscriptionStatus`: string — same status enum
|
|
241
|
+
|
|
242
|
+
### Subscription Change — `POST /api/v1/subscription/change`
|
|
243
|
+
|
|
244
|
+
**Request** (`SubscriptionChangeRequest`):
|
|
245
|
+
- `subscriptionRequest`: string (required) — max 32, NEW subscription request id
|
|
246
|
+
- `merchantSubscriptionId`: string — max 64
|
|
247
|
+
- `originSubscriptionRequest`: string (required) — max 32
|
|
248
|
+
- `remainingAmount`: string (required) — max 24
|
|
249
|
+
- `currency`: string (required) — max 12
|
|
250
|
+
- `userCurrency`: string — max 12
|
|
251
|
+
- `requestedAt`: string/date-time (required)
|
|
252
|
+
- `successRedirectUrl`: string — max 256
|
|
253
|
+
- `failedRedirectUrl`: string — max 256
|
|
254
|
+
- `notifyUrl`: string (required) — max 256
|
|
255
|
+
- `cancelRedirectUrl`: string — max 512
|
|
256
|
+
- `subscriptionManagementUrl`: string — max 256
|
|
257
|
+
- `extendInfo`: string — max 256, JSON
|
|
258
|
+
- `orderExpiredAt`: string/date-time
|
|
259
|
+
- `productInfoList`: ChangeProductInfo[] (required) — minItems 1
|
|
260
|
+
- `merchantInfo`: ChangeMerchantInfo (required)
|
|
261
|
+
- `userInfo`: ChangeUserInfo (required)
|
|
262
|
+
- `goodsInfo`: ChangeGoodsInfo (required)
|
|
263
|
+
- `addressInfo`: ChangeAddressInfo
|
|
264
|
+
- `paymentInfo`: ChangePaymentInfo (required — productName required)
|
|
265
|
+
- `riskData`: ChangeRiskData
|
|
266
|
+
|
|
267
|
+
**Response** (`SubscriptionChangeResponse`):
|
|
268
|
+
- `originSubscriptionRequest`: string
|
|
269
|
+
- `subscriptionRequest`: string
|
|
270
|
+
- `merchantSubscriptionId`: string
|
|
271
|
+
- `subscriptionChangeStatus`: string — "IN_PROGRESS" | "AUTHORIZATION_REQUIRED" | "SUCCESS" | "CLOSED"
|
|
272
|
+
- `subscriptionAction`: string
|
|
273
|
+
- `subscriptionId`: string (required)
|
|
274
|
+
|
|
275
|
+
### Subscription Change Inquiry — `POST /api/v1/subscription/change/inquiry`
|
|
276
|
+
|
|
277
|
+
**Request** (`SubscriptionChangeInquiryRequest`):
|
|
278
|
+
- `originSubscriptionRequest`: string (required) — max 32
|
|
279
|
+
- `subscriptionRequest`: string (required) — max 32
|
|
280
|
+
|
|
281
|
+
**Response** (`SubscriptionChangeInquiryResponse`): mirrors change request fields plus status — see openapi.json for full field list.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 4. Config Module
|
|
286
|
+
|
|
287
|
+
### Merchant Config Inquiry — `POST /api/v1/merchantconfig/inquiry`
|
|
288
|
+
|
|
289
|
+
**Request**: `merchantId`: string (required) — max 64
|
|
290
|
+
|
|
291
|
+
**Response** (`AcqMerchantConfigInquiryResponse`):
|
|
292
|
+
- `merchantId`: string (required)
|
|
293
|
+
- `totalDailyLimit`: string — JSON `{"currency":"value"}`
|
|
294
|
+
- `remainingDailyLimit`: string — JSON
|
|
295
|
+
- `transactionLimit`: string — JSON
|
|
296
|
+
|
|
297
|
+
### Pay Method Config Inquiry — `POST /api/v1/paymethodconfig/inquiry`
|
|
298
|
+
|
|
299
|
+
**Request**: `merchantId`: string (required) — max 64
|
|
300
|
+
|
|
301
|
+
**Response** (`PayMethodConfigInquiryResponse`):
|
|
302
|
+
- `merchantId`: string (required)
|
|
303
|
+
- `payMethodDetails`: PayMethodDetail[] (required)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## 5. Shared Schemas
|
|
308
|
+
|
|
309
|
+
### MerchantInfo
|
|
310
|
+
- `merchantId`: string (required) — max 64
|
|
311
|
+
- `subMerchantId`: string — max 64
|
|
312
|
+
|
|
313
|
+
### UserInfo (Subscription)
|
|
314
|
+
- `userId`: string (required) — max 64
|
|
315
|
+
- `userEmail`: string (required) — max 64
|
|
316
|
+
- `userPhone`: string — max 16
|
|
317
|
+
- `userFirstName`: string — max 64
|
|
318
|
+
- `userLastName`: string — max 64
|
|
319
|
+
- `userCreatedAt`: string — max 24
|
|
320
|
+
|
|
321
|
+
### OrderUserInfo (`AcqOrderMerchantUserInfo`)
|
|
322
|
+
- `userId`: string (required) — max 64
|
|
323
|
+
- `userEmail`: string (required) — max 64
|
|
324
|
+
- `userTerminal`: string (required) — "WEB" | "APP" | "IN_WALLET_APP" | "IN_MINI_PROGRAM", max 32
|
|
325
|
+
- `userPhone`: string — max 30
|
|
326
|
+
- `userCountryCode`: string — max 3
|
|
327
|
+
- `userFirstName`: string — max 64
|
|
328
|
+
- `userLastName`: string — max 64
|
|
329
|
+
- `userBrowserIp`: string — max 128, required for direct card
|
|
330
|
+
- `userAgent`: string — max 256, required for direct card
|
|
331
|
+
- `userCreatedAt`: string
|
|
332
|
+
- `userReceiptUrl`: string — read-only in inquiry
|
|
333
|
+
|
|
334
|
+
### ProductInfo (Subscription)
|
|
335
|
+
- `description`: string (required) — max 128
|
|
336
|
+
- `periodType`: string (required) — "DAILY" | "WEEKLY" | "MONTHLY", max 12
|
|
337
|
+
- `periodInterval`: string (required) — max 12
|
|
338
|
+
- `numberOfPeriod`: string — max 24
|
|
339
|
+
- `trialPeriodAmount`: string — max 24, must be > 0
|
|
340
|
+
- `numberOfTrialPeriod`: string — max 12
|
|
341
|
+
- `trialPeriodType`: string — "DAILY" | "WEEKLY" | "MONTHLY"
|
|
342
|
+
- `trialPeriodInterval`: string — max 12
|
|
343
|
+
- `startDateTime`: string — max 24 (inquiry response only)
|
|
344
|
+
- `endDateTime`: string — max 24 (inquiry response only)
|
|
345
|
+
- `nextPaymentDateTime`: string — max 24 (inquiry response only)
|
|
346
|
+
- `currentPeriod`: string — max 24 (inquiry response only)
|
|
347
|
+
|
|
348
|
+
### ChangeProductInfo (in productInfoList[])
|
|
349
|
+
Same as ProductInfo but adds:
|
|
350
|
+
- `amount`: string (required) — max 12
|
|
351
|
+
|
|
352
|
+
### PaymentInfo (Subscription)
|
|
353
|
+
- `productName`: string (required) — "SUBSCRIPTION" | "MINI_PROGRAM_SUBSCRIPTION", max 32
|
|
354
|
+
- `payMethodType`: string — "EWALLET" | "CREDITCARD" | "DEBITCARD", max 16
|
|
355
|
+
- `payMethodName`: string (required) — max 24
|
|
356
|
+
- `payMethodProperties`: string — max 256, JSON
|
|
357
|
+
- `payMethodResponse`: string — max 256, read-only
|
|
358
|
+
- `payMethodUserAccountType`: string — "EMAIL" | "PHONE_NO" | "ACCOUNT_ID", max 24
|
|
359
|
+
- `payMethodUserAccountNo`: string — max 64
|
|
360
|
+
- `payMethodPublicUid`: string — max 128
|
|
361
|
+
- `payMethodUserAccessToken`: string — max 128
|
|
362
|
+
|
|
363
|
+
### OrderPaymentInfo (`AcqOrderPaymentInfo`)
|
|
364
|
+
- `productName`: string (required) — "ONE_TIME_PAYMENT" | "DIRECT_PAYMENT", max 32
|
|
365
|
+
- `payMethodType`: string — "EWALLET" | "ONLINE_BANKING" | "DIGITAL_BANKING" | "OTC" | "CREDITCARD" | "DEBITCARD", max 256
|
|
366
|
+
- `payMethodName`: string — max 256
|
|
367
|
+
- `payMethodProperties`: string — max 1024, JSON
|
|
368
|
+
- `payMethodResponse`: string — read-only
|
|
369
|
+
- `userPaymentAccessToken`: string — max 256, for ONE_CLICK_PAYMENT
|
|
370
|
+
- `payMethodUserAccountNo`: string — max 64
|
|
371
|
+
- `payMethodUserAccountType`: string — max 24
|
|
372
|
+
- `payOption`: string — read-only: "BALANCE" | "DEBIT_CARD" | "CREDIT_CARD"
|
|
373
|
+
- `cashierLanguage`: string — max 24, IETF BCP 47
|
|
374
|
+
- `cashierAppearance`: string — JSON theme config
|
|
375
|
+
- `payMethodCountry`: string — max 3
|
|
376
|
+
- `captureMode`: string — max 24
|
|
377
|
+
- `merchantInitiatedMode`: string — "scheduled" | "unscheduled", max 24
|
|
378
|
+
|
|
379
|
+
### GoodsInfo (Subscription)
|
|
380
|
+
- `goodsId`: string
|
|
381
|
+
- `goodsName`: string
|
|
382
|
+
- `goodsCategory`: string
|
|
383
|
+
- `goodsUrl`: string
|
|
384
|
+
- `appName`: string
|
|
385
|
+
- `skuName`: string
|
|
386
|
+
- `goodsUniquePrice`: string
|
|
387
|
+
- `goodsQuantity`: integer
|
|
388
|
+
|
|
389
|
+
### OrderGoodsInfo (`AcqOrderGoodsInfo`)
|
|
390
|
+
- `goodsId`: string — max 128
|
|
391
|
+
- `goodsName`: string (required) — max 64
|
|
392
|
+
- `skuName`: string — max 32
|
|
393
|
+
- `goodsUniquePrice`: string — max 16
|
|
394
|
+
- `goodsQuantity`: integer
|
|
395
|
+
- `goodsCategory`: string — max 32
|
|
396
|
+
- `goodsUrl`: string (required) — max 128
|
|
397
|
+
- `appName`: string (required) — max 32
|
|
398
|
+
|
|
399
|
+
### AddressInfo
|
|
400
|
+
- `address`: string
|
|
401
|
+
- `city`: string
|
|
402
|
+
- `region`: string
|
|
403
|
+
- `postcode`: string
|
|
404
|
+
- `addressCountryCode`: string
|
|
405
|
+
|
|
406
|
+
### CardInfo (`AcqCardInfo`)
|
|
407
|
+
- `cardNumber`: string (required) — 14-24 chars
|
|
408
|
+
- `cardExpiryYear`: integer (required) — 4 digits, min 2024
|
|
409
|
+
- `cardExpiryMonth`: integer (required) — 1-12
|
|
410
|
+
- `cardCvv`: string (required) — 3-4 chars
|
|
411
|
+
- `cardHolderName`: string (required) — max 128
|
|
412
|
+
- `threeDsDecision`: string — "3DS_FORCE" | "3DS_ATTEMPT" | "NO_3DS"
|
|
413
|
+
|
|
414
|
+
### SubscriptionInfo (in Order Inquiry response)
|
|
415
|
+
- `subscriptionId`: string (required)
|
|
416
|
+
- `period`: string (required)
|
|
417
|
+
- `merchantRequest`: string (required)
|
|
418
|
+
- `subscriptionRequest`: string (required)
|
|
419
|
+
|
|
420
|
+
### PaymentDetail (in Subscription Inquiry response)
|
|
421
|
+
- `acquiringOrderId`: string
|
|
422
|
+
- `orderCurrency`: string
|
|
423
|
+
- `orderAmount`: string
|
|
424
|
+
- `orderStatus`: string — "PAY_SUCCESS" | "ORDER_CLOSE"
|
|
425
|
+
- `orderUpdatedAt`: string
|
|
426
|
+
- `period`: string
|
|
427
|
+
|
|
428
|
+
### PayMethodDetail (in PayMethod Config response)
|
|
429
|
+
- `productName`: string (required) — "ONE_TIME_PAYMENT" | "DIRECT_PAYMENT"
|
|
430
|
+
- `payMethodName`: string (required)
|
|
431
|
+
- `country`: string (required)
|
|
432
|
+
- `currentStatus`: string (required) — "1" (available) | "0" (unavailable)
|
|
433
|
+
- `fixedMaintenanceRules`: FixedMaintenanceRule[] (required)
|
|
434
|
+
- `fixedMaintenanceTimezone`: string (required)
|
|
435
|
+
|
|
436
|
+
### RefundOrderUserInfo
|
|
437
|
+
- `userType`: string (required) — "INDIVIDUAL" | "BUSINESS"
|
|
438
|
+
- `userFirstName`: string — max 64
|
|
439
|
+
- `userMiddleName`: string — max 64
|
|
440
|
+
- `userLastName`: string — max 64
|
|
441
|
+
- `nationality`: string — max 3
|
|
442
|
+
- `userEmail`: string — max 64
|
|
443
|
+
- `userPhone`: string — max 16
|
|
444
|
+
- `userBirthDay`: string — max 12
|
|
445
|
+
- `userIDType`: string — max 24
|
|
446
|
+
- `userIDNumber`: string — max 64
|
|
447
|
+
- `userIDIssueDate`: string — max 12, dd/mm/yyyy
|
|
448
|
+
- `userIDExpiryDate`: string — max 12, dd/mm/yyyy
|
|
449
|
+
- `userBankInfo`: RefundOrderUserBankInfo
|
|
450
|
+
|
|
451
|
+
### RefundOrderUserBankInfo
|
|
452
|
+
- `bankAccountNo`: string — max 64
|
|
453
|
+
- `bankCode`: string — max 64
|
|
454
|
+
- `bankName`: string — max 64
|
|
455
|
+
- `bankCity`: string — max 64
|
|
456
|
+
- `bankBranch`: string — max 64
|
|
457
|
+
|
|
458
|
+
### RiskData (Subscription — all required)
|
|
459
|
+
- `userType`: string — "Individual" | "Agent" | "Institution" | "Internal"
|
|
460
|
+
- `userCategory`: string — "Member" | "Non-Member"
|
|
461
|
+
- `userLegalName`: string — max 128
|
|
462
|
+
- `userDisplayName`: string — max 128
|
|
463
|
+
- `userRegistrationIp`: string — max 24
|
|
464
|
+
- `userLastSeenIp`: string — max 24
|
|
465
|
+
- `userIsNew`: string — "Yes" | "No"
|
|
466
|
+
- `userIsFirstPurchase`: string — "Yes" | "No"
|
|
467
|
+
|
|
468
|
+
### OrderRiskData (Order — all optional, same fields as RiskData)
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## 6. Field Name Gotchas
|
|
473
|
+
|
|
474
|
+
| Concept | Order API field | Subscription API field |
|
|
475
|
+
|---------|----------------|----------------------|
|
|
476
|
+
| Currency | `orderCurrency` | `currency` |
|
|
477
|
+
| Amount | `orderAmount` | `amount` |
|
|
478
|
+
| Request time | `orderRequestedAt` | `requestedAt` |
|
|
479
|
+
| Request ID | `paymentRequestId` | `subscriptionRequest` |
|
|
480
|
+
| Waffo ID | `acquiringOrderId` | `subscriptionId` |
|
|
481
|
+
| Merchant ID field | nested in `merchantInfo` | nested in `merchantInfo` (or top-level `merchantId` for cancel) |
|
|
482
|
+
| Redirect URLs | optional | `successRedirectUrl`, `failedRedirectUrl`, `cancelRedirectUrl` all required for create |
|
|
483
|
+
| GoodsInfo required fields | `goodsName`, `goodsUrl`, `appName` | none (all optional) |
|
|
484
|
+
| UserInfo required fields | `userId`, `userEmail`, `userTerminal` | `userId`, `userEmail` |
|
|
485
|
+
| PaymentInfo productName | "ONE_TIME_PAYMENT" / "DIRECT_PAYMENT" | "SUBSCRIPTION" / "MINI_PROGRAM_SUBSCRIPTION" |
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## 7. Status Handling Guide
|
|
490
|
+
|
|
491
|
+
### Order Statuses
|
|
492
|
+
|
|
493
|
+
| Status | Meaning | Recommended Action |
|
|
494
|
+
|--------|---------|-------------------|
|
|
495
|
+
| `PAY_IN_PROGRESS` | Payment processing | Wait for webhook or poll via `order().inquiry()` |
|
|
496
|
+
| `AUTHORIZATION_REQUIRED` | User must complete 3DS or redirect | Redirect user to `orderAction.webUrl` |
|
|
497
|
+
| `AUTHED_WAITING_CAPTURE` | Pre-auth completed, awaiting capture | Call `order().capture()` when ready to settle |
|
|
498
|
+
| `PAY_SUCCESS` | Payment completed | Fulfill the order |
|
|
499
|
+
| `ORDER_CLOSE` | Payment failed or expired | Show failure to user, allow retry with new `paymentRequestId` |
|
|
500
|
+
|
|
501
|
+
### Refund Statuses
|
|
502
|
+
|
|
503
|
+
| Status | Meaning | Recommended Action |
|
|
504
|
+
|--------|---------|-------------------|
|
|
505
|
+
| `REFUND_IN_PROGRESS` | Refund processing | Wait for `REFUND_NOTIFICATION` webhook |
|
|
506
|
+
| `ORDER_FULLY_REFUNDED` | Full refund completed | Update order state, notify user |
|
|
507
|
+
| `ORDER_PARTIALLY_REFUNDED` | Partial refund completed | Update refund balance, allow further refunds |
|
|
508
|
+
| `ORDER_REFUND_FAILED` | Refund rejected | Check `refundFailedReason`, may need manual intervention |
|
|
509
|
+
|
|
510
|
+
### Subscription Statuses
|
|
511
|
+
|
|
512
|
+
| Status | Meaning | Recommended Action |
|
|
513
|
+
|--------|---------|-------------------|
|
|
514
|
+
| `AUTHORIZATION_REQUIRED` | User must complete initial payment | Redirect to `subscriptionAction.webUrl` |
|
|
515
|
+
| `IN_PROGRESS` | Subscription being set up | Wait for webhook or poll via `subscription().inquiry()` |
|
|
516
|
+
| `ACTIVE` | Subscription active and billing | Enable entitlements; `manage()` API available |
|
|
517
|
+
| `CLOSE` | Creation failed or closed | Treat as terminal failure |
|
|
518
|
+
| `MERCHANT_CANCELLED` | Merchant initiated cancellation | Disable renewal, keep access until period end |
|
|
519
|
+
| `USER_CANCELLED` | User cancelled via management page | Disable renewal, keep access until period end |
|
|
520
|
+
| `CHANNEL_CANCELLED` | Payment channel cancelled (e.g. card expired) | Notify user, prompt to update payment method |
|
|
521
|
+
| `EXPIRED` | All billing periods completed | Remove entitlements |
|
|
522
|
+
|
|
523
|
+
### Subscription Change Statuses
|
|
524
|
+
|
|
525
|
+
| Status | Meaning | Recommended Action |
|
|
526
|
+
|--------|---------|-------------------|
|
|
527
|
+
| `IN_PROGRESS` | Change processing | Keep current plan active until confirmed |
|
|
528
|
+
| `AUTHORIZATION_REQUIRED` | User must authorize new payment | Redirect to `subscriptionAction.webUrl` |
|
|
529
|
+
| `SUCCESS` | Plan change completed | Activate new plan, deactivate old |
|
|
530
|
+
| `CLOSED` | Change failed | Keep original plan unchanged |
|
|
531
|
+
|
|
532
|
+
### Unknown Status / Timeout Handling
|
|
533
|
+
|
|
534
|
+
When an API call times out or returns a network error on a **write operation** (create, refund, cancel):
|
|
535
|
+
|
|
536
|
+
1. **Do NOT treat it as failure** — the operation may have succeeded server-side
|
|
537
|
+
2. **Do NOT retry with a new request ID** — this would create a duplicate operation
|
|
538
|
+
3. **Query the status** — use the corresponding inquiry API with the same request ID
|
|
539
|
+
4. **Trust the webhook** — if a webhook arrives before you query, it is the source of truth
|