Project

General

Profile

BBL Integration » History » Version 1

Ryan Supawarapong, 03/31/2026 10:10 AM

1 1 Ryan Supawarapong
# BBL Integration
2
3
Detail for API on BBL integration.
4
5
- [API Payment](#API-Payment)
6
- [ThaiQR](#ThaiQR)
7
8
## API Payment
9
10
### Module Summary
11
12
| Item | Value |
13
|---|---|
14
| Base path | `/api/v1/bank/apipayment` |
15
| Purpose | Receiver lookup, transfer confirmation, and post-transfer inquiry for BBL account, other-bank account, and PromptPay flows |
16
| Inbound content type | `application/json` |
17
| Inbound auth | None at route layer |
18
| Outbound auth to BBL | Internal only: Basic Auth + RSA signature |
19
| Local transaction type | `API_PAYMENT` |
20
| Supported `paymentType` | `BBL`, `OTH`, `PP` |
21
| Supported `receiverType` | `BANKAC`, `NATID`, `MSISDN` |
22
| Upstream `transType` | `CASHLESS` |
23
24
### Endpoint Matrix
25
26
| Method | Path | Upstream BBL `transCode` | Purpose | Local side effects |
27
|---|---|---|---|---|
28
| `POST` | `/validation` | `LOOKUP_AC`, `LOOKUP_OTH_AC`, `LOOKUP_PP` | Validate receiver and create a local transaction | Inserts `apipayments` + `transactions`; status becomes `1100` or `2000` |
29
| `POST` | `/confirm` | `TRANSFER_AC`, `TRANSFER_OTH_AC`, `TRANSFER_PP` | Execute transfer using a prior `lookupRef` | Marks local transaction `5000`; updates API Payment transmit time and transaction code |
30
| `GET` | `/inquiry/:transactionID` | `INQUIRY` | Query transfer result using local transaction ID | Updates stored BBL reference number on the API Payment record |
31
32
### `POST /validation` Request Contract
33
34
| Field | Type | Required | Constraints | Notes |
35
|---|---|---|---|---|
36
| `receiverValue` | `string` | Yes | Non-empty | Receiver account / PromptPay target |
37
| `receiverType` | `string` | Yes | `BANKAC`, `NATID`, `MSISDN` | `PP` flow only allows `NATID` or `MSISDN` |
38
| `receiverBankCode` | `string` | Conditional | Length must be `3` for `paymentType=OTH` | Ignored for `BBL`; internally forced to `002` |
39
| `paymentType` | `string` | Yes | `BBL`, `OTH`, `PP` | Selects lookup / confirm flow |
40
| `amount` | `float64` | Yes | Positive amount expected | Used in downstream lookup |
41
| `additionalRef` | `string` | No | None | Passed through to BBL where applicable |
42
| `customerCode` | `int` | Yes | Must map to existing customer data | Used to compare stored customer name vs BBL receiver name |
43
44
### `POST /validation` Success Response
45
46
| Field | Type | Description |
47
|---|---|---|
48
| `responseCode` | `string` | BBL/business result code |
49
| `responseMesg` | `string` | Human-readable message |
50
| `lookupRef` | `string` | BBL lookup reference, required for `/confirm` |
51
| `receiverName` | `string` | Receiver name returned by BBL |
52
| `requestRef` | `string` | BBL request reference generated by this service |
53
| `transactionID` | `string` | Local `transactions.id` generated by this service |
54
| `storedFullname` | `string` | Uppercased full name loaded from local customer data |
55
| `customerNameMatch` | `bool` | `true` when `storedFullname == receiverName` |
56
57
### `POST /confirm` Request Contract
58
59
| Field | Type | Required | Constraints | Notes |
60
|---|---|---|---|---|
61
| `receiverValue` | `string` | Yes | Non-empty | Same logical receiver as in validation |
62
| `receiverType` | `string` | Yes | `BANKAC`, `NATID`, `MSISDN` | `PP` flow only allows `NATID` or `MSISDN` |
63
| `receiverBankCode` | `string` | Conditional | Length must be `3` for `paymentType=OTH` | `BBL` flow internally uses `002` |
64
| `paymentType` | `string` | Yes | `BBL`, `OTH`, `PP` | Must match the intended transfer flow |
65
| `amount` | `float64` | Yes | Positive amount expected | Passed to BBL confirm call |
66
| `additionalRef` | `string` | No | None | Optional pass-through |
67
| `smsMobileNo` | `string` | No | None | Only forwarded in PromptPay confirm flow |
68
| `smsLanguage` | `string` | No | None | Only forwarded in PromptPay confirm flow |
69
| `lookupRef` | `string` | Yes | Non-empty | Must come from `/validation` response |
70
| `origRequestRef` | `string` | Yes | Non-empty | Must be the `requestRef` from `/validation`, not the local `transactionID` |
71
72
### `POST /confirm` Success Response
73
74
| Field | Type | Description |
75
|---|---|---|
76
| `responseCode` | `string` | BBL/business result code |
77
| `responseMesg` | `string` | Human-readable message |
78
| `transactionID` | `string` | Local `transactions.id` resolved from `origRequestRef` |
79
| `customerID` | `int` | Local customer ID from the transaction |
80
| `bankRefNo` | `string` | BBL bank transfer reference number |
81
82
### `GET /inquiry/:transactionID` Request Contract
83
84
| Item | Type | Required | Notes |
85
|---|---|---|---|
86
| `transactionID` | `path param` | Yes | Local `transactions.id`, not BBL reference |
87
88
### `GET /inquiry/:transactionID` Success Response
89
90
| Field | Type | Description |
91
|---|---|---|
92
| `responseCode` | `string` | BBL/business result code |
93
| `responseMesg` | `string` | Human-readable message |
94
| `transactionID` | `string` | Local transaction ID |
95
| `customerID` | `int` | Local customer ID |
96
| `inqRspCode` | `string` | BBL inquiry response code |
97
| `inqRspMesg` | `string` | BBL inquiry response message |
98
| `origRequestRef` | `string` | Original BBL request reference used in confirm |
99
| `origTransDateTime` | `string` | Original transmit time used in confirm |
100
| `bankRefNo` | `string` | BBL bank reference number |
101
102
### API Payment Status Lifecycle
103
104
| Event | Local status |
105
|---|---|
106
| Validation success and stored customer name matches BBL receiver name | `1100` (`VerifyStatus`) |
107
| Validation success but stored customer name does not match BBL receiver name | `2000` (`WaitingApprovalStatus`) |
108
| Confirm success | `5000` (`CompleteStatus`) |
109
110
### API Payment Implementation Notes
111
112
| Topic | Detail |
113
|---|---|
114
| Route prefix | The actual route prefix is `/api/v1/bank/apipayment`; it does not include `/bbl` |
115
| Error handling | Handler returns HTTP `400` with `{"error":"..."}` on bind, validation, or usecase failures |
116
| Name matching | Validation compares BBL `receiverName` with locally stored `EN_NAME + EN_SURNAME`; mismatch does not fail validation, but changes local status to waiting approval |
117
| Inquiry input model | Inquiry reconstructs the outbound BBL payload from DB state; the caller only supplies local `transactionID` |
118
119
---
120
121
## ThaiQR
122
123
### Module Summary
124
125
| Item | Value |
126
|---|---|
127
| Base path | `/api/v1/bank/bbl/thaiqr` |
128
| Purpose | Generate ThaiQR payloads, receive BBL callbacks, query payment status, and refund completed ThaiQR transactions |
129
| Inbound content type | `application/json` |
130
| Local transaction type | `ThaiQR` |
131
| OAuth model | Local `GET /access-token` fetches BBL token; caller then passes that token payload back into `POST /inquiry/:transactionID` and `POST /refund/:transactionID` |
132
| Callback auth | JWT signature in `Signature` header |
133
| Outbound auth to BBL | Bearer token + RSA/JWT signature |
134
| Primary local lifecycle | `1000` pending -> `1100` verified -> `5000` complete |
135
136
### Endpoint Matrix
137
138
| Method | Path | Purpose | Local side effects |
139
|---|---|---|---|
140
| `GET` | `/access-token` | Fetch BBL OAuth access token | None |
141
| `POST` | `/generate-qr` | Create local pending ThaiQR transaction and generate QR string | Inserts `thaiqr` + `transactions`; status becomes `1000` |
142
| `POST` | `/verify` | Receive BBL verification callback | Updates ThaiQR transaction date/time; status becomes `1100` |
143
| `POST` | `/noti` | Receive final BBL payment notification callback | Updates ThaiQR payment metadata; status becomes `5000` |
144
| `POST` | `/inquiry/:transactionID` | Query BBL for ThaiQR payment result using local transaction ID | None locally besides read-side lookup |
145
| `POST` | `/refund/:transactionID` | Refund a completed ThaiQR transaction | Inserts refund transaction and updates refund status fields |
146
147
### `GET /access-token` Contract
148
149
| Item | Value |
150
|---|---|
151
| Request body | None |
152
| Local method | `GET` |
153
| Upstream method | `POST` with `application/x-www-form-urlencoded` |
154
| Upstream grant type | `client_credentials` |
155
| Upstream extra form field | `expireIn=86399` |
156
157
### `GET /access-token` Success Response
158
159
| Field | Type | Description |
160
|---|---|---|
161
| `accessToken` | `string` | OAuth bearer token for ThaiQR inquiry/refund |
162
| `expiresIn` | `string` | Token TTL from BBL |
163
| `scope` | `string` | Granted scope |
164
165
### `POST /generate-qr` Request Contract
166
167
| Field | Type | Required | Constraints | Notes |
168
|---|---|---|---|---|
169
| `transactionAmount` | `float64` | Yes | `<= 9999999999999.99` | Amount encoded into QR and stored in DB |
170
| `customerId` | `string` | Yes | Must parse to integer | Used as local transaction customer ID |
171
172
### `POST /generate-qr` Success Response
173
174
| Field | Type | Description |
175
|---|---|---|
176
| `status` | `string` | Common response wrapper status, expected `success` |
177
| `data.qr.qrCode` | `string` | Generated EMV ThaiQR payload |
178
| `data.qr.billerId` | `string` | Biller ID + suffix used in the QR |
179
| `data.qr.reference1` | `string` | Generated reference 1 |
180
| `data.qr.reference2` | `string` | Generated reference 2 |
181
182
### ThaiQR Callback Contract
183
184
| Method | Path | Required headers | Request body | Success response | Local side effects |
185
|---|---|---|---|---|---|
186
| `POST` | `/verify` | `Signature`, `Request-Ref` | `billerId`, `amount`, `transDate`, `transTime`, `reference1`, `reference2`, `reference3` | `responseCode="000"`, `responseMesg="Success"` plus response headers `Request-Ref`, `Signature`, `Transmit-Date-Time` | Verifies JWT signature, updates ThaiQR date/time, sets status `1100` |
187
| `POST` | `/noti` | `Signature`, `Request-Ref` | `type`, and `data.{billerId, amount, transDate, transTime, termType, fromBank, fromName, retryFlag, approvalCode, bankRef, reference1, reference2, reference3}` | `responseCode="000"`, `responseMesg="Success"` plus response headers `Request-Ref`, `Signature`, `Transmit-Date-Time` | Verifies JWT signature, updates bank/payment metadata, sets status `5000` |
188
189
### `POST /inquiry/:transactionID` Request Contract
190
191
| Item | Type | Required | Notes |
192
|---|---|---|---|
193
| `transactionID` | `path param` | Yes | Local `transactions.id` |
194
| `accessToken` | `string` | Yes | Passed in request body using `AccessTokenResponse` shape |
195
| `expiresIn` | `string` | No | Bound but not required by business logic |
196
| `scope` | `string` | No | Bound but not required by business logic |
197
198
### `POST /inquiry/:transactionID` Success Response
199
200
| Field | Type | Description |
201
|---|---|---|
202
| `responseCode` | `string` | BBL/business result code |
203
| `responseMesg` | `string` | Human-readable message |
204
| `data.billerId` | `string` | Biller ID |
205
| `data.transDate` | `string` | Payment date |
206
| `data.transTime` | `string` | Payment time |
207
| `data.termType` | `string` | Terminal type |
208
| `data.amount` | `string` | Paid amount |
209
| `data.reference1` | `string` | ThaiQR reference 1 |
210
| `data.reference2` | `string` | ThaiQR reference 2 |
211
| `data.reference3` | `string` | ThaiQR reference 3 |
212
| `data.fromBank` | `string` | Payer bank code |
213
| `data.fromName` | `string` | Payer display name |
214
| `data.approvalCode` | `string` | Approval code |
215
216
### `POST /refund/:transactionID` Request Contract
217
218
| Item | Type | Required | Notes |
219
|---|---|---|---|
220
| `transactionID` | `path param` | Yes | Local `transactions.id` |
221
| `accessToken` | `string` | Yes | Passed in request body using `AccessTokenResponse` shape |
222
| `expiresIn` | `string` | No | Bound but not required by business logic |
223
| `scope` | `string` | No | Bound but not required by business logic |
224
225
### `POST /refund/:transactionID` Success Response
226
227
| Field | Type | Description |
228
|---|---|---|
229
| `responseCode` | `string` | Expected `000` on success |
230
| `responseMesg` | `string` | Expected `Success` on success |
231
232
### ThaiQR Refund Preconditions and Lifecycle
233
234
| Step | Rule / Result |
235
|---|---|
236
| Precondition | Target local transaction must already be `5000` (`CompleteStatus`) |
237
| Precondition | Target local transaction must have `refunded=false` |
238
| Refund verification success | Creates refund transaction with status `3100` (`VerifyRefundstatus`) |
239
| Refund verification failure | Creates refund transaction with status `3150` (`VerifyRefundFailStatus`) |
240
| Refund advice success | Updates refund status to `3200` (`AdviceRefundStatus`) and marks original transaction `refunded=true` |
241
| Refund advice failure | Updates refund status to `3250` (`AdviceRefundFailStatus`) |
242
| Refund reversal success | Updates refund status to `3300` (`ReversalRefundStaus`) |
243
| Refund reversal failure | Updates refund status to `3350` (`ReversalRefundFailStaus`) |
244
245
### ThaiQR Implementation Notes
246
247
| Topic | Detail |
248
|---|---|
249
| Route semantics | The actual callback endpoints registered in the router are `/verify` and `/noti` |
250
| Error handling: access token | Normal failures return HTTP `400` with `{"message":"..."}`; connection-reset case is mapped to response code `999` |
251
| Error handling: generate QR | Validation failures return common response with failure status; usecase failures return common error response |
252
| Error handling: verify/noti/refund | Business-level failures still return HTTP `200`, with non-`000` `responseCode` in the response body |
253
| Token handoff | `/inquiry/:transactionID` and `/refund/:transactionID` expect the caller to POST the previously obtained token payload in the request body rather than using an inbound `Authorization` header |
254
| TLS behavior | Current ThaiQR outbound HTTP calls use clients with TLS verification disabled (`InsecureSkipVerify=true`) |
255
256
---
257
258
## Common Identifier Semantics
259
260
| Field | Meaning |
261
|---|---|
262
| `transactionID` | Local `transactions.id` created by this service |
263
| `requestRef` | BBL request reference generated by this service and sent in `Request-Ref` |
264
| `origRequestRef` | Existing `requestRef` from a prior API Payment validation/confirm step |
265
| `lookupRef` | BBL lookup reference returned by API Payment validation |
266
| `bankRefNo` | BBL transfer reference returned in API Payment flows |
267
| `bankRef` | BBL bank reference used in ThaiQR notification data |
268
| `reference1`, `reference2`, `reference3` | ThaiQR merchant/payment references stored in the `thaiqr` record |
269
270
## Common BBL Response Codes Seen in These Flows
271
272
| Code | Meaning |
273
|---|---|
274
| `000` | Success |
275
| `052` | Unknown Biller ID |
276
| `054` | System unavailable |
277
| `209` | Transaction not found |
278
| `210` | Time out |
279
| `211` | Invalid data |
280
| `215` | Invalid token |
281
| `341` | Service not ready |
282
| `888` | Other error |
283
| `999` | Connection reset by peer |