# FLPAY Merchant Payment Interface ### Revision History | Version | Date | Remarks | | -------- | -------- | -------- | | 0.1.1 | 2023/09/14 | Add customerName and email parameters of request body. | | 0.1.0 | 2023/08/09 | Add signature.<br>Add callbackURL parameters of request body. | | 0.0.3 | 2023/07/28 | Add redirectUrl and channelCode parameters to the request body. | | 0.0.2 | 2023/06/21 | Add the error attribute to the response body. | ### 0. Preparation work before integration. - Applying for a HashKey and HashIV - Provide a call back URL for transaction result notification. ### 1. Obtain Check-out address <table> <tbody> <tr> <td>URL</td> <td>/payment.php</td> </tr> <tr> <td>Content Type</td> <td>application/json</td> </tr> <tr> <td>Request Method</td> <td>POST</td> </tr> </tbody> </table> #### 1.1 Header | Header | Required | Description | Sample Value | | -------- | -------- | -------- | -------- | | Signature | Yes | A digital signature for an API document is like a virtual fingerprint that proves the document is real, hasn't been altered, and can be trusted. Note: For signature creation please refer in this section [3.1 Create signature](https://hackmd.io/@FlPay/SyYTjvhC2#3-Signature) | algorithm=SHA256withRSA,signature=*** | | Request-Time | Yes | equest time refers to the timestamp indicating the exact moment when a request is made or initiated. | 2023-08-06T08:08:08+08:00 | | Content-Type | No | Content type refers to the format of data being transmitted over a network. | application/json; charset=UTF-8 | ##### 1.1.1 Signature The signature that is generated in [3.1 Create signature](https://hackmd.io/@FlPay/SyYTjvhC2#3-Signature) Example: ``` Sinature:algorithm=SHA256withRSA,signature=mzk5bMMZcpDC3NI3lTaHtxS2s1IC22lv5oqeU%2BFxudA%2BhrGgQQ0oeSzXKUC7W7DLWkwf7rLDBSrXI73eAIfBBb0eiLlDcZaT59PGzoxXOcFaaVxaWAFPi0Z3UVqzkWa6AxoWwgrwyvxZHNT0Mq3gqqH%2Fs%2BpQYNDfMGtx8wmMdLVb3%2Fk8GCLnb1VzZGkeUcwxErnmKzHyTRJLQij5GSIb2TTXgNBn9m06ECO63hSIBYUjWpfXUKq2dZMybAUsfKqWMvul%2B80Xm4UgmvQ73Qqgl6sCdaJTrLpnIVpSqM1R7SgRIQwVOUQUzvvUxwat5Q%2F2GoFYzzo7GH0MDdj3Xf9n4Q%3D%3D ``` ##### 1.1.2 Content-Type Content-Type indicates the media type of the body of the request, as defined by RFC2616. In which, charset is used for generating/validating the signature. Example: ``` Content-Type:application/json;charset=UTF-8 ``` ##### 1.1.3 Request-Time The time when the request is sent is specified in ISO8601 format, which provides a standardized representation of the date and time. Note: This field must be at least accurate to seconds. Example: ``` Request-Time:2023-08-06T08:08:08+08:00 ``` #### 1.2 Request Body | Parameter | Datatype | Required | Description | | -------- | -------- | -------- | -------- | | hashKey | String | Yes |Unique HashKey generated by merchant | | hashIV | String | Yes |Unique HashIV generated by merchant | | amount | String | Yes |Transaction amount<br>(Please keep 2 decimal places) | | merTradeID | String | Yes |Unique ID generated by merchant | | customerName | String | Yes |Payer's Name | | email | String | Yes |Payer's Email | | merProductID | String | No |Product ID purchased by the user. | | merUserID | String | No |User ID of the purchaser | | remark | String | No |Order Remarks | | redirectUrl | String | No |redirect url | | channelCode | String | No |channel code | | callbackURL | String | No |URL invoked by the system during notifications. | #### 1.3 Response Body | Parameter | Datatype | Description | | -------- | -------- | -------- | | code | Integer | Indicates the request result, values are:<br> 200 = Success<br> 403 Wrong request<br> 500 = Abnormal request| | message | String | Result message that describes the result code in details | | url | String | Indicates the url for FLPAY Check-out | | paymentID | String | Unique ID generated by FLPAY | | merTradeID | String | Merchant payment ID | | error | ErrorData | The response contains error code and error message when error occurred. | #### 1.4 ErrorData | Code | Message | | -------- | -------- | | 9180002 | The data for HashKey or HashIV is incorrect. | | 9180011 | Total amount of receipts exceeding today's limit.| #### 1.5 Sample Data ##### 1.5.1 Request Body ```json { "hashKey": "9DLNS8QLSTBJCS47TSA6CQ", "hashIV": "9PH48MEL7B4HUMK7P6WKN", "amount": 2000, "merTradeID": "trade1688", "remark": "some content" } ``` ##### 1.5.2 Response Body Successful Response ```json { "code": 200, "message": "Success", "url": "https://merchant-h5.eponwallet.ph/dist/pay/eco/947d0256d0a2418fbc7f64fd32123e4", "paymentID": "23062015583899735754", "merTradeID": "merTradeID", "error": null } ``` Error Response ```json { "code": 403, "message": null, "url": null, "paymentID": null, "merTradeID": "merTradeID", "error": { "code": 9180002, "message": "The data for Key is incorrect." } } ``` #### 1.6 Channel Code | Channel Name | Code | | -------- | -------- | | BDO | 53 | | UnionBank | 55 | | Security Bank | 56 | | GCash | 57 | | GrabPay | 58 | | WebPay | 77 | | ShopeePay | 107 | ### 2. Notification The notification API is used to notify the merchant of the payment result. #### 2.1 Request Header | Header | Required | Description | Sample Value | | -------- | -------- | -------- | -------- | | Signature | Yes | A digital signature for an API document is like a virtual fingerprint that proves the document is real, hasn't been altered, and can be trusted. Note: For signature creation please refer in this section [3.1 Create signature](https://hackmd.io/@FlPay/SyYTjvhC2#3-Signature) | algorithm=SHA256withRSA,signature=*** | | Request-Time | Yes | equest time refers to the timestamp indicating the exact moment when a request is made or initiated. | 2023-08-06T08:08:08+08:00 | | Content-Type | No | Content type refers to the format of data being transmitted over a network. | application/json; charset=UTF-8 | Note: For the header details, please check [Verify a Signature](https://hackmd.io/@FlPay/SyYTjvhC2#32-Verifying-a-Signature) | Request Method | Content-Type | | -------- | -------- | | POST | application/json | #### 2.2 Request Body | Parameter | Datatype | Required | Description | | -------- | -------- | -------- | -------- | | RtnCode | String | Yes | Indicates the payment result, values are:<br>1 = Success<br>200 request success, but payment failed<br>403 Wrong request<br> 500 = Abnormal request | | RtnMessage | String | Yes | Result message that describes the result code in details | | MerTradeID | String | Yes | Indicates the Unique ID created by the merchant as their reference number | | MerProductID | String | No | Product ID purchased by the user. | | MerUserID | String | No | User ID of the purchaser | | Amount | BigDecimal | Yes | Transaction amount | | TransactionDate | Text | Yes | Transaction date | | PaymentDate | Text | No | Payment date | | Fee | Text | No | Payment transaction fee | | Status | Text | No | Payment status, values are:<br>Payment successful<br>Payment failed | #### 2.3 Response | Parameter | Datatype | Description | | -------- | -------- | -------- | | resultStatus | String | Result Status. Example:<br> SUCCESS<br>FAILED | #### 2.4 Sample Data ##### 2.4.1 Response Body ```json { "resultStatus": "SUCCESS" } ``` ### 3. Signature #### 3.1 Create Signature To generate the signature, utilize the SHA256withRSA method with the appropriate algorithm and private key. This process involves applying the SHA-256 hashing algorithm to the data and then encrypting it using the private key associated with RSA. ##### 3.1.1 Procedure Here are the steps to generate and add a signature to a request using the provided privateKey: 1. Acquire your private key, referred to as privateKey, which will be used for request signing. 2. Prepare the content that needs to be signed, denoted as Content_To_Be_Signed. 3. Calculate and generate the signature using the privateKey and Content_To_Be_Signed. 4. Include the generated signature in the request header. 5. Refer to the examples below for a detailed breakdown of each step. ##### 3.1.2 Example **1. Obtain your private key to sign the request** Prepare your private key, which will be utilized to generate the signature at a later stage. **2. Syntax of content to be signed** HTTP_METHOD<space>HTTP_URI<space>Request-Time<dot>HTTP_BODY For instance, let's consider a request with the following properties: | HTTP_METHOD | HTTP_URI | REQUEST_TIME | HTTP_BODY | | -------- | -------- | -------- | -------- | | POST | /payment.php | 2023-08-06T08:08:08+08:00 | The body is formatted in the following structure: {<br>"hashKey": "3YKL97TSA6CQ",<br> "hashIV": "VEXJ9P7P6WKN",<br> "amount": 2000,<br> "merTradeID": "trade1688",<br> "remark": "some content"<br>} | By complying with the Syntax of Content to be signed, the content to be signed is created as follows: ```json POST /payment.php 2023-08-06T08:08:08+08:00.{ "hashKey": "9DLNS8QLSTBJCS47TSA6CQ", "hashIV": "9PH48MEL7B4HUMK7P6WKN", "amount": 2000, "merTradeID": "trade1688", "remark": "some content" } ``` **3. Syntax of Content to be Signed** ``` HTTP_METHOD<space>HTTP_URI<space>Request-Time<dot>HTTP_BODY ``` **4. Calculate and generate the signature** To calculate and generate the signature using the proper algorithm and private key, employ the SHA256withRSA method. This method utilizes the SHA-256 hashing algorithm in combination with the RSA encryption scheme, leveraging the private key for signing the data and producing the signatur ``` generatedSignature=base64UrlEncode(sha256withrsa(<Content_To_Be_Signed>), <privateKey>) ``` **Content_To_Be_Signed**: The content to be signed, obtained in step 2, refers to the data that needs to be included when generating the signature. **privateKey** : The private key value obtained in step 1 refers to the confidential key used in the signature generation process. **sha256withrsa** : The specified algorithm to use is SHA256withRSA. For example, the generated signature generatedSignature looks as follows ``` mzk5bMMZcpDC3NI3lTaHtxS2s1IC22lv5oqeU%2BFxudA%2BhrGgQQ0oeSzXKUC7W7DLWkwf7rLDBSrXI73eAIfB Bb0eiLlDcZaT59PGzoxXOcFaaVxaWAFPi0Z3UVqzkWa6AxoWwgrwyvxZHNT0Mq3gqqH%2Fs%2BpQYNDfMGtx8wmM dLVb3%2Fk8GCLnb1VzZGkeUcwxErnmKzHyTRJLQij5GSIb2TTXgNBn9m06ECO63hSIBYUjWpfXUKq2dZMybAUsfK qWMvul%2B80Xm4UgmvQ73Qqgl6sCdaJTrLpnIVpSqM1R7SgRIQwVOUQUzvvUxwat5Q%2F2GoFYzzo7GH0MDdj3Xf 9n4Q%3D%3D ``` **5. Add the generated signature to the request header** Assemble a signature string as the following syntax. ``` 'Signature: algorithm=<algorithm>,signature=<generatedSignature>' ``` generatedSignature : the signature that is generated in step 4 **6. Send a request** Construct a request by adding the Request-Time, and Signature fields to the request header. After a request is constructed, you can use common tools, like cURL or Postman to send the request. In the following example, cURL is used. ``` curl -X POST\ -H "Content-Type: application/json"\ -H "Request-Time: 2023-08-06T08:08:08+08:00"\ -H "Signature: algorithm=SHA256withRSA,signature=mzk5bMMZcpDC3NI3lTaHtxS2s1IC22lv5oqeU%2BFxudA%2BhrGgQQ0oeSzXKUC7W7DLWkwf7rLDBSrXI73eAIfBBb0eiLlDcZaT59PGzoxXOcFaaVxaWAFPi0Z3UVqzkWa6AxoWwgrwyvxZHNT0Mq3gqqH%2Fs%2BpQYNDfMGtx8wmMdLVb3%2Fk8GCLnb1VzZGkeUcwxErnmKzHyTRJLQij5GSIb2TTXgNBn9m06ECO63hSIBYUjWpfXUKq2dZMybAUsfKqWMvul%2B80Xm4UgmvQ73Qqgl6sCdaJTrLpnIVpSqM1R7SgRIQwVOUQUzvvUxwat5Q%2F2GoFYzzo7GH0MDdj3Xf9n4Q%3D%3D"\ -d'{ "hashKey": "9DLNS8QLSTBJCS47TSA6CQ", "hashIV": "9PH48MEL7B4HUMK7P6WKN", "amount": 2000, "merTradeID": "trade1688", "remark": "some content" }' ``` **7. Signed Sample** ```php $requestTime = '2023-08-22T16:59:45+08:00'; $bodyData = '{ "hashKey": "QHIEK32QAXH6GQPYRQMP8DT", "hashIV": "PIQ89ADZN7GHLWHBGQ8PMEP6S", "amount": 100, "merTradeID": "FLPAY1234567890", "remark": "FLPAY1234567890" }'; $aclSignData = 'POST /payment.php '.$requestTime.'.'.$bodyData; // 取得簽章 $aclSignature = getSign($aclSignData, $pkcs8PrivateKey); $aclSignature = urlencode($aclSignature); function getSign($content, $privateKey) { $key = openssl_get_privatekey($privateKey); openssl_sign($content, $signature, $key, OPENSSL_ALGO_SHA256); $sign = base64_encode($signature); return $sign; } ``` #### 3.2 Verifying a Signature Once a response is received, the merchant have the option to verify the signature of the response. This involves validating both the response headers and the response body for authenticity and integrity. The response header sample: | HTTP_METHOD | REQUEST_TIME | SIGNATURE | | -------- | -------- | -------- | | POST | 2023-08-06T08:08:08+08:00 | algorithm=SHA256withRSA,signature=mzk5bMMZcpDC3NI3lTaHtxS2s1IC22lv5oqeU%2BFxudA%2BhrGgQQ0oeSzXKUC7W7DLWkwf7rLDBSrXI73eAIfBBb0eiLlDcZaT59PGzoxXOcFaaVxaWAFPi0Z3UVqzkWa6AxoWwgrwyvxZHNT0Mq3gqqH%2Fs%2BpQYNDfMGtx8wmMdLVb3%2Fk8GCLnb1VzZGkeUcwxErnmKzHyTRJLQij5GSIb2TTXgNBn9m06ECO63hSIBYUjWpfXUKq2dZMybAUsfKqWMvul%2B80Xm4UgmvQ73Qqgl6sCdaJTrLpnIVpSqM1R7SgRIQwVOUQUzvvUxwat5Q%2F2GoFYzzo7GH0MDdj3Xf9n4Q%3D%3D | ##### 3.2.1 Validate a Sinature Here are the steps to validate the signature of the response: 1. Acquire the platform's public key. 2. Prepare the content to be validated, denoted as Content_To_Be_Validated. 3. Retrieve the signature from the response header. 4. Perform the signature validation process to verify the authenticity and integrity of the response.For details of each step, see the following examples. ##### 3.2.2 Example **1. Obtain the platform public key** The serverPublicKey properties can be obtained from the response header. **2. Construct the content to be validated** To construct the content to be validated, adhering to the Syntax of Content to be Validated, use the provided response body sample in the following manner: ``` POST /payment/notify 2023-08-06T08:08:08+08:00.{ "RtnCode":"1", "RtnMessage":"Success", "MerTradeID":"mt1690911905402", "MerProductID":"pid98372984", "MerUserID":"user298342", "Amount":"100", "TransactionDate":"2023-08-06 14:38:32", "PaymentDate":null, "Fee":"1", "Status":"Payment successful" } ``` **3. Syntax of Content_To_Be_Validate** ``` HTTP_METHOD<space>HTTP_URI<space>Request-Time<dot>HTTP_BODY ``` **REQUEST_TIME**: The response timestamp, adhering to the ISO8601 standard, indicates the exact time when the response is returned. It is important to note that this field must be accurate up to milliseconds. You can obtain this timestamp from the response header, providing precise timing information for further processing or analysis. **HTTP_BODY**: The data body of the response refers to the content or payload that is included in the response. It contains the relevant information or data that is being returned as part of the response to fulfill the request. This data body provides the actual response content that can be processed or utilized by the recipient of the response. **HTTP_METHOD**: HTTP method is a type of request method used in web communications to indicate the desired action to be performed on a resource. **HTTP_URI**: is a string of characters that identifies a resource on the web. **4. Get the Signature from the response header** The target signature string, denoted as target_signature, is obtained from the Signature header of the response. This signature header contains the specific information required for signature validation. ``` Signature: algorithm=SHA256withRSA,signature=<target_signature> ``` **5. Validate Signature** To validate the signature of a response, utilize the sha256withrsa_verify method. This method employs the SHA-256 hashing algorithm in combination with the RSA encryption scheme to verify the authenticity and integrity of the signature. By applying this verification method, you can ensure the validity and integrity of the received response. Syntax of the sha256withrsa_verify method: ``` sha256withrsa_verify(base64UrlDecode(<target_signature>),<Content_To_be_Validated>,<serverPublicKey>) ``` **target_signature** : The extracted signature from the response header, acquired in step 4, is used for signature validation. This signature is a cryptographic representation of the response's integrity and authenticity. By validating this extracted signature, you can verify that the response has not been tampered with and originated from the expected source. **Content_To_Be_Validated** : The content to be validated, which is created in step 2, is used for signature verification. This content is constructed based on a specific syntax or structure and includes the relevant data or information from the response. By validating this content, you can ensure that the response has not been altered and matches the expected data integrity. **serverPublicKey** : The platform's public key, obtained in step 1, is used for signature validation. This public key is provided by the platform and is used to verify the signature of the response. By utilizing the platform's public key, you can verify the authenticity and integrity of the response, ensuring that it was indeed generated by the expected platform