# Phương thức API

### Tài liệu liên quan <a href="#tai-lieu-lien-quan" id="tai-lieu-lien-quan"></a>

* Thông tin kết nối giữa giữ Gotadi và Đối tác.
* Kịch bản kiểm kiểm thử.
* Source code mẫu.

***

### Thuật ngữ và viết tắt <a href="#thuat-ngu-va-viet-tat" id="thuat-ngu-va-viet-tat"></a>

* **URL** `Uniform Resource` *được dùng để tham chiếu tới tài nguyên trên Internet.*
* **SSL** `Secure Sockets Layer` *là các giao thức mật mã được thiết kế để cung cấp truyền thông an toàn qua Internet.*
* **HTTPS** `Hypertext Transfer Protocol Secure` *là một giao thức kết hợp giữa giao thức HTTP và giao thức bảo mật SSL hay TLS cho phép trao đổi thông tin một cách bảo mật trên Internet.*
* **3DES** `Triple DES (3DES hay TDES)` *là một thuật toán khóa đối xứng, áp dụng thuật toán mã hóa DES ba lần cho mỗi khối dữ liệu.*
* **RSA** `Rivest–Shamir–Adleman` *là một thuật toán mật mã hóa khóa công khai. Đây là thuật toán đầu tiên phù hợp với việc tạo ra chữ ký điện tử đồng thời với việc mã hóa.*
* **SHA-256** `Secure Hash Algorithm` *là giải thuật dùng để chuyển một đoạn dữ liệu nhất định thành một đoạn dữ liệu có chiều dài không đổi với xác suất khác biệt cao. SHA-256 (trả lại kết quả dài 256 bit)*
* **Chữ ký điện tử** *Thông tin đi kèm theo dữ liệu (văn bản, hình ảnh, video…) nhằm mục đích xác định người chủ của dữ liệu đó*

***

### Yêu cầu bảo mật <a href="#yeu-cau-bao-mat" id="yeu-cau-bao-mat"></a>

#### 1. Kênh truyền SSL/HTTPS <a href="#id-1-kenh-truyen-sslhttps" id="id-1-kenh-truyen-sslhttps"></a>

SSL/HTTPS được áp dụng để truyền nhận dữ liệu giữa hệ thống của đối tác và Gotadi. Mục đích sử dụng SSL/HTTPS là giúp dữ liệu trao đổi giữa đối tác và Gotadi được mã hóa, khó bị đánh cắp và giả mạo.

#### 2. Header bảo mật và thống kê lưu lượng truyền <a href="#id-2-header-bao-mat-va-thong-ke-luu-luong-truyen" id="id-2-header-bao-mat-va-thong-ke-luu-luong-truyen"></a>

Tất cả các request từ phía đối tác gọi sang hệ thống của Gotadi phải chứa các Headers bên dưới để phục vụ các nghiệp vụ về bảo mật và thống kê số liệu của Gotadi:

Lưu ý

Giá trị `<api_key>` và `<access_code>` do Gotadi cung cấp cho Đối tác.

#### 3. Mã hóa dữ liệu truyền và xác thực chữ ký điện tử <a href="#id-3-ma-hoa-du-lieu-truyen-va-xac-thuc-chu-ky-ien-tu" id="id-3-ma-hoa-du-lieu-truyen-va-xac-thuc-chu-ky-ien-tu"></a>

Request/response giữa Gotadi và Đối tác ở một số API quan trọng được yêu cầu mã hóa bằng thuật toán mã hóa bất đối xứng 3DES và kèm theo chữ ký điện tử để xác thực. Thuật toán mã hóa, giải mã sẽ được mô tả cụ thể trong tài liệu này.

Lưu ý

Các API có yêu cầu mã hóa dữ liệu và kèm theo chữ ký điện tử sẽ được ghi chú ở phần Yêu cầu bảo mật.

**3.1 Mã hóa dữ liệu gửi đi**

**Input** Original data, RSA PublicKey của bên nhận, RSA Private Key của bên gửi

**Output** Encrypted Key, Encrypted Data

<details>

<summary>Bước 1: Khởi tạo khóa ngẫu nhiên (Random key)</summary>

<img src="https://developer.gotadi.com/img/1.png" alt="" data-size="original">

Hàm 3DES Key Generate được dùng để tạo random key dựa theo tiêu chí DESedeKeySpec (Độ dài key: 24 byte). Mỗi request/response sẽ được cấp một random key riêng biệt.

Example:

Java

```
    public static byte[] generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
        SecretKey secretKey = keyGenerator.generateKey();
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
        DESedeKeySpec deSedeKeySpec = (DESedeKeySpec)   secretKeyFactory.getKeySpec(secretKey, DESedeKeySpec.class);
        byte[] randomKey = deSedeKeySpec.getKey();
        return randomKey;
    }
```

</details>

<details>

<summary>Bước 2: Mã hóa khóa ngẫu nhiên (Encrypted random key)</summary>

<img src="https://developer.gotadi.com/img/2.png" alt="" data-size="original">

Random key được tạo ra ở bước 1 sẽ được mã hóa bằng thuật toán mã hóa bất đối xứng RSA bằng **Public key của bên nhận**.

Example:

Java

```
public static String encryptRSA(byte[] randomKey, String xmlPublicKey) throws Exception {
    Cipher cipher = createCipherEncrypt(xmlPublicKey);
    byte[] encryptedKey = cipher.doFinal(randomKey);
    return Base64.encodeBase64URLSafeString(encryptedKey);
}
```

</details>

<details>

<summary>Bước 3: Khởi tạo chữ ký chữ ký điện tử (Signature)</summary>

<img src="https://developer.gotadi.com/img/3.png" alt="" data-size="original">

Bên gửi áp dụng thuật toán **RSA-SHA256** kết hợp với **Private key của chính mình** để ký chữ ký điện tử trên signature data.

Lưu ý

Schema để thành lập signature data sẽ được mô tả cụ thể ở từng API.

Example:

Java

```
public static String signRSA(String signatureData, String xmlPrivateKey) throws Exception {
    PrivateKey privateKey = getPrivateKeyFromXML(xmlPrivateKey);
    Signature instance = Signature.getInstance("SHA256withRSA");
    instance.initSign(privateKey);
    instance.update(signatureData.getBytes("UTF-8"));
    byte[] signature = instance.sign();
    return Base64.encodeBase64String(signature);
}
```

</details>

<details>

<summary>Bước 4: Mã hóa dữ liệu (Encrypted data)</summary>

<img src="https://developer.gotadi.com/img/4.png" alt="" data-size="original">

**Original data có chứa signature** sẽ được mã hóa bằng thuật toán **3DES** với random key đã được tạo ra ở bước trước đó.

Lưu ý

Schema để thành lập original data sẽ được mô tả cụ thể ở từng API.

Example:

Java

```
public static String encryptTripleDes(String originalData, byte[] randomKey) throws Exception {
    Cipher cipher = Cipher.getInstance("DESede");
    SecretKeySpec secretKeySpec = new SecretKeySpec(randomKey, "DESede");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    byte[] encryptedData = cipher.doFinal(originalData.getBytes("UTF-8"));
    return Base64.encodeBase64URLSafeString(encryptedData);
}
```

</details>

**3.2 Giải mã dữ liệu nhận được và xác thực chữ ký điện tử**

**Input** Encrypted Key, Encrypted Data, RSA PrivateKey của bên nhận, RSA PublicKey của bên gửi

**Output** Original Data, Verify Result

<details>

<summary>Bước 1: Giải mã khóa ngẫu nhiên 3DES (Decrypted random key)</summary>

<img src="https://developer.gotadi.com/img/5.png" alt="" data-size="original">

Bên nhận sử dụng **Private key của chính mình** để giải mã encrypted key nhận được.

Example:

Java

```
public static byte[] decryptRSAToByte(String encryptedKey, String xmlPrivateKey) throws Exception {
    Cipher cipher = createCipherDecrypt(xmlPrivateKey);
    byte[] bts = Base64.decodeBase64(encryptedKey);
    byte[] randomKey = cipher.doFinal(bts);
    return randomKey;
}
```

</details>

<details>

<summary>Bước 2: Giải mã dữ liệu (Decrypted data)</summary>

<img src="https://developer.gotadi.com/img/6.png" alt="" data-size="original">

Bên nhận áp dụng thuật toán **3DES** kết hợp với random key có được ở bước trước đó, giải mã encrypted data để nhận được **original data có chứa signature**.

Lưu ý

Schema để thành lập original data sẽ được mô tả cụ thể ở từng API.

Example:

Java

```
public static String decryptTripleDes(String encryptedData, byte[] randomKey) throws Exception {
    Cipher cipher = Cipher.getInstance("DESede");
    SecretKeySpec secretKeySpec = new SecretKeySpec(randomKey, "DESede");
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] originalData  = cipher.doFinal(Base64.decodeBase64(encryptedData));
    return new String(originalData, "UTF-8");
}
```

</details>

<details>

<summary>Bước 3: Xác thực chữ ký điện tử</summary>

<img src="https://developer.gotadi.com/img/7.png" alt="" data-size="original">

Bên nhận sử dụng Thuật toán **RSA-SHA256 và Public key của bên gửi** để xác thực signature được lấy ra từ original data.

Example:

Java

```
public static boolean verifyRSA(String signedData, String signature, String xmlPublicKey) throws Exception {
    PublicKey publicKey = getPublicKeyFromXML(xmlPublicKey);
    Signature instance = Signature.getInstance("SHA256withRSA");
    instance.initVerify(publicKey);
    instance.update(signedData.getBytes("UTF-8"));
    return instance.verify(Base64.decodeBase64(signature));
}
```

</details>

***

### Kết nối <a href="#ket-noi" id="ket-noi"></a>

#### 1. Quy trình kết nối <a href="#id-1-quy-trinh-ket-noi" id="id-1-quy-trinh-ket-noi"></a>

<details>

<summary>Bước 1</summary>

Đối tác cung cấp thông tin để Gotadi khởi tạo tài khoản đại lý trên môi trường sandbox. Thông tin bao gồm:

* Thông tin công ty:
  * Tên công ty
  * Địa chỉ công ty
  * Địa chỉ website
* Thông tin quản trị viên:
  * Họ tên
  * Địa chỉ email
  * Số điện thoại
* Thông tin kết nối:
  * Đường dẫn tới hệ thống của đối tác: Link sản phẩm, Link cổng thanh toán, …
  * Các tài liệu tích hợp liên quan
  * Public key của đối tác. (RSA public key chiều dài tối thiểu 1024 bit)

</details>

<details>

<summary>Bước 2</summary>

Gotadi khởi tạo tài khoản dựa vào thông tin Đối tác cung cấp và gửi lại các thông tin tài khoản cho Đối tác. Thông tin bao gồm:

* Link kích hoạt tài khoản và đăng nhập vào B2B portal của Gotadi (Gửi vào email quản trị viên).
* Đường dẫn tới hệ thống của Gotadi: `<gotadi_api_gateway>`
* Public key của Gotadi. (RSA public key chiều dài tối thiểu 1024 bit)
* Tham số truyền vào request header:
  * Khóa truy cập API: `<api_key>`
  * Mã truy cập của đối tác: `<access_code>`

</details>

<details>

<summary>Bước 3</summary>

Đối tác kích hoạt tài khoản và sử dụng thông tin ở bước 2 tiến hành kết nối và kiểm thử trên môi trường sandbox

</details>

<details>

<summary>Bước 4</summary>

Nghiệm thu Sandbox và Golive dịch vụ

</details>

#### 2. Các quy ước viết tắt <a href="#id-2-cac-quy-uoc-viet-tat" id="id-2-cac-quy-uoc-viet-tat"></a>

| Viết tắt | Từ đầy đủ   | Mô tả                                                                                                |
| -------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| M        | `Mandatory` | Bắt buộc phải có khi gọi API.                                                                        |
| O        | `Optional`  | Không yêu cầu khi gọi API, tùy từng mục đích sử dụng mà có truyền tham số này không                  |
| C        | `Condition` | Dựa trên Condition của field khác khi gọi API mà field này được quyết định là Mandatory hay Optional |

#### 3. HTTP Response code <a href="#id-3-http-response-code" id="id-3-http-response-code"></a>

| Response code | Mô tả                 |
| ------------- | --------------------- |
| 200           | Success               |
| 400           | Bad Request           |
| 401           | Unauthorized          |
| 402           | Forbidden             |
| 402           | Not Found             |
| 500           | Internal Server Error |
| 503           | Service Unavailable   |

#### 5. Các tham số phổ biến <a href="#id-5-cac-tham-so-pho-bien" id="id-5-cac-tham-so-pho-bien"></a>

* page (Integer, Optional)

  Số thứ tự của trang (bắt đầu từ 0)
* size (Integer, Optional)

  Số lượng phần tử của mỗi trang
* sort (String, Optional)

  Mảng chứa tên trường và kiểu sắp xếp dữ liệu.

  VD: id,desc,createdDate,asc
* duration (String, Optional)

  Thời gian xử lý yêu cầu - Kể từ thời điểm nhận request đến thời điểm trả kết quả.
* success (Boolean, Required)

  Kết quả xử lý yêu cầu
* infos (Object\[], Optional)

  Mảng chứa thông tin mô tả kết quả ở các bước trong quá trình xử lý yêu cầu.
* errors (Object\[], Optional)

  Mảng chứa thông tin mô tả các lỗi đã xảy ra trong quá trình xử lý yêu cầu.
* textMessage (String, Optional)

  Thông báo được đề xuất hiển thị cho người dùng.
* pageDTO (PageDTO, Optional)

  Đối tượng mô tả các thông tin phân trang: Số thứ tự của trang được trả về, số phần tử của mỗi trang, tổng số trang, …

#### 6. Luồng tương tác <a href="#id-6-luong-tuong-tac" id="id-6-luong-tuong-tac"></a>

<figure><img src="/files/JdLqVbSOxKJ4nlmPtuGa" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/iO5OfQ4WmHZWIqcTIU9K" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/PdH0MBRLpBotR9FMRfIZ" alt=""><figcaption></figcaption></figure>

#### 7. Mã lỗi <a href="#id-7-ma-loi" id="id-7-ma-loi"></a>

| Mã lỗi | Mô tả                                                       |
| ------ | ----------------------------------------------------------- |
| 00     | Yêu cầu đã được xử lý thành công.                           |
| 01     | Yêu cầu đang được xử lý.                                    |
| 02     | Yêu cầu đã được xử lý thất bại.                             |
| 03     | Yêu bị từ chối do Xác thực tài khoản đại lý khoản thất bại. |
| 04     | Yêu bị từ chối do Chữ ký điện tử không hợp lệ.              |
| 05     | Yêu bị từ chối do Giải mã dữ liệu không thành công.         |
| 06     | Yêu bị từ chối do Mã xác thực (Access Code) không hợp lệ.   |
| 07     | Yêu bị từ chối do Dữ liệu sai định dạng.                    |
| 08     | Yêu bị từ chối do Đã được xử lý trước đó.                   |
| 09     | Yêu cầu chưa được xử lý.                                    |
| 10     | Thông tin tài khoản không tìm thấy                          |
| 99     | Lỗi khác.                                                   |

#### 8. Bảng mã lỗi chung

**Ghi chú:** Đây là các mã lỗi thông thường được dùng chung cho các API.\
Các mã lỗi riêng của từng API được mô tả bên dưới API đó.

| Mã lỗi                                  | Mô tả                                         |
| --------------------------------------- | --------------------------------------------- |
| INVALID\_REQUEST\_PARAM                 | <p>Request param không hợp lệ (Xem thêm       |
| <br>message để biết thêm chi tiết).</p> |                                               |
| UNKNOWN\_ERROR                          | <p>Lỗi chưa xác định. Liên hệ đội kỹ thuật để |
| <br>biết thêm chi tiết.</p>             |                                               |

**Example:** Response trả về với lỗi trùng booking

```json
{ 
    "duration": null, 
    "infos": null, 
    "isSuccess": true, 
    "textMessage": null, 
    "errors": [ 
        { 
            "code": "5_BOOKING_RESERVE_FAILED_DUPLICATED", 
            "id": "5013", 
            "message": "Cannot reserve booking with duplicated info" 
        } 
    ] 
}
```

**Giải thích:**

* Trong response, trường **success** (kiểu boolean) quy định kết quả trả  \
  về thành công hay thất bại.
* Nếu **success** là **false**, cần xem các lỗi trong trường **errors**.
* Mỗi error có ba trường thông tin: **mã ID**, **mã code** và **message** lỗi (chỉ dành cho developer). Quý đại lý vui lòng chỉ nên dùng **mã code** và tham chiếu với bảng mã lỗi được cung cấp ở mỗi API để biết thông tin lỗi tương ứng.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.gotadi.com/vietnamese/doi-tac-b2b2c/phuong-thuc-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
