# General

Specialized site for Developers

## Welcome to Casso Developer

There is where you can find all the documentation, tutorials, and resources for **programming your software integration** **with Casso.**

Casso was born with the DNA of **security, automation**, and **unlimited integration**. We consider integration as the core value of our product. Therefore, we have developed Casso as providing a variety of ways to connect with other software systems, serving many **different purposes**.

## Integration methods

| Method                                                                                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Manual Webhook Setup](/english-v2-new/webhook/thiet-lap-webhook-thu-cong)             | <ul><li>Configure an additional <strong>webhook</strong> on the Casso interface.</li><li>Every time a bank account has a new transaction, Casso will <strong>transmit the transaction information</strong> into the configured webhook, <a href="/pages/-MchBu0xMPRO7iRUlfzL">see reference</a></li></ul>                                                                                                                                                                                                                                                                                                                                                                      |
| [Create Auth Code Manually](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) | <ul><li>Use the <strong>API Key</strong> to call the <strong>Casso API</strong>. The <strong>API Key</strong> is similar to an <strong>Access token</strong>, the only difference is that only when the <strong>API Key</strong> is deleted will the <strong>API Key</strong> expire, <a href="/pages/-MchCJYt6Wqz_h78ZhMR">see reference</a>.</li></ul>                                                                                                                                                                                                                                                                                                                       |
| [OAuth 2](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)                        | <ul><li>Authentication Mechanism of <strong>OAuth 2</strong> allows <strong>End-users</strong> to automatically authorize <strong>Developers</strong> to access their account information at Casso.</li><li>After the users complete the authorization process on <strong>the Developer's software</strong>, an Auth Code will be automatically generated.</li><li><strong>Developers</strong> use this <strong>Authorization Code</strong> for calling Casso's Oauth 2.0 system to get the <strong>Access token</strong>. Then use the newly received <strong>Access token</strong> to call the Casso API, <a href="/pages/-MchCrnygNiqB1UgtiJK">see reference</a>.</li></ul> |

The first two methods are for **End-users**: businesses and individuals who used Casso software to serve their revenue and expenditure management needs, and now need to integrate **Casso** into other software systems that enterprises are also using.&#x20;

**The OAuth 2 method** is for **enterprise software developers** who want to integrate Casso to give users the option of **linking Casso accounts** into the software.

## Expected Plan

Besides the above 3 built-in methods, we are also working on implementing the 4th method, which is developing a set of integrated libraries similar to **Plaid for Vietnam,** provided to software developers as **source code libraries**.

This set of libraries will help these partners develop **the functionality of linking users' banks** into their software, in a secure and simple way. Users will not need to create an account with Casso, just link banks right on the **Developer's web and app**. And **Developers** do not need to worry about the security of user accounts and data.

We expect to launch officially in early 2022. *Please get in touch if you are interested in participating in our Beta Test program.*


# Manual Webhook Setup

Casso allows integration with Webhook API that calls to your server. Every time there is a new transaction, Casso will call to the API you have set up to send this transaction information.

{% hint style="success" %}
If you need a payment confirmation, use [payOS by Casso](https://payos.vn/)

payOS is a specialized solution from Casso for payment confirmation, developed through the integration of VietQR technology, Virtual Account Number, and Open Banking API.
{% endhint %}

## Operating Model

Casso uses Webhooks to notify your application when there is a deposit or withdrawal transaction to your bank account.

Integrating Casso into your application via Webhook involves just three simple steps:

1. [Program a Webhook](https://developer.casso.vn/webhook/gia-lap-giao-dich-den) endpoint to handle Webhook events on your server.
2. Simulate a new transaction from the bank for **testing** and ensuring that your webhook endpoint runs correctly.
3. Register URL of Webhook endpoint on Casso and **Go live**&#x20;

![](/files/-MfTt-1ZvnJb0f78pD1p)

## Before Starting

You have to:

* Create an account on [Casso](https://casso.vn)
* Link a bank account to Casso&#x20;

## Setting up Webhook in Casso

Log in Casso account at [my.casso.vn ](https://my.casso.vn/)

Access **Setting** > **Integration** và click **Create Integration (+)**

![](/files/-McjhH7nzwpUep215BYP)

In the list of **Integration Options,** choose **Webhook**, then open interface of **Integrated Webhook**:

![](/files/-McjlbWAK16mLz8QGw7l)

In the section **Bank receiving Webhook** :

* Choose the bank account that will be monitored to transmit transaction information.
* You can choose **All** so that **Casso System** will transmit transaction information of all bank accounts you have linked.

In the step of **Entering Webhook information:**

* Parameter **Webhook URL** will be the path to the Webhook receiver API on your web server.
* Parameter **Security Key** contains a secret code that every time Casso calls the **Webhook URL**, Casso will attach this security key to the HTTP Header. You can check the header to get the secret code information to authenticate the validity of the call to the Webhook URL.

{% hint style="danger" %}
Do not use Webhook URL is a path **only accessible from the internal network** **or localhost, 127.0.01, 192.160.1.x** ... Webhook URL must be a **public path** **on the Internet.**
{% endhint %}

Click on the Test Call button to have the Casso system send a test transaction to the Webhook URL.

If Casso transmits successfully the Webhook URL, your configuration is valid. Now you can click the **Save** button to save this configuration.

{% hint style="info" %}
Strict mode: is an advanced result verification step, when the status code returned is 200, Casso will further check in JSON returned either **success : 1** or **success : true.** If it is 0/false, the system will interpret it as a failure, and Casso will resend the Webhook. If the strict mode is not enabled, when receiving a response of status code 200, Casso will consider it as a successful Webhook transmission.&#x20;
{% endhint %}

{% hint style="success" %}
**TIP**: During the integration programming process, besides the custom Webhook pointing to your website, you can register another custom Webhook using services such as **pipedream.com**, **webhook.site**, **ngrok.com** to debug information Casso send to Webhook URL.
{% endhint %}

## Requirement of Webhook URL

Casso will make an API call to the Webhook URL every time there is a new transaction. The Webhook URL will need to meet the following requirements:

#### Accessible ability

* Must be a public link that is accessible from the internet
* The path to use the security protocol **HTTPS**
* If the website uses Cloudfare or DDOS prevention services, note that you must whitelist Casso's IP.

#### Successful response

After processing, your webhook should respond with a status code of **200 OK** and the response time less than 5 seconds ( Casso will set the timeout for request post transmit webhook to 5s)

#### Handling failure cases

If the webhook transmiting fails for some reason, Casso will repeatedly call the webhook for the next 12 hours, the first call will be after 1 minute, and this timeout will increase to the next [**Fibonacci**](https://vi.wikipedia.org/wiki/D%C3%A3y_Fibonacci) value every time the retry failed.

In total, Casso will retry a Webhook event up to 17 times. After that, it will skip and mark the Webhook event as **FAIL**.

If continuous Webhook calls fail for 24 hours, Casso will change the Webhook configuration to **PAUSED** status. When the Webhook configuration is paused and new transactions occur, these Webhook events will not be executed but instead will be held with the status of **HOLDING.** After customers fix the system's Webhook event processing issue, they can access the Casso interface to Replay these Webhook events.

If a Webhook configuration is paused for 7 days without being processed, Casso will change the Webhook configuration to Disabled status. Transactions that occur when the Webhook configuration is disabled will not be able to be replayed.&#x20;

#### Anti-duplicate

To counter the attack methods of **Replay Attack**, Does your webhook need to be de-duplicated by checking if a new transaction has been processed before? Each Casso transaction is identified by an `id`. With a new webhook coming, check an`id` whether this transaction has been processed before; if it is, then this transaction has been replayed for some reason, just ignore it.

#### Post-check processing

Despite being rare, there will always be a chance that the webhook will fail. To avoid the case of missed transactions, Developers might consider providing Full Transaction Tracing by using the API to download transactions and check if there are any missed transactions. See more in [Create Auth Cod Manually](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) or [OAuth 2 ](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)

## Data structure sent via Webhook

Casso will transmit data into the Webhook URL you declared with JSON format data, where the data field will store **an array of new transactions**.

```javascript
{
    "error": 0,
    "data": [
        {
            "id": 6785,        // Mã định danh duy nhất của giao dịch (Casso quy định)
            "tid": "BANK_REF_ID", // Mã giao dịch từ phía ngân hàng
            "description": "giao dich thu nghiem", // Nội dung giao dịch
            "amount": 79000, // Số tiền giao dịch
            "cusum_balance": 20079000,  // Số tiền còn lại sau giao dịch                 
            "when": "2020-10-14 00:34:57",    // Thời gian ghi có giao dịch ở ngân hàng
            "bank_sub_acc_id": "123456789",   // Mã tài khoản ngân hàng mà giao dịch thuộc về
            "subAccId" :  "123456789"       // Tương tự field bank_sub_acc_id, nhằm tương thích với code cũ
            "bankName" : "VPBank", // Tên ngân hàng
            "bankAbbreviation" : "VPB", // Viết tắt tên ngân hàng 
            "virtualAccount": "", // Tài khoản ảo
            "virtualAccountName": "", // Tên tài khoản ảo
            "corresponsiveName": "", // Tên tài khoản đối ứng
            "corresponsiveAccount": "", // Tài khoản đối ứng
            "corresponsiveBankId": "", // Mã ngân hàng đối ứng
            "corresponsiveBankName": "" // Tên ngân hàng đối ứng
        },
    
    ]
}
```

{% hint style="warning" %}
Notice: If there is a new transaction, Casso will still send through an array containing 1 new transaction element.
{% endhint %}

## Programming Webhook

Some resources you can refer to program the webhook handling module **Webhook Event Handler.**

| No. | Description                                                                                       | Link                                                                                                   |
| --- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| 1   | Source code **Webhook Event Handler** sample  written in PHP                                      | <https://github.com/CassoHQ/casso-webhook-handler-sample>                                              |
| 2   | Source code **Webhook Event Handler** sample  written in Java                                     | *Updating. Please contact us.*                                                                         |
| 3   | Source code **Webhook Event Handler** sample  written in NodeJS                                   | *Updating. Please contact us.*                                                                         |
| 4   | Woocommerce Plugin Official Source Code`Casso – Automatic confirmation of bank transfer payments` | <https://plugins.trac.wordpress.org/browser/casso-tu-dong-xac-nhan-thanh-toan-chuyen-khoan-ngan-hang/> |

Start now!


# Xử lý sự kiện Webhook

Hướng dẫn các bước lập trình một API xử lý sự kiện webhook. Có code mẫu bằng NodeJS

Tích hợp phương pháp webhook rất đơn giản, **tất cả mọi thứ bạn cần làm là lập trình một API xử lý sự kiện Webhook.** Sau khi bạn đã đăng kí URL của API này vào một [mục tích hợp webhook](/english-v2-new/webhook/thiet-lap-webhook-thu-cong) trong Casso.

Mỗi khi Casso phát hiện tài khoản ngân hàng liên kết có một giao dịch mới, Casso sẽ gọi vào API này

Đặc tả của API này là :&#x20;

## Xử lý giao dịch được gửi từ Casso

<mark style="color:green;">`POST`</mark> `https://websitecuaban.com/api/webhook-event-handler`

#### Headers

| Name         | Type   | Description                                       |
| ------------ | ------ | ------------------------------------------------- |
| secure-token | string | Key bảo mật để xác thực Webhook được gọi từ Casso |

#### Request Body

| Name  | Type   | Description                       |
| ----- | ------ | --------------------------------- |
| error | string | Mã lỗi.                           |
| data  | string | Mảng danh sách các giao dịch mới. |

{% tabs %}
{% tab title="200 " %}

```





```

{% endtab %}
{% endtabs %}

## Code

Bạn có thể sử dụng bất kì ngôn ngữ nào hỗ trợ xây dựng  restful API để Code.

Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:&#x20;

* Tạo dự án Restful API mới (Nodejs Express / Java Spring Boot / PHP single file, ...)
* Test in ra được helloword!
* Tạo controller mới xử lý một Post tên là /webhook-event-handler&#x20;
* Test : Dùng Curl Post một giao dịch mô phỏng lên /webhook-event-handler  và chỉnh code để in ra đúng được nội dung gửi lên (xem thêm phần Test bên dưới)
* Rút trích nội dung giao dịch
* Xử lý nội dung giao dịch
* Phản hồi HTTP status code 200 OK

Ví dụ bên dưới viết bằng NodeJS, log ra số giao dịch Webhook Api nhận dc. Bằng cách chỉnh sửa vài dòng  [ Hello World Sample của Node JS Express](https://expressjs.com/en/starter/hello-world.html)

{% tabs %}
{% tab title="First Tab" %}
{% code title="app.js" %}

```javascript
const express = require('express')
const app = express()
const port = 8080

app.use(express.json());
app.post('/api/webhook-event-handler', (req, res) => {
    let error = req.body.error;
    if (error != 0) {
        //Không làm gì cả.
        return;
    }
    
    //mảng chứa danh sách các giao dịch
    let transactions = req.body.data;
    
    console.log(`Received ${transactions.length} transactions`);
    
    //thêm code xử lý giao dịch ở đây.
    
    res.end("OK");
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
```

{% endcode %}
{% endtab %}

{% tab title="Second Tab" %}

{% endtab %}
{% endtabs %}

Bạn có thể xem thêm cách code một [API xử lý sự kiện webhook cho tính năng Tích hợp xác nhận thanh toán](/english-v2-new/tai-nguyen-khac/tich-hop-xac-nhan-thanh-toan)

### Sử dụng ngrok để public Webhook ở Local

[Ngrok](https://ngrok.com/) là một ứng dụng tạo ra một đường hầm từ máy bạn (desktop, localhost) đi qua hệ thống Firewall/Nat, giúp từ internet có thể truy cập vào máy trạm.

Nếu như bạn đang chạy server ở local port **8080**, ở **terminal**, bạn nhập: **ngrok http 8080**.

{% hint style="info" %}
Một url có thể khả dụng trong 8 giờ.

Chỉ sử dụng **https\://**

Bạn có thể sử dụng giao diện web của [Ngrok](https://ngrok.com/) để xêm lưu lượng HTTP request và response qua hệ thống của bạn: <http://localhost:8080>
{% endhint %}

## Test

Có 5 cách để giả lập giao dịch gửi vào API xử lý webhook bạn đang code như sau:

| STT | Môi trường     | Phương pháp                                                           |
| --- | -------------- | --------------------------------------------------------------------- |
| 1   | Local          | Tự gọi API bằng Curl  / Postman                                       |
| 2   | Dev \| Staging | Nút Gọi Thử Trong giao diện setup Webhook                             |
| 3   | Dev \| Staging | Nút đồng bộ giao dịch ngay trong giao diện 1 Tài khoản ngân hàng Demo |
| 4   | Live           | Tạo một lệnh chuyển tiền.                                             |

Tuy nhiên, chúng tôi khuyến cáo bạn hãy viết và test thật kĩ trên Local trước , và test nhanh bằng Postman hoặc Curl.&#x20;

{% tabs %}
{% tab title="Curl (Mac OS | Linux)" %}
Copy nội dung bên dưới, sau khi đã fix lại đường dẫn API xử lý webhook

Mở terminal&#x20;

```bash
curl --location --request POST 'http://localhost:8080/api/webhook-event-handler' \
--header 'secure-token: eogrBiWqaq' \
--header 'Content-Type: application/json' \
--data-raw '{
    "error": 0,
    "data": [
        {
            "id" : 1, 
            "when": "2020-11-02",
            "amount": 200500,
            "description": "DH35",
            "cusum_balance": 15900500,
            "tid": "TF80307914",
            "subAccId": "123456789",
            "order": "2020110200001"
        }
    ]
}'
```

Paste & Enter
{% endtab %}

{% tab title="Curl (Window)" %}

{% endtab %}

{% tab title="Postman" %}

{% endtab %}
{% endtabs %}

## Phát hành

* Release dự án lên internet
* Cập nhật lại Webhook URL trong cấu hình webhook
* Link môt tài khoản ngân hàng thật
* Chuyển tiền vào tài khoản ngân hàng (5,000 , 10,000 thôi)
* Xác nhận rằng Casso đã gọi qua Webhook và xử lý thành công

Và \
... Xin chúc mừng. **Bạn đã hoàn tất!!!!**\
\
Chúng tôi ở đây để làm cho thế giới đơn giản hơn. ^^


# Chứng thực API

Các phương pháp chứng thức với API của Casso.

## Các phương pháp chứng thực

| Phương pháp                                                           | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [API Key ](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) | <ul><li>Dùng <strong>API Key</strong> để gọi các API của Casso. <strong>API Key</strong> sẽ được xem như là một <strong>Access token,</strong> chỉ khác nhau ở chỗ chỉ khi <strong>API Key</strong> bị xóa đi thì <strong>API Key</strong> này mới hết hạn, <a href="/pages/-MchCJYt6Wqz_h78ZhMR">tham khảo tài liệu này</a>.</li></ul>                                                                                                                                                                                                                                                                                                                                                   |
| [OAuth 2.0](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)     | <ul><li>Cơ chế chứng thực <strong>OAuth 2.0</strong> cho phép <strong>người dùng cuối</strong> tự động phân quyền cho <strong>Nhà Phát Triển</strong> truy cập thông tin tài khoản của họ tại Casso.</li><li>Sau khi người dùng thực hiện quy trình phân quyền trên phần mềm của <strong>Nhà Phát Triển</strong>, thì một Authorization Code sẽ được tự động sinh ra.</li><li><strong>Nhà Phát triển</strong> sử dụng Authorization Code này gọi tới hệ thống Oauth 2.0 của Casso để lấy <strong>Access token</strong>. Sau đó dùng <strong>Access token</strong> mới nhận được để gọi tới các API của Casso, <a href="/pages/-MchCrnygNiqB1UgtiJK">tham khảo tài liệu này.</a></li></ul> |

[Phương pháp **API Key**](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) dành cho **người dùng cuối.** Là những doanh nghiệp, cá nhân đã sử dụng phần mềm **Casso** phục vụ nhu cầu quản lý thu chi. Và nay doanh nghiệp, cá nhân này cần tích hợp Casso vào hệ thống phần mềm khác mà doanh nghiệp cũng đang sử dụng.&#x20;

[Phương pháp **OAuth 2.0** ](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)dành cho các **nhà phát triển phần mềm cho doanh nghiệp,** muốn tích hợp với Casso để cung cấp cho người dùng thêm lựa chọn **liên kết tài khoản Casso** vào phần mềm.

### Ví dụ với API Key:

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"API Key của bạn">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

### Ví dụ với Access token từ OAuth 2.0 Casso:

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer <"Access token nhận được từ OAuth 2.0 của Casso">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Nếu như các bạn đã có các thông tin ở trên như: **API Key**, **access token** từ [Oauth 2.0 Casso](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2). Các bạn đã có thể sử dụng các thông tin đó với [danh sách API của Casso.](/english-v2-new/casso-api/api)
{% endhint %}


# Tạo API Key thủ công

Auth code được dùng để lấy access token cho phép ứng dụng bên ngoài truy cập và lấy thông tin trên hệ thống Casso.

## Cách tạo API Key&#x20;

Truy cập vào **Thiết lập** > **Api Keys** > **Tạo API Key > Tạo và xem API Key**

![](/files/-Me8f6FpQ-xh0BpS1Vlo)

## Cách sử dụng với API Key mới tạo

Nếu như các bạn đã quen với `v1` thì ở `v2` Casso đã bỏ đi bước [gọi lấy token](broken://pages/-MchBzabvDdqOWufUMb_) và Casso sẽ xem `API Key` này đầy đủ chức năng như là một `access token` . Điểm khác của `API Key` so với `access token` là  sẽ không có thời gian hết hạn và tiền tố  là **`<"Apikey">`** lúc bạn thêm `API Key` vào trường Authorization trên HTTP header. Ngoại trừ việc bạn xóa nó đi thì API Key đó được xem như là hết hạn. Để có thể biết cách hoạt động của API Key chúng ta sẽ xem một ví dụ ở dưới với [API lấy thông tin user v2](/english-v2-new/casso-api/api/lay-thong-tin-user):

#### Ví dụ:

{% tabs %}
{% tab title="CURL" %}

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"API Key của bạn"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

Ở ví dụ trên, bạn sẽ thấy ở phần `header` chúng tôi sẽ sử dụng **`API Key`** trong trường `Authorization` kèm theo đó phía trước **`API Key`** mà bạn tạo sẽ có tiền tố `Apikey`. Thì với tiền tố này Casso sẽ phân biệt nó với **`access token`** mà bạn nhận được từ OAuth 2.0 của Casso.

{% hint style="info" %}
Với những API còn lại bạn đều có thể sử API Key để thay thế cho Access token, như [API lấy giao dịch](/english-v2-new/casso-api/api/lay-giao-dich), [API thiết lập webhook](/english-v2-new/casso-api/api/thiet-lap-webhook), ...
{% endhint %}

{% hint style="info" %}
Lưu ý: Những API Key mới được tạo ra sau ngày 31/08/2021 sẽ không thể chạy trên các [API v1](broken://pages/-MeB7KQQcxVvlhajVnKA), những API Key này chỉ chạy được trên [API v2](/english-v2-new/casso-api/api/lay-thong-tin-user).
{% endhint %}


# Tích hợp OAuth2

Cơ chế xác thực OAuth2 cho phép người dùng cuối tự động phân quyền cho Nhà Phát Triển truy cập thông tin tài khoản của họ trên Casso.

#### Trước khi bắt đầu

Trước khi bắt đầu sử dụng Oauth2 của Casso, bạn cần phải:

* Có một tài khoản Casso.
* [Đăng ký một ứng dụng liên kết ](https://forms.gle/9Q6cvPLLmXNwpo366)với tài khoản developer của bạn.

#### Cách hoạt động

Casso hỗ trợ [Oauth 2.0 Authorization Code grant type](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type), được chia thành 4 bước cơ bản như sau:

1. Ứng dụng của bạn sẽ mở một cửa sổ trình duyệt để đưa người dùng đến Casso OAuth2.
2. Người dùng xem xét các quyền được yêu cầu và cấp quyền truy cập ứng dụng.
3. Người dùng được chuyển hướng trở lại ứng dụng với mã ủy quyền(authorization code) trong chuỗi truy vấn(query params).
4. Ứng dụng gửi yêu cầu đến Casso OAuth2 để trao đổi mã ủy quyền(authorization code) để lấy **`access token`**.

#### Hướng dẫn

* [**Lấy OAuth2 token**](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2#lay-oauth2-token): Cách ủy quyền ứng dụng của bạn với người dùng.
* [**Sử dụng OAuth2 token**](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2#su-dung-oauth2-token): Cách thực hiện một truy vấn với token.
* [**Lấy lại OAuth2 token**](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2#lay-lai-oauth-2-token): Cách sử dụng refresh token do Casso cung cấp.

## Lấy OAuth2 token

#### Bước 1: Tạo một authorization URL và hướng người dùng đến Oauth2 của Casso.

Khi một người dùng truy vấn tới hệ thống Oauth2 của Casso, đầu tiên sẽ phải tạo một authorization URL. Điều này sẽ xác định ứng dụng và phạm vi tài nguyên mà ứng dụng yêu cầu quyền truy cập thay cho người dùng. Các tham số truy vấn bạn có thể truyền như một phần của authorization URL được hiển thị ở dưới.&#x20;

| Tham số         | Bắt buộc | Mô tả                                                                                                                                                                 | Ví dụ                                   |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `client_id`     | Có       | Client ID dùng để xác định ứng dụng của bạn.                                                                                                                          | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `scope`         | Có       | Các phạm vi ứng dụng của bạn đang yêu cầu, được phân tách bằng dấu cách được mã hóa URL.                                                                              | `webhook%20transaction`                 |
| `redirect_uri`  | Có       | URL mà người dùng sẽ được chuyển hướng đến sau khi họ ủy quyền cho ứng dụng của bạn trong các phạm vi được yêu cầu. Đối với các ứng dụng sản xuất, https là bắt buộc. | `https://www.example.com/auth-callback` |
| `response_type` | Có       | Loại phản hồi                                                                                                                                                         | `code`                                  |
| `state`         | Không    | Đây là thông số khi bạn gửi lên như nào thì lúc bạn nhận authorization code thì nó vẫn như vậy.                                                                       | `84be6ce9661042d59cf`                   |

Khi bạn đã tạo xong authorization URL của mình, hãy bắt đầu tiến trình OAuth2 bằng cách đưa người dùng đến URL đó.

#### Ví dụ

Sử dụng một server-side redirect:

```javascript
// Build the auth URL
const authUrl =
  'https://oauth.casso.vn/auth/authorize' +
  `?client_id=${encodeURIComponent(CLIENT_ID)}` +
  `&scope=${encodeURIComponent(SCOPES)}` +
  `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
  `&response_type=${encodeURIComponent(RESPONSE_TYPE)}`;

// Redirect the user
return res.redirect(authUrl);
```

Sử dụng đương dẫn HTML:

```javascript
<a href="https://oauth.casso.vn/auth/authorize?scope=webhook%20transaction&redirect_uri=https://www.example.com/auth-callback&client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">One click to Casso</a>
```

#### Bước 2: Casso nhắc nhở người dùng chấp thuận&#x20;

Casso hiển thị cửa sổ cho người dùng đồng ý, hiển thị tên ứng dụng của bạn và mô tả ngắn gọn về các dịch vụ API của Casso mà họ đang yêu cầu quyền truy cập. Sau đó, người dùng có thể cấp quyền truy cập doanh nghiệp của họ cho ứng dụng của bạn.

![](/files/-MiuCN3PSFhpIOblrkO1)

Ứng dụng của bạn không thực hiện bất kỳ điều gì ở giai đoạn này. Sau khi quyền truy cập được người dùng cấp, Casso OAuth2 sẽ gửi kết quả đến **`Callback URL`** được xác định trong authorization URL.

#### Bước 3: Xử lý phản hồi của OAuth2

Khi người dùng đã hoàn tất lời nhắc đồng ý từ Bước 2, OAuth 2.0 server sẽ gửi yêu cầu GET tới **redirect URI** được chỉ định trong authorization URL của bạn. Nếu không có vấn đề gì và người dùng chấp thuận yêu cầu truy cập, yêu cầu tới **redirect URI** sẽ được trả về với tham số truy vấn mã được đính kèm. Nếu người dùng không cấp quyền truy cập, sẽ gửi một yêu cầu lỗi về **redirect URI**.

#### Ví dụ:

```javascript
app.get('/oauth-callback', async (req, res) => {
  if (req.query.code) {
    // Handle the received code
  }
});
```

#### Bước 4: Trao đổi authorization code để lấy token

Sau khi ứng dụng của bạn nhận được **authorization code** từ OAuth server, ứng dụng có thể trao đổi mã đó để lấy **access token** và **refresh token** bằng cách gửi yêu cầu [POST URL-form encoded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#example) tới `https://oauth.casso.vn/auth/token` với các giá trị được hiển thị bên dưới.  Cung cấp base64 của **client\_*****id:client\_secret*** dưới dạng **`basic token`** trong Authorization HTTP Header.

| Tham số         | Mô tả                                                                 | Ví dụ                                   |
| --------------- | --------------------------------------------------------------------- | --------------------------------------- |
| `grant_type`    | Bắt buộc là`authorization_code`                                       | `authorization_code`                    |
| `client_id`     | Client ID của ứng dụng của bạn                                        | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `client_secret` | Client secret của ứng dụng của bạn                                    | `58dfc671-c650-457f-8a24-3d57bdeab5ac`  |
| `redirect_uri`  | Chuyển hướng tới URI này khi người dùng ủy quyền cho ứng dụng của bạn | `https://www.example.com/auth-callback` |
| `code`          | Authorization code nhận được từ Oauth2 server                         | `6be34af7-6699-41cb-9c41-e02c635bd354`  |

#### Ví dụ:

```javascript
const formData = {
  grant_type: 'authorization_code',
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  code: req.query.code
};

request.post(
  'https://oauth.casso.vn/auth/token', 
  { 
    form: formData,
    headers: {
      Authorization: `Basic ${Buffer.from(CLIENT_ID+":"+CLIENT_SECRET).toString('base64')}`
    } 
  }, (err, data) => {
  // Handle the returned tokens
}
```

Nội dung của phản hồi mã thông báo sẽ là dữ liệu JSON có dạng:&#x20;

```javascript
{
    "refresh_token":"f71345a6-f53d-4191-903c-3823d9adb9e",
    "access_token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxODI5IiwiZXhwIjoxNjMwOTQxMDI4LCeJpYXQiOjE2MzA5MTk0M9.mYA8HFw0HqyoLJAocIzffNw4aG2kA8sHlf2UYNIKhHlazWK2ajbj06Bil4_0NxS6Jiamw3E9Q28tpiU7f9tYA",
    "expires_in":21600,
    "token_type": "bearer"
}
```

{% hint style="info" %}
Note: Access token sẽ hết hạn sau số giây được cung cấp trong trường expires\_in của phản hồi (sáu giờ). Để biết thông tin về cách nhận access token mới, hãy xem [Lấy lại Oauth2 token](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2#lay-lai-oauth-2-token).
{% endhint %}

## Sử dụng OAuth2 token

Sau khi hoàn tất quy trình authorization code, ứng dụng của bạn được ủy quyền thay người dùng gửi request. Để thực hiện việc này, cung cấp access token dưới dạng bearer token trong Authorization HTTP Header.&#x20;

#### Ví dụ:

```javascript
request.get('https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4',
  {
    headers: {
      'Authorization': `Bearer ${ACCESS_TOKEN}`,
      'Content-Type': 'application/json'
    }
  },
  (err, data) => {
    // Handle the API response
  }
);
```

## Lấy lại OAuth 2 token

OAuth access token hết hạn định kỳ. Điều này nhằm đảm bảo rằng nếu chúng bị xâm nhập, những kẻ tấn công sẽ chỉ có quyền truy cập trong một thời gian ngắn. Tuổi thọ của access token (sáu giờ theo mặc định) được chỉ định trong trường **`expires_in`** khi **`authorization code`** được trao đổi lấy access token.

Ứng dụng của bạn có thể trao đổi **`refresh token`** đã nhận để lấy **`access token`** mới bằng cách gửi yêu cầu [POST URL-form encoded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#example) tới **`https://oauth.casso.com/auth/token`** với các giá trị bên dưới. Cung cấp base64 của **client\_*****id:client\_secret*** dưới dạng basic token trong Authorization HTTP Header.

| Tham số         | Mô tả                                                                 | Ví dụ                                   |
| --------------- | --------------------------------------------------------------------- | --------------------------------------- |
| `grant_type`    | Phải là `refresh_token`                                               | `refresh_token`                         |
| `client_id`     | Client ID của ứng dụng của bạn                                        | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `client_secret` | Client secret của ứng dụng của bạn                                    | `58dfc671-c650-457f-8a24-3d57bdeab5ac`  |
| `redirect_uri`  | Chuyển hướng tới URI này khi người dùng ủy quyền cho ứng dụng của bạn | `https://www.example.com/auth-callback` |
| `refresh_token` | Refresh token nhận được khi người dùng ủy quyền cho ứng dụng của bạn  | `6be34af7-6699-41cb-9c41-e02c635bd354`  |

#### Ví dụ:

```javascript
const formData = {
  grant_type: 'refresh_token',
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  refresh_token: REFRESH_TOKEN
};

request.post(
  'https://oauth.casso.vn/auth/token', 
  { 
    form: formData, 
    headers: {
      Authorization: `Basic ${Buffer.from(CLIENT_ID+":"+CLIENT_SECRET).toString('base64')}`
    } 
  }, (err, data) => {
  // Handle the returned tokens
}
```

Nội dung của phản hồi mã thông báo sẽ là dữ liệu JSON có dạng:&#x20;

```javascript
{
    "access_token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxODI5IiwiZXhwjsIjoxNjMwOTQyODc4LCJpYXQiOjE2MzA5MjEyNzh9.qh0_UkSudFUu_WabtW9wu_j57b3VJ5WEWASLpSklPfrb-EKzrYl4Z4PYkrPIPrLseCPnSXlIDsixp8OkBrh_BW4g",
    "token_type": "bearer",
    "expires_in": 21600
}
```

**`Access token`** mới có thể được sử dụng để thực hiện request thay cho người dùng. Khi **`access token`** mới hết hạn, bạn có thể thực hiện lại các bước tương tự để lấy mã mới.

{% hint style="info" %}
**Refresh token** không có thời gian hết hạn. Mỗi lần **`access token`** hết hạn, bạn thực hiện lại các bước tương tự với **refresh token** để lấy mã mới.
{% endhint %}


# Danh sách API

Danh sách các API của Casso

## Trước khi bắt đầu

Để có thể bắt đầu với các API sau yêu cầu các bạn chuẩn bị:

* Một tài khoản [Casso](https://my.casso.vn), đã liên kết một tài khoản ngân. Bạn có thể sử dụng tài [khoản ngân hàng Demo này.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Chọn một trong [phương pháp chứng thực API.](/english-v2-new/casso-api/chung-thuc)

{% hint style="info" %}
Bạn có thể sử dụng một trong hai phương pháp chứng thức API của Casso đó là [API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) và [Oauth 2.0](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2) để có thể sử dụng với các API dưới.
{% endhint %}

## Bảng danh sách các API

| API                                                                        | Mô tả                                                                                            |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [Thông tin user](/english-v2-new/casso-api/api/lay-thong-tin-user)         | Lấy thông tin chi tiết của tài khoản như: email, tên doanh nghiệp, danh sách liên kết ngân hàng. |
| [Thiết lập Webhook](/english-v2-new/casso-api/api/thiet-lap-webhook)       | Thiết lập Webhook như: thêm, sửa và xóa                                                          |
| [Giao dịch ngân hàng](/english-v2-new/casso-api/api/lay-giao-dich)         | Lấy giao dịch ngân hàng                                                                          |
| [Đồng bộ giao dịch mới](/english-v2-new/casso-api/api/check-giao-dich-moi) | Gọi đồng bộ giao dịch mới với tài khoản tương ứng                                                |

{% hint style="info" %}
Lưu ý: Ở phần Authorization HTTP Header của các API trên, bạn phải sử dụng tiền tố phú hợp với mỗi kết quả từ các [phương thức chứng thực](/english-v2-new/casso-api/chung-thuc). Như với [chứng thực API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) bạn phải sử dụng tiền tố **`Apikey + API key của bạn,`** với access token từ [Oauth 2.0 của Casso ](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)bản phải sử dụng tiền tố là **`Bearer + access token nhận được từ Oauth 2.0.`**
{% endhint %}

{% hint style="success" %}
Mẹo hay với [API đồng bộ giao dịch](/english-v2-new/casso-api/api/check-giao-dich-moi) mới đối với các doanh nghiệp/cá nhân bán hàng trực tuyến. Bạn có thể [xem chi tiết ở đây.](/english-v2-new/tai-nguyen-khac/tich-hop-xac-nhan-thanh-toan)
{% endhint %}


# API lấy thông tin user

Dùng để lấy thông tin người dùng như: thông tin tài khoản, thông tin doanh nghiệp, danh sách các ngân hàng liên kết.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) hoặc [Access token từ Oauth 2.0 của Casso](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2) để thiết lập ở trường Authorization HTTP Header.

## Lấy thông tin user

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/userInfo`

Lấy chi tiết thông tin tài khoản như: email, thông tin doanh nghiệp và thông tin tài khoản ngân hàng liên kết.

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 Cake successfully retrieved." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "user": {
            "id": 1553,
            "email": "haonh@magik.vn"
        },
        "business": {
            "id": 1540,
            "name": "Hữu Hảo"
        },
        "bankAccs": [
            {
                "id": 69,
                "bank": {
                    "bin": 970416,
                    "codeName": "acb_digi"
                },
                "bankAccountName": null,
                "bankSubAccId": "17271687",
                "connectStatus": 1,
                "planStatus": 1
            },
            {
                "id": 63,
                "bank": {
                    "bin": 970454,
                    "codeName": "timoplus"
                },
                "bankAccountName": null,
                "bankSubAccId": "8007041023848",
                "connectStatus": 1,
                "planStatus": 0
            }
        ]
    }
}
```

{% endtab %}

{% tab title="401 Could not find a cake matching this query." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
Mẹo: Bạn có thể sử dụng thông tin phản hồi của API này trong trường **`bankAccs`** để có thể tạo cho mình các mã [VietQR code ](https://www.vietqr.io/)tương ứng với các thông tin phản hồi này.
{% endhint %}


# API thiết lập webhook

Dùng để thiết lập webhook như: thêm, sửa và xóa.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có một endpoint/API để nhận sự kiện từ Casso đây được gọi là [Webhook](https://en.wikipedia.org/wiki/Webhook).
* Endpoint/API này phải public ra ngoài Internet. Nếu như bạn đang ở **local** bạn có thể [xem hương dẫn này](/english-v2-new/webhook/gia-lap-giao-dich-den#su-dung-ngrok-de-public-webhook-o-local) để biết cách public endpoint của bạn.
* Bạn cần có [API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) hoặc [Access token từ Oauth 2.0 của Casso](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2) để thiết lập ở trường Authorization HTTP Header.

## Tạo webhook

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v2/webhooks`

Thực hiện tạo webhook tới server của bạn

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

#### Request Body

| Name          | Type    | Description                                                                      |
| ------------- | ------- | -------------------------------------------------------------------------------- |
| income\_only | boolean | Giá trị được thiết lập để gửi bắn sự kiện tới webhook đối với giao dịch tiền vào |
| secure\_token | string  | Mã bảo mật để mỗi lần gửi Event từ Casso sẽ được đính kèm trên header.           |
| webhook       | string  | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso             |

{% tabs %}
{% tab title="200 Response thông tin webhook đã tạo thành công." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 114,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạn." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request POST 'https://oauth.casso.vn/v2/webhooks' \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
    "secure_token": "@123#abc",
    "income_only": true
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'webhook' => 'https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php',
  'secure_token' => '@123#abc',
  'income_only' => true
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("webhook", "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php")
  .add("secure_token", "@123#abc")
  .add("income_only", true)
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xem chi tiết webhook

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Xem chi tiết các thông về webhook của bạn theo dựa theo `webhook Id`

#### Path Parameters

| Name | Type   | Description                        |
| ---- | ------ | ---------------------------------- |
| id   | string | `id webhook` bạn muốn xem chi tiết |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com.vn/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/webhooks/134' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/134",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/134")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Cập nhật một webhook

<mark style="color:orange;">`PUT`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Cập nhật các thông tin trong webhook đã được thiết lập trước đó

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

#### Request Body

| Name          | Type    | Description                                                          |
| ------------- | ------- | -------------------------------------------------------------------- |
| income\_only  | boolean | Xác nhận gửi webhook đối với tiền vào                                |
| secure\_token | string  | mã bảo mật                                                           |
| webhook       | string  | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://webhook-cua-ban.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request PUT 'https://oauth.casso.vn/v2/webhooks/111' \
--header 'Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/api/bank",
    "secure_token": "@xyz@123",
    "income_only": "false"
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'webhook' => 'https://ten-mien-cua-ban.com/api/bank'
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/111",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PUT",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("webhook", "https://ten-mien-cua-ban-new.com/wc-new/handler-bank-transfer.php")
  .add("secure_token", "@123#abc-new")
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/111")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xoá một webhook

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Thực hiện xóa một webhook bằng `id webhook` &#x20;

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://khanh-dep-trai.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request DELETE 'https://oauth.casso.vn/v2/webhooks/85' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/85",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "DELETE",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/85")
  .delete()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xoá tất cả webhook trong đường dẫn &#x20;

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v2/webhooks`

Xóa tất cả các webhook đang tồn tại trong doanh nghiệp của bạn trên Casso tương ứng với giá trị webhook mà bạn yêu cầu.

#### Query Parameters

| Name    | Type   | Description                                                          |
| ------- | ------ | -------------------------------------------------------------------- |
| webhook | string | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": [
        {
            "id": 108,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 109,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 110,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
    ]
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}

{% tab title="404 " %}

```
{
    "error": 12,
    "message": "Webhook not exists",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request DELETE 'https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "DELETE",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook")
  .delete()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
Lưu ý: Khi bạn gọi API có thể sẽ xóa đi những webhook cũ mà bạn đã thiết lập trên hệ thống của Casso. Cân nhắc trước khi dùng tới API này.
{% endhint %}


# API lấy giao dịch

Dùng để lấy một hoặc nhiều giao dịch ngân hàng

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) hoặc [Access token từ Oauth 2.0 của Casso](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2) để thiết lập ở trường Authorization HTTP Header.

## &#x20;Lấy giao dịch ngân hàng &#x20;

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/transactions`

API này cho phép lấy toàn bộ thông tin giao dịch ngân hàng.

#### Query Parameters

| Name     | Type    | Description                                                                             |
| -------- | ------- | --------------------------------------------------------------------------------------- |
| sort     | string  | Sắp xếp tăng hoặc giảm dần dựa theo thời gian của giao dịch. Mặc định là ASC(tăng dần). |
| pageSize | string  | Số lượng giao dịch trên một trang                                                       |
| page     | integer | Số thứ tự của trang                                                                     |
| fromDate | string  | Lấy giao dịch bắt đầu từ ngày. Định dạng: YYYY-MM-                                      |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 Response chi tiết các giao dịch ngân hàng" %}
{% tabs %}
{% tab title="Response theo page" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "page": 4,
        "pageSize": 10,
        "nextPage": 5,
        "prevPage": 3,
        "totalPages": 35,
        "totalRecords": 341,
        "records": [
            {
                "id": 5789,
                "tid": "TF2104152395814062",
                "description": "Khanhnm chuyen tien",
                "amount": -193000,
                "cusum_balance": 1070904,
                "when": "2021-04-15"
            },
            {
                "id": 5790,
                "tid": "TF2104152997602811",
                "description": "Chuyen tien nap momo",
                "amount": -350000,
                "cusum_balance": 720904,
                "when": "2021-04-15"
            },
        ]
    }
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạ" %}

```
```

{% endtab %}
{% endtabs %}

#### Chi tiết các tham số

| Tham số        | Mô tả                                                                                    | Gá trị mặc định |
| -------------- | ---------------------------------------------------------------------------------------- | --------------- |
| ***fromDate*** | Thời gian bắt đầu bạn muốn lấy giao                                                     | 7 ngày gần nhất |
| ***page***     | Số thứ tự trang                                                                          | 1               |
| ***pageSize*** | Số giao dịch trên một trang                                                              | 10              |
| ***sort***     | Sắp xếp giao dịch, các giá trị gồm: ASC, DESC. Với ASC là tăng dần còn DESC là giảm dần. | ASC             |

{% hint style="info" %}
Nếu tham số nào không tồn tại thì sẽ lấy giá trị mặc định.
{% endhint %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC' \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## Lấy chi tiết một giao dịch

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/transactions/:id`

API cho phép bạn xem chi tiết của một giao dịch ngân hàng.

#### Path Parameters

| Name | Type   | Description                          |
| ---- | ------ | ------------------------------------ |
| id   | number | ID của giao dịch trên hệ thống Casso |

#### Headers

| Name          | Type   | Description                                                |
| ------------- | ------ | ---------------------------------------------------------- |
| Authorization | string | `Bearer` + `access token nhận được từ OAuth 2.0 của Casso` |

{% tabs %}
{% tab title="200 Thông tin chi tiết của 1 giao dịch" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 314344,
        "tid": "TF210702253136879",
        "description": "DH220",
        "amount": -10000,
        "cusumBalance": 389460,
        "when": "2021-07-02T12:50:00",
        "bankSubAccId": "8007041023848"
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/transactions/123 \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/transactions/12",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/transactions/12")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}


# API check giao dịch mới

Thay vì phải chờ hệ thống của Casso tự động đồng bộ giao dịch mới thì với API này sẽ giúp bạn xử lý các giao dịch mới mà hệ thống của Casso chưa đồng bộ kịp thời.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **hạn chế** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong) hoặc [Access token từ Oauth 2.0 của Casso](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2) để thiết lập ở trường Authorization HTTP Header.

## Đồng bộ giao dịch mới

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v2/sync`

Đồng bộ giao dịch mới tương ứng với số tài khoản của bạn trong business

#### Headers

| Name           | Type   | Description                                                               |
| -------------- | ------ | ------------------------------------------------------------------------- |
| Authentication | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

#### Request Body

| Name          | Type   | Description                                                     |
| ------------- | ------ | --------------------------------------------------------------- |
| bank\_acc\_id | string | Số tài khoản ngân hàng của bạn liên kết trên hệ thống của Casso |

{% tabs %}
{% tab title="200 Sync successfully." %}
{% tabs %}
{% tab title="Đồng bộ giao dịch thành công" %}

```
{
    "error": 0,
    "message": "success",
    "data": null
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Token sai hoặc hết hạn" %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request POST 'https://oauth.casso.vn/v2/sync' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">' \
--header 'Content-Type: application/json' \
--data-raw '{
    "bank_acc_id": "Số tài khoản ngân hàng cần đồng bộ"
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'bank_acc_id' => 'Số tài khoản ngân hàng cần đồng bộ',
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/sync",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("bank_acc_id", "Số tài khoản ngân hàng cần đồng bộ")
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/sync")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Sau khi bạn gọi API này, nếu hệ thống của Casso phát hiện có một hoặc nhiều giao dịch mới được đồng bộ thì ngay lúc đó hệ thống của Casso sẽ đẩy một Event chứa các giao dịch mới đó tới [Webhook của bạn đã thiết lập](/english-v2-new/casso-api/api/thiet-lap-webhook).
{% endhint %}


# Tích hợp xác nhận thanh toán

Thực hành lập trình xử lý sự kiện webhook để xác nhận thanh toán

## Giới thiệu

Hiện tại [Casso](https://casso.vn/) đã hỗ trợ nhiều hình thức tích hợp xác nhận thanh toán thông qua các [API](https://restfulapi.net/) [Casso](https://casso.vn/) đã public. Để phần tích hợp thanh toán của bạn xịn hơn thì có thể dùng [VietQR](https://www.vietqr.io/) để tạo QR-Code cho phần thanh toán. [VietQR](https://www.vietqr.io/) là tiêu chuẩn quốc gia về mã QR ngân hàng. Mã này được chấp nhận bởi 50 ngân hàng Việt Nam. Có thể xem chi tiết tại [đây](https://www.vietqr.io)

## Trước khi bắt đầu

## Hướng dẫn tích hợp

Để có thể sử dụng và hiểu được các API này thì dưới đây Casso demo một server basic được viết bằng [NodeJS](https://nodejs.org/en/about/) + [Express](https://expressjs.com/)  basic về tích hợp thanh toán. Chi tiết source tại [Github](https://github.com/CassoHQ/Integrated-payment-confirmation/blob/main/routes/index.js).

Dưới đây là demo các bước về việc tạo webhook để lắng nghe có các giao dịch mới của Casso gửi qua và yêu cầu đồng bộ giao dịch tức thì từ phía app. Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:

### Cấu trúc file sever

![](/files/-MeFtZq8tCb2a6Cr7XK4)

### **Bước 1: Tạo file index.js**

Đầu tiên chúng ta sẽ tạo file `index.js` để xây dựng server lắng nghe các request. Server mình sẽ thiết lập với cổng **4300**

```javascript
require('dotenv').config({ path: '.env' });
let app = require('./app');
async function main() {
    app
    console.log(`Server on port ${process.env.PORT || 4300}`);
};
main();
```

### **Bước 2**: Tạo file app.js, config và xử lý lỗi

Các thứ cần thiết cho server như: `cors, json, urlencoded`và [Express error handling](https://expressjs.com/en/guide/error-handling.html)

```javascript
let express = require("express");
var cors = require('cors');
let app = express();
// Tạo cors
var corsOption = {
    origin: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
    exposedHeaders: ['x-auth-token']
  };
app.use(cors(corsOption));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/', require('./routes'));
// Endpoint not found
app.use(function (req, res, next) {
    res.status(404).json({
        code: 404,
        message: 'Endpoint not found'
    });
})
// Xử lí khi lỗi ở phía server
app.use(function (err, req, res, next) {
    res.status(500).json({
        code: 500, error: 'Something went wrong, please try again!'
    })
})
app.listen(process.env.PORT || 4300);
module.exports = app;
```

### **Bước 3: Tạo các routes và test hello world**

Ở đây mình sẽ tạo 3 route chính:

* `/webhook/handler-bank-transfer` Webhook để nhận thông tin giao dịch từ Casso
* `/register-webhook` Thực hiện đăng kí webhook và lấy token từ Casso
* `/users-paid` Thực hiện tính năng đồng bộ giao dịch tức thì qua Casso

```javascript
var express = require('express');
var router = express.Router();
//Router này sẽ là webhook nhận thông tin giao dịch từ casso gọi qua được bảo mật bằng secure_token trong header
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Router này sẽ thực hiện tính năng đồng bộ giao dịch tức thì.
// Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút tôi đã thanh toán thì nên xử lí gọi qua casso đề đồng bộ giao dịch vừa chuyển khoản
router.route('/users-paid')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Route này sẽ thực hiện đăng kí webhook dựa vào API KEY và lấy thông tin về business và banks
router.route('/register-webhook')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })

module.exports = router;
```

Kiểm tra với postman&#x20;

![](/files/-MexD2hlKQCo8-6ZjteV)

### **Bước 4:** Xây dựng các hàm hỗ trợ

Để có thể giao tiếp với server Casso sẽ dùng 1 [HTTP Client](https://tapit.vn/http-request-va-http-response-phuong-thuc-giao-tiep-giua-server-client/)  để gọi qua. Ở Demo này sẽ sử dụng [Axios](https://www.npmjs.com/package/axios) và [Query-string](https://www.npmjs.com/package/query-string).

```javascript
//utils/api.js
const axios = require("axios");
const queryString =  require("query-string");

const axiosClient = axios.create({
  baseURL: 'https://oauth.casso.vn/v2',
  headers: {
    "content-type": "application/json",
    "Authorization": `Apikey ${api_key}`,
  },
  paramsSerializer: (params) => queryString.stringify(params),
});
axiosClient.interceptors.request.use(async (config) => {
  return config;
});
axiosClient.interceptors.response.use(
  (response) => {
    if (response && response.data) return response.data;
    return response;
  },
  (error) => {
    throw error;
  }
);
module.exports =  axiosClient;
```

{% hint style="success" %}
**Mẹo**:  Bạn có thể thay thế giá trị của **Authorization** với **`Bearer + access token`** nhận được từ [xác thực Oauth 2.0 của Casso.](/english-v2-new/casso-api/chung-thuc/tich-hop-oauth2)
{% endhint %}

{% hint style="info" %}
Bạn thể [tham khảo tài liệu này](/english-v2-new/casso-api/chung-thuc/tao-api-key-thu-cong), để lấy API Key của bạn trên Casso.
{% endhint %}

Sau khi code HTTP Client thì tiến hành dựng từng hàm tương ứng với từng API.

* Get `userInfo` bao gồm thông tin về business và banks. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-lay-thong-tin-user)

```javascript
/*utils/get_user_info.util.js*/
    getDetailUser: async () => {
        let res = await api.get(`/userInfo`);
        return res;
    },
```

* Đồng bộ dữ liệu mới nhất. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-check-giao-dich-moi)

```javascript
/*utils/sync.util.js*/
    syncTransaction: async (bankNumber, apiKey) => {
        let res = await api.post('/sync', { bank_acc_id: bankNumber });
        return res;
    }
```

* Các hàm thêm, xóa, sửa và xóa `webhook` Mô tả chi tiết tại [đây](https://developer.casso.vn/danh-sach-api/api-thiet-lap-webhook)

```javascript
/*webhook.util.js*/
    create: async (data) => {
        let res = await api.post('/webhooks', data);
        return res;
    },
    getDetailWebhookById: async (webhookId) => {
        let res = await api.get(`/webhooks/${webhookId}`);
        return res;
    },
    updateWebhookById: async (webhookId, data) => {
        let res = await api.put(`/webhooks/${webhookId}`, data);
        return res;
    },
    deleteWebhookById: async (webhookId) => {
        let res = await api.delete(`/webhooks/${webhookId}`);
        return res;
    },
    deleteWebhookByUrl: async (urlWebhook) => {
        // Thêm url vào query để delete https://oauth.casso.vn/v1/webhooks?webhook=https://website-cua-ban.com/api/webhook
        let query = { params: { webhook: urlWebhook } };
        let res = await api.delete(`/webhooks`, query);
        return res;
    },
```

* Parser `orderId` từ nội dung giao dịch và tiền tố giao dịch (`DH1231=> 1231`) và đồng thời cũng kiểm tra có phân biệt chữ hoa với thường trong nội dung giao dịch hay không?

```javascript
/*webhook.util.js*/
    parseOrderId: (caseInsensitive, transactionPrefix, description) => {
        // Ở đây mình ở sử dụng regex để parse nội dung chuyển khoản có chứa orderId
        // CASSO101 => orderId = 101
        let re = new RegExp(transactionPrefix);
        if (!caseInsensitive)
            re = new RegExp(transactionPrefix, 'i');
        let matchPrefix = description.match(re);
        // Không tồn tại tiền tố giao dịch
        if (!matchPrefix) return null;
        let orderId = parseInt(description.substring(transactionPrefix.length, description.length));
        return orderId;
    }
```

### Bước 5: Xây dựng các Route&#x20;

Mình cần định nghĩa một vài biến cần trong quá trình dựng

```javascript
//routes/index.js
//Tiền tố giao dịch
const transaction_prefix = 'CASSO';
// Phân biệt chữ hoa/thường trong tiền tố giao dịch
const case_insensitive = false;
//Hạn của đơn hàng là 3 ngày. Quá 3 ngày thì không xử lý
const expiration_date = 3;
// API KEY lấy từ casso
const api_key = '45e40320-e0b7-11eb-a12c-35cc867f21a0';
// secure_token đăng kí khi tạo webhook
const secure_token = 'R5G4cbnN7uSAwfTd'
```

1. Route tạo webhook  bằng API\_KEY và lấy thông tin user bao gồm Business và banks

```javascript
//routes/index.js
router.route('/register-webhook')
    .post(async (req, res, next) => {
        try {
            //Delete Toàn bộ webhook đã đăng kí trước đó với https://ten-mien-cua-ban.com/webhook/handler-bank-transfer
            await webhookUtil.deleteWebhookByUrl('https://ten-mien-cua-ban.com/webhook/handler-bank-transfer');
            //Tiến hành tạo webhook
            let data = {
                webhook: 'https://ten-mien-cua-ban.com/webhook/handler-bank-transfer',
                secure_token: secure_token,
                income_only: true
            }
            let newWebhook = await webhookUtil.create(data);
            // Lấy thông tin về userInfo
            let userInfo = await userUtil.getDetailUser();
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: {
                    webhook: newWebhook.data,
                    userInfo: userInfo.data
                }
            })
        } catch (error) {
            next(error)
        }
    })
```

```javascript
curl --location --request POST 'http://localhost:4300/register-webhook' \
--header 'Content-Type: application/json'
```

```javascript
{
    "code": 200,
    "message": "success",
    "data": {
        "webhook": {
            "id": 415,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/webhook/handler-bank-transfer",
            "param2": "R5G4cbnN7uSAwfTd",
            "sendOnlyIncome": 1
        },
        "userInfo": {
            "user": {
                "id": 1553,
                "email": "haonh@magik.vn"
            },
            "business": {
                "id": 1540,
                "name": "Hữu Hảo"
            },
            "bankAccs": [
                {
                    "id": 619,
                    "bank": {
                        "bin": 970416,
                        "codeName": "acb_digi"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "17271687",
                    "connectStatus": 1,
                    "planStatus": 1
                },
                {
                    "id": 623,
                    "bank": {
                        "bin": 970454,
                        "codeName": "timoplus"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "8007041023848",
                    "connectStatus": 1,
                    "planStatus": 0
                }
            ]
        }
    }
}
```

2\. Route này sẽ thực hiện tính năng đồng bộ giao dịch qua Casso.

Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút **tôi đã thanh toán** thì nên xử lí gọi qua Casso để đồng bộ giao dịch vừa được chuyển khoản. Có thể sử dụng cho tính năng **Tôi đã thanh toán** để xác nhận thanh toán ngay.

```javascript
//routes/index.js
router.route('/users-paid')
    .post(async (req, res, next) => {
        try {
            // Để thực hiện tính năng đồng bộ cần có Số tài khoản, Bạn có thể validate bằng schema ở middlewares
            // Hoặc có thể kiểm tra trong đây luôn
            if (!req.body.accountNumber) {
                return res.status(404).json({
                    code: 404,
                    message: 'Not foung Account number'
                })
            }
            // Tiến hành gọi hàm đồng bộ qua casso
            await syncUtil.syncTransaction(req.body.accountNumber);
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }

    })
```

3\. Tạo một webhook để Casso có thể gửi giao dịch qua khi có giao dịch mới (**quan trọng**):&#x20;

```javascript
//routes/index.js
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        try {
            // B1: Ở đây mình sẽ thực hiện check secure-token. Bình thường phần này sẽ nằm trong middlewares
            // Mình sẽ code trực tiếp tại đây cho dễ hình dung luồng. Nếu không có secure-token hoặc sai đều trả về lỗi
            if (!req.header('secure-token') || req.header('secure-token') != secure_token) {
                return res.status(401).json({
                    code: 401,
                    message: 'Missing secure-token or wrong secure-token'
                })
            }
            // B2: Thực hiện lấy thông tin giao dịch 
            for (let item of req.body.data) {
                // Lấy thông orderId từ nội dung giao dịch
                let orderId = webhookUtil.parseOrderId(case_insensitive, transaction_prefix, item.description);
                // Nếu không có orderId phù hợp từ nội dung ra next giao dịch tiếp theo
                if (!orderId) continue;
                // Kiểm tra giao dịch còn hạn hay không? Nếu không qua giao dịch tiếp theo
                if ((((new Date()).getTime() - (new Date(item.when)).getTime()) / 86400000) >= expiration_date) continue;
                // Bước quan trọng đây.
                // Sau khi có orderId Thì thực hiện thay đổi các trang thái giao dịch
                // Ví dụ như kiểm tra orderId có tồn tại trong danh sách các đơn hàng của bạn?
                // Sau đó cập nhật trạng thái theo orderId và amount nhận được: đủ hay thiếu tiền...
                // Và một số chức năng khác có thể tùy biến
            }
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }
    })
```

### Cảm ơn đã theo dõi


# Change log

Từ 01/09/2021 , Casso chính thức công bố API v2, bao gồm một số thay đổi:&#x20;

* Ra mắt Oauth 2
* Thay đổi cơ chế Api Keys

### 1/ Cơ chế Api Keys

Api keys ở v1 sẽ tương đương với authorization code. Api key v2 sẽ tương đương một access token (lifetime access token).

Với nâng cấp ở version 2 này,  Developer sẽ không cần phải gọi api /v1/token để đổi api key thành access token mà sử dụng access token này để authorize các api truy cập vào Casso  luôn.

Ở API v1, để gọi api /userInfo, bước 1 là bạn phải gọi api /token để đổi access token, sau đó dùng access token này gắn vào header để gọi api /userInfo

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v1/userInfo \
--header 'Authorization: <"Access token">'
```

Thì ở API /v2 , API key bạn đã tạo ra ở giao diện tích hợp của Casso sẽ được dùng trực tiếp để authen api luôn như ví dụ bên dưới.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"api_key_here">'
```

### 2/ Cơ chế OAuth 2.0&#x20;

Nếu như bạn nhận **`Access token`** từ việc xác thực ở OAuth 2.0 của Casso thì bạn có thể dùng **`Access token`** này gắn vào Authorization trên header để gọi với các API Resource của Casso tương ứng với [Version 2](/english-v2-new/casso-api/api/lay-thong-tin-user), kèm theo tiền tố là **`Bearer`**.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```


# Tổng quan

Chuyên trang dành cho lập trình viên

## Chào mừng bạn tới Casso Developer

Đây là nơi bạn có thể tìm thấy tất cả các tài liệu đặc tả, hướng dẫn, tài nguyên để **lập trình tích hợp** phần mềm của bạn với **Casso**

Casso được sinh ra với DNA là **bảo mật,  tự động hóa** và **tích hợp không giới hạn.** Chúng tôi coi **khả năng tích hợp** là giá trị cốt lõi của sản phẩm. Do đó, chúng tôi đã phát triển Casso theo hướng cung cấp đa dạng hình thức kết nối với các hệ thống phần mềm khác, phục vụ **nhiều mục đích** khác nhau.&#x20;

## Các phương pháp tích hợp

| Phương pháp                                                         | Mô tả                                                                                                                                                                                                                                                                                                                               |
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Thiết lập Webhook thủ công](/webhook/thiet-lap-webhook-thu-cong)   | <ul><li>Cấu hình thêm một <strong>webhook</strong> trên giao diện của Casso.</li><li>Mỗi khi tài khoản ngân hàng có một giao dịch mới, Casso sẽ <strong>bắn thông tin giao dịch</strong> vào webhook đã cấu hình, <a href="/pages/-MchBu0xMPRO7iRUlfzL">tham khảo tài liệu.</a></li></ul>                                           |
| [Tạo API Key  thủ công](/casso-api/chung-thuc/tao-api-key-thu-cong) | <ul><li>Dùng <strong>API Key</strong> để gọi các API của Casso. <strong>API Key</strong> sẽ được xem như là một <strong>Access token,</strong> chỉ khác nhau ở chỗ chỉ khi <strong>API Key</strong> bị xóa đi thì <strong>API Key</strong> này mới hết hạn, <a href="/pages/-MchCJYt6Wqz_h78ZhMR">tham khảo tài liệu.</a></li></ul> |

Hai phương pháp đầu là dành cho **người dùng cuối.** Là những doanh nghiệp, cá nhân đã sử dụng phần mềm **Casso** phục vụ nhu cầu quản lý thu chi. Và nay doanh nghiệp, cá nhân này cần tích hợp Casso vào hệ thống phần mềm khác mà doanh nghiệp cũng đang sử dụng.&#x20;

Phương pháp **OAuth 2.0** dành cho các **nhà phát triển phần mềm cho doanh nghiệp,** muốn tích hợp với Casso để cung cấp cho người dùng thêm lựa chọn **liên kết tài khoản Casso** vào phần mềm.

## Kế hoạch dự kiến

Bên cạnh 3 phương pháp tích hợp trên, chúng tôi cũng đang làm việc để triển khai phương pháp thứ 4, đó là phát triển một bộ thư viện tích hợp tương tự như **Plaid cho Việt Nam,** được cung cấp cho các **nhà phát triển** phần mềm dưới dạng **thư viện mã nguồn**.&#x20;

Bộ thư viện này sẽ giúp các đơn vị này phát triển **tính năng liên kết ngân hàng** của người dùng vào phần mềm của họ, một cách đơn giản và bảo mật. Người dùng phần mềm sẽ ko cần tạo tài khoản bên Casso mà liên kết ngân hàng ngay trên web, app của **nhà phát triển**. Và **Nhà Phát Triển** không cần phải lo lắng về vấn đề bảo mật cho tài khoản và dữ liệu của người dùng.

Chúng tôi dự kiến sẽ ra mắt chính thức trong vào đầu năm 2022. *Vui lòng liên hệ nếu bạn muốn tham gia vào chương trình dùng thử Beta Test của chúng tôi.*


# Thiết lập Webhook thủ công

Casso cho phép tích hợp với một Webhook API gọi tới server của bạn. Mỗi khi có giao dịch mới, Casso sẽ thực hiện gọi tới API bạn đã thiết lập sẵn để gửi thông tin giao dịch này.

{% hint style="success" %}
Nếu như Bạn cần giải pháp Xác nhận thanh toán, hãy dùng [payOS by Casso](https://payos.vn).

**payOS** là một giải pháp của Casso chuyên dụng dành cho việc xác nhận thanh toán, được phát triển bằng sự kết hợp các công nghệ VietQR , Virtual Account Number và Open Banking API.
{% endhint %}

## Mô hình hoạt động

Casso sử dụng webhook để thông báo cho ứng dụng của bạn khi có một giao dịch tiền vào hoặc tiền ra tài khoản ngân hàng của bạn.

Tích hợp Casso vào ứng dụng của bạn bằng webhook chỉ bao gồm 3 bước đơn giản

1. [**Lập trình** một webhook ](/webhook/gia-lap-giao-dich-den)endpoint để xử lý sự kiện webhook trên server của bạn
2. Giả lập giao dịch mới từ ngân hàng để **Test** và đảm bảo webhook endpoint của bạn chạy đúng.
3. Đăng kí URL của Webhook endpoint vào Casso và **Go live**.

![](/files/-MfTt-1ZvnJb0f78pD1p)

## Trước khi bắt đầu

Bạn cần phải:

* Tạo một tài khoản tại [Casso](https://casso.vn)
* Liên kết một tài khoản ngân hàng vào Casso

## Thiết lập webhook trong Casso

Đăng nhập vào tài khoản tại [casso.vn](https://casso.vn)&#x20;

Truy cập vào **Kết nối** > **Tích hợp** và ấn vào nút **Thêm tích hợp**

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

Trong danh sách **Chọn ứng dụng để tích hợp ,** chọn **Webhook** hoặc **Webhook V2.** Sẽ mở ra giao diện **Thêm tích hợp Webhook**:&#x20;

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

Ở mục **1. Chọn ngân hàng** :

* Bạn chọn tài khoản ngân hàng sẽ được theo dõi để bắn thông tin giao dịch.&#x20;
* Bạn có thể chọn Tất cả để Hệ thống **Casso** bắn giao dịch của tất cả các tài khoản ngân hàng đã liên kết.

Bạn nhấn nút **Tiếp tục** để chuyển sang bước **Thiết lập Webhook nhận dữ liệu:**

{% tabs %}
{% tab title="Webhook V2" %}

<figure><img src="/files/2dNHzOxW1PgHl13f1HV2" alt=""><figcaption></figcaption></figure>

Ở bước **Thiết lập :**

* Thông số **Webhook URL** sẽ là đường dẫn tới API endpoint của **hệ thống xử lý sự kiện webhook** trên web server của bạn.
* Thông số **Key bảo mật** là một chuỗi các ký tự ngẫu nhiên do Casso tự sinh ra cho mỗi tích hợp. Key bảo mật này sẽ dùng để tạo chữ ký số đối với dữ liệu của Webhook và một số thông tin khác. Bạn có thể kiểm tra header lấy thông tin chữ ký số để xác thực việc gọi vào Webhook URL là hợp lệ.

{% hint style="info" %}

* Nếu bạn cảm thấy Key bảo mật hiện tại không an toàn, bạn có thể nhấn nút rotate ở bên phải trường Key bảo mật để làm mới và Lưu lại tích hợp.&#x20;
* Tuy nhiên, hãy đảm bảo rằng tất cả sự kiện của Tích hợp Webhook V2 đã được xử lý thành công trước khi làm mới Key bảo mật. Nếu bạn làm mới Key bảo mật trong khi vẫn còn sự kiện chưa được xử lý, các sự kiện này vẫn sẽ dùng Key bảo mật cũ tạo chữ ký số.
  {% endhint %}
  {% endtab %}

{% tab title="Webhook" %}

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

Ở bước **Thiết lập :**

* Thông số **Webhook URL** sẽ là đường dẫn tới API endpoint của **hệ thống xử lý sự kiện webhook** trên web server của bạn.
* Thông số **Key bảo mật** chứa một mã bí mật  mà mỗi lần gọi vào **Webhook URL**, Casso sẽ đính kèm key bảo mật này vào trong HTTP Header. Bạn có thể kiểm tra header lấy thông tin mã bí mật để xác thực việc gọi vào Webhook URL là hợp lệ.
  {% endtab %}
  {% endtabs %}

{% hint style="danger" %}
Không sử dụng Webhook URL là **đường dẫn chỉ có thể truy cập tư mạng nội bộ** hoặc **localhost, 127.0.01, 192.160.1.x ...** Webhook URL buộc phải là một đường dẫn public trên Internet.
{% endhint %}

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

Ở bước **Cấu hình dữ liệu**, bạn cần thiết lập các tùy chọn **Gửi kèm thông tin số dư, Gửi kèm thông tin mã giao dịch, Strict mode** để Casso có thể gửi đầy đủ thông tin mà bạn cần qua webhook đồng thời xử lý phản hồi từ hệ thống của bạn một cách chính xác.

Bấm vào nút **Tiếp tục** để tới bước tiếp theo.

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

Bấm vào nút **Gọi thử**, để hệ thống Casso bắn một giao dịch test vào Webhook URL.&#x20;

Nếu Casso bắn Webhook URL thành công, tức là cấu hình của bạn đã hợp lệ. Lúc này bạn có thể bấm vào nút **Lưu** để hệ thống lưu lại cấu hình này.

{% hint style="info" %}
**Strict mode**: là bước kiểm tra nâng cao kết quả trả về, khi kết quả trả về status code là 200, thì Casso sẽ kiểm tra thêm 1 bước nữa trong JSON trả về **success : 1** hoặc **success: true**. Nếu là **0**/**false** thì hệ thống sẽ hiểu là fail và Casso sẽ gửi lại webhook. \
Nếu không bật strict mode thì khi nhận phản hồi status code 200 thì Casso sẽ hiểu là đã gửi webhook thành công.
{% endhint %}

{% hint style="success" %}
**MẸO** : Trong quá trình lập trình tích hợp, bên cạnh Webhook tùy chỉnh trỏ tới website của bạn, bạn có thể đăng kí thêm 1 webhook tùy chỉnh khác sử dụng các dịch vụ như **pipedream.com**, **webhook.site**, **ngrok.com** để debug nội dung Casso gửi vào Webhook URL
{% endhint %}

## Yêu cầu của Webhook URL

Casso sẽ thực hiện việc gọi API vào Webhook URL mỗi khi có giao dịch mới. Webhook URL sẽ cần phải đáp ứng các yêu cầu sau:

### Khả năng truy cập

* Phải là đường dẫn công khai có thể truy cập từ internet
* Đường dẫn sử dụng giao thức bảo mật **HTTPS**
* Nếu website sử dụng Cloudflare hoặc các dịch vụ ngăn chặn DDOS, lưu ý bạn phải whitelist IP của Casso.&#x20;

### Phản hồi khi thành công

Sau khi xử lý, webhook của bạn phải phản hồi với status code là **200 OK**. Và đáp ứng thời gian phản hồi dưới 5 giây ( Casso sẽ thiết lập timeout cho request POST bắn webhook là 5s)

### Xử lý các trường hợp thất bại.

Nếu quá trình bắn webhook thất bại vì một lý do nào đó, Casso sẽ gọi lại liên tục webhook trong 24 giờ sau đó, lần đầu gọi sẽ sau 1 phút và thời gian chờ này sẽ tăng lên thành giá trị [**Fibonacci**](https://vi.wikipedia.org/wiki/D%C3%A3y_Fibonacci) kế tiếp sau mỗi lần gọi lại thất bại.&#x20;

Tổng cộng, Casso sẽ gọi lại 1 sự kiện webhook nhiều nhất là 17 lần. Sau đó mới bỏ qua và chuyển sự kiện webhook qua trạng thái **Thất Bại** (FAIL).

Sau 24 giờ liên tục gọi webhook toàn thất bại, Casso sẽ chuyển cấu hình webhook sang trạng thái **Tạm Dừng** (PAUSED). Khi cấu hình webhook bị tạm dừng mà có giao dịch mới phát sinh, các sự kiện webhook này sẽ không được thực hiện mà được lưu lại với trạng thái là **Tạm Giữ** (HOLDING). Khách hàng sau khi fix lỗi của hệ thống xử lý sự kiện webhook thì có thể truy cập vào giao diện Casso để **thực hiện lại** (Replay) các sự kiện webhook này.

Sau 7 ngày cấu hình webhook bị tạm dừng mà không được xử lý, Casso sẽ chuyển cấu hình webhook sáng trạng thái Tắt (DISABLE). Các giao dịch xảy ra khi cấu hình webhook bị tắt sẽ không có khả năng thực hiện lại.

### Chống trùng lắp

Để chống lại phương pháp tấn công **Replay Attack**, Hệ thống xử lý sự kiện Webhook của bạn cần phải được xử lý chống trùng lặp thông qua kiểm tra xem một giao dịch mới đã được xử lý trước đây hay chưa? Mỗi giao dịch của Casso được định danh bởi một `id`. Với một webhook mới đến, bạn hãy kiểm tra xem `id` của giao dịch này đã được xử lý trước đây hay chưa, nếu đã có thì tức là giao dịch này đã bị Replay bởi một lý do nào đó, hãy bỏ qua nó.

### Xử lý hậu kiểm

Dù tỉ lệ có thể sẽ rất thấp, nhưng sẽ luôn có khả năng webhook thất bại, để tránh trường hợp bị sót giao dịch. Nhà phát triển có thể cân nhắc cung cấp tính năng **Tra soát toàn bộ giao dịch** bắng cách sử dụng API để tải về các giao dịch và kiểm tra xem có giao dịch nào sót không. Xem thêm ở mục [Tạo Auth code thủ công](/casso-api/chung-thuc/tao-api-key-thu-cong).

## Cấu trúc dữ liệu gửi qua Webhook

Casso sẽ bắn dữ liệu vào Webhook URL mà bạn đã khai báo, Dữ liệu định dạng JSON, trong đó trường data sẽ lưu thông tin giao dịch mới.

{% tabs %}
{% tab title="Webhook V2" %}

```json
{
    "error": 0,
    "data": {
        "id": 0, // Mã định danh duy nhất của giao dịch (Casso quy định)
        "reference": "BANK_REF_ID", // Mã giao dịch từ phía ngân hàng
        "description": "giao dich thu nghiem",  // Nội dung giao dịch
        "amount": 599000, // Số tiền giao dịch
        "runningBalance": 25000000, // Số dư sau giao dịch
        "transactionDateTime": "2025-02-12 15:36:21", // Thời gian giao dịch
        "accountNumber": "88888888", // Số tài khoản mà giao dịch thuộc về
        "bankName": "VPBank", // Tên ngân hàng
        "bankAbbreviation": "VPB", // Viết tắt tên ngân hàng
        "virtualAccountNumber": "", // Tài khoản ảo
        "virtualAccountName": "", // Tên tài khoản ảo
        "counterAccountName": "", // Tên tài khoản đối ứng
        "counterAccountNumber": "", // Tài khoản đối ứng
        "counterAccountBankId": "", // Mã ngân hàng đối ứng
        "counterAccountBankName": "" // Tên ngân hàng đối ứng
    }
}
```

{% endtab %}

{% tab title="Webhook" %}

```json
{
    "error": 0,
    "data": [
        {
            "id": 6785,        // Mã định danh duy nhất của giao dịch (Casso quy định)
            "tid": "BANK_REF_ID", // Mã giao dịch từ phía ngân hàng
            "description": "giao dich thu nghiem", // Nội dung giao dịch
            "amount": 79000, // Số tiền giao dịch
            "cusum_balance": 20079000,  // Số tiền còn lại sau giao dịch                 
            "when": "2020-10-14 00:34:57",    // Thời gian ghi có giao dịch ở ngân hàng
            "bank_sub_acc_id": "123456789",   // Mã tài khoản ngân hàng mà giao dịch thuộc về
            "subAccId" :  "123456789"       // Tương tự field bank_sub_acc_id, nhằm tương thích với code cũ
            "bankName" : "VPBank", // Tên ngân hàng
            "bankAbbreviation" : "VPB", // Viết tắt tên ngân hàng 
            "virtualAccount": "", // Tài khoản ảo
            "virtualAccountName": "", // Tên tài khoản ảo
            "corresponsiveName": "", // Tên tài khoản đối ứng
            "corresponsiveAccount": "", // Tài khoản đối ứng
            "corresponsiveBankId": "", // Mã ngân hàng đối ứng
            "corresponsiveBankName": "" // Tên ngân hàng đối ứng
        },
    
    ]
}
```

{% hint style="warning" %}
Lưu ý : Nếu có một giao dịch mới, Casso vẫn sẽ gửi qua một mảng chứa 1 phần tử giao dịch mới.&#x20;
{% endhint %}
{% endtab %}
{% endtabs %}

## Lập trình webhook

Một số tài nguyên ban có thể tham khảo để lập trình Module xử lý webhook **Webhook Event Handler.**

| STT | Tên                                                                                                              | Link                                                                                                   |
| --- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| 1   | Mã nguồn **Webhook Event Handler** sample viết bằng PHP                                                          | <https://github.com/CassoHQ/casso-webhook-handler-sample>                                              |
| 2   | Mã nguồn **Webhook Event Handler** sample viết bằng Java                                                         | *Đang cập nhật. Liên hệ chúng tôi*                                                                     |
| 3   | Mã nguồn **Webhook Event Handler** sample viết bằng NodeJS                                                       | *Đang cập nhật. Liên hệ chúng tôi*                                                                     |
| 4   | Mã nguồn chính thức của Plugin Woocommerce `Casso – Tự động xác nhận thanh toán chuyển khoản ngân hàng`          | <https://plugins.trac.wordpress.org/browser/casso-tu-dong-xac-nhan-thanh-toan-chuyen-khoan-ngan-hang/> |
| 5   | Mã nguồn **hướng dẫn tạo và xác thực chữ ký số Webhook V2** viết bằng Java, C#, JavaScript, PHP, Python, Golang. | <https://github.com/CassoHQ/casso-webhook-v2-verify-signature>                                         |

Hãy bắt đầu&#x20;


# Xử lý sự kiện Webhook

Hướng dẫn các bước lập trình một API xử lý sự kiện webhook. Có code mẫu bằng NodeJS

Tích hợp phương pháp webhook rất đơn giản, **tất cả mọi thứ bạn cần làm là lập trình một API xử lý sự kiện Webhook.** Sau khi bạn đã đăng kí URL của API này vào một [mục tích hợp webhook](/webhook/thiet-lap-webhook-thu-cong) trong Casso.

Mỗi khi Casso phát hiện tài khoản ngân hàng liên kết có một giao dịch mới, Casso sẽ gọi vào API này.

Hiện tại, Casso cung cấp 2 giải pháp nhận thông tin giao dịch là Webhook và Webhook V2. Chúng tôi khuyến khích bạn sử dụng tích hợp Webhook V2 để tăng khả năng bảo mật khi xác thực tính toàn vẹn của dữ liệu mà Casso gửi qua hệ thống của bạn cũng như đảm bảo rằng dữ liệu này được gửi trực tiếp từ Casso.

Đặc tả của API này là :&#x20;

## Xử lý giao dịch được gửi từ Casso

### Webhook V2

<mark style="color:green;">`POST`</mark> `https://websitecuaban.com/api/webhook-event-handler`

#### Headers

| Name              | Type   | Description                                                                                                                                                                                              |
| ----------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| X-Casso-Signature | string | Chữ ký số được tạo bởi dữ liệu webhook và một số thông tin khác (Sample code tạo và kiểm tra chữ ký số tại bài viết [Thiết lập Webhook thủ công](/webhook/thiet-lap-webhook-thu-cong#lap-trinh-webhook)) |

#### Request Body

| Name  | Type   | Description                          |
| ----- | ------ | ------------------------------------ |
| error | string | Mã lỗi.                              |
| data  | string | Object chứa thông tin giao dịch mới. |

{% tabs %}
{% tab title="200" %}

```json
{
    "error": 0,
    "data": {
        "id": 0,
        "reference": "MA_GIAO_DICH_THU_NGHIEM",
        "description": "giao dich thu nghiem",
        "amount": 599000,
        "runningBalance": 25000000,
        "transactionDateTime": "2025-02-12 15:36:21",
        "accountNumber": "88888888",
        "bankName": "VPBank",
        "bankAbbreviation": "VPB",
        "virtualAccountNumber": "",
        "virtualAccountName": "",
        "counterAccountName": "NGUYEN VAN A",
        "counterAccountNumber": "8888888888",
        "counterAccountBankId": "970415",
        "counterAccountBankName": "VietinBank"
      }
}
```

{% endtab %}
{% endtabs %}

### Webhook

<mark style="color:green;">`POST`</mark> `https://websitecuaban.com/api/webhook-event-handler`

#### Headers

<table><thead><tr><th width="250">Name</th><th width="255">Type</th><th>Description</th></tr></thead><tbody><tr><td>secure-token</td><td>string</td><td>Key bảo mật để xác thực Webhook được gọi từ Casso</td></tr></tbody></table>

#### Request Body

| Name  | Type   | Description                       |
| ----- | ------ | --------------------------------- |
| error | string | Mã lỗi.                           |
| data  | string | Mảng danh sách các giao dịch mới. |

{% tabs %}
{% tab title="200 " %}

```json

{
    "error": 0,
    "data": [
        {
            "id": 6785,
            "tid": "BANK_REF_ID",
            "description": "giao dich thu nghiem",
            "amount": 79000,
            "cusum_balance": 2007900,                
            "when": "2020-10-14 00:34:57",
            "bank_sub_acc_id": "123456789",
            "subAccId" :  "123456789",
            "bankName" : "VPBank",
            "bankAbbreviation" : "VPB", 
            "virtualAccount": "",
            "virtualAccountName": "",
            "corresponsiveName": "",
            "corresponsiveAccount": "",
            "corresponsiveBankId": "",
            "corresponsiveBankName": ""
        },
    
    ]
}



```

{% endtab %}
{% endtabs %}

## Code

Bạn có thể sử dụng bất kì ngôn ngữ nào hỗ trợ xây dựng  restful API để Code.

Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:&#x20;

* Tạo dự án Restful API mới (Nodejs Express / Java Spring Boot / PHP single file, ...)
* Test in ra được helloword!
* Tạo controller mới xử lý một Post tên là /webhook-event-handler&#x20;
* Test : Dùng Curl Post một giao dịch mô phỏng lên /webhook-event-handler  và chỉnh code để in ra đúng được nội dung gửi lên (xem thêm phần Test bên dưới)
* Rút trích nội dung giao dịch
* Xử lý nội dung giao dịch
* Phản hồi HTTP status code 200 OK

Ví dụ bên dưới viết bằng NodeJS, log ra số giao dịch Webhook Api nhận dc. Bằng cách chỉnh sửa vài dòng  [ Hello World Sample của Node JS Express](https://expressjs.com/en/starter/hello-world.html)

{% code title="app.js" %}

```javascript
const express = require('express')
const app = express()
const port = 8080

app.use(express.json());
app.post('/api/webhook-event-handler', (req, res) => {
    let error = req.body.error;
    if (error != 0) {
        //Không làm gì cả.
        return;
    }
    
    //mảng chứa danh sách các giao dịch
    let transactions = req.body.data;
    
    console.log(`Received ${transactions.length} transactions`);
    
    //thêm code xử lý giao dịch ở đây.
    
    res.end("OK");
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
```

{% endcode %}

Bạn có thể xem thêm cách code một [API xử lý sự kiện webhook cho tính năng Tích hợp xác nhận thanh toán](/tai-nguyen-khac/tich-hop-xac-nhan-thanh-toan)

## Tạo sự kiện webhook để test

Có 5 cách để giả lập giao dịch gửi vào API xử lý webhook bạn đang code như sau:

| STT | Môi trường     | Phương pháp                                                           |
| --- | -------------- | --------------------------------------------------------------------- |
| 1   | Local          | Tự gọi API bằng Curl  / Postman                                       |
| 2   | Local          | Sử dụng ngrok để dẫn (pipe) webhook về local                          |
| 3   | Dev \| Staging | Nút Gọi Thử Trong giao diện setup Webhook                             |
| 4   | Dev \| Staging | Nút đồng bộ giao dịch ngay trong giao diện 1 Tài khoản ngân hàng Demo |
| 5   | Live           | Link tài khoản thật & tạo 1 lệnh chuyển tiền                          |

Tuy nhiên, chúng tôi khuyến cáo bạn hãy viết và test thật kĩ trên Local trước , và test nhanh bằng Postman hoặc Curl.&#x20;

### Sử dụng ngrok để public Webhook ở Local

[Ngrok](https://ngrok.com/) là một ứng dụng tạo ra một đường hầm từ máy bạn (desktop, localhost) đi qua hệ thống Firewall/Nat, giúp từ internet có thể truy cập vào máy trạm.

Nếu như bạn đang chạy server ở local port **8080**, ở **terminal**, bạn nhập: **ngrok http 8080**.

{% hint style="info" %}
Một url có thể khả dụng trong 8 giờ.

Chỉ sử dụng **https\://**

Bạn có thể sử dụng giao diện web của [Ngrok](https://ngrok.com/) để xêm lưu lượng HTTP request và response qua hệ thống của bạn: <http://localhost:8080>
{% endhint %}

### Sử dụng Curl để test

Copy nội dung bên dưới, sau khi đã fix lại đường dẫn API xử lý webhook

Mở terminal&#x20;

{% tabs %}
{% tab title="Webhook V2 Curl" %}

```bash
curl --location --request POST 'http://localhost:8080/api/webhook-event-handler' \
--header 'X-Casso-Signature: t=1727948258788,v1=ed0a4bd2e826d5cb69988cdb141e6c1a080e21f3b57eb72cd78192220042b9e7dde0868fc667faea8e224900fa7904e7c88dfa098032fb2d6b6996856e8b7ff3' \
--header 'Content-Type: application/json' \
--data-raw '{
    "error": 0,
    "data": {
        "id": 0,
        "reference": "MA_GIAO_DICH_THU_NGHIEM",
        "description": "giao dich thu nghiem",
        "amount": 599000,
        "runningBalance": 25000000,
        "transactionDateTime": "2024-10-03 15:06:37",
        "accountNumber": "88888888",
        "bankName": "VPBank",
        "bankAbbreviation": "VPB",
        "virtualAccountNumber": "",
        "virtualAccountName": "",
        "counterAccountName": "NGUYEN VAN A",
        "counterAccountNumber": "8888888888",
        "counterAccountBankId": "970415",
        "counterAccountBankName": "VietinBank"
    }
}'
```

Paste & Enter

{% hint style="info" %}
Đây là dữ liệu mẫu để bạn có thể hình dung cách mà Casso sẽ truyền thông tin giao dịch, chữ ký số khi gọi API sang hệ thống xử lý sự kiện Webhook của bạn. Header X-Casso-Signature được tạo dựa trên thông tin giao dịch trong data-raw và Key bảo mật của Tích hợp Webhook V2. Để tìm hiểu thêm về phương pháp tạo và xác thực chữ ký số, vui lòng tham khảo [Thiết lập Webhook thủ công](/webhook/thiet-lap-webhook-thu-cong#lap-trinh-webhook)
{% endhint %}

{% hint style="info" %}
Lưu ý: \
Trường transactionDateTime có thể có hoặc không có giờ phút giây, tùy thuộc vào ngân hàng.

Ví dụ : ACB thì transactionDateTime sẽ là "2020-11-02 00:00:00", còn VietinBank thì transactionDateTime sẽ là "2020-11-02 11:50:30"
{% endhint %}
{% endtab %}

{% tab title="Webhook Curl" %}

```bash
curl --location --request POST 'http://localhost:8080/api/webhook-event-handler' \
--header 'secure-token: eogrBiWqaq' \
--header 'Content-Type: application/json' \
--data-raw '{
    "error": 0,
    "data": [
        {
            "id" : 1, 
            "when": "2020-11-02 11:50:30",
            "amount": 200500,
            "description": "DH35",
            "cusum_balance": 15900500,
            "tid": "TF80307914",
            "subAccId": "123456789",
            "bank_sub_acc_id": "123456789",
            "virtualAccount": "",
            "virtualAccountName": "",
            "corresponsiveName": "",
            "corresponsiveAccount": "",
            "corresponsiveBankId": "",
            "corresponsiveBankName": ""
        }
    ]
}'
```

Paste & Enter

{% hint style="info" %}
Lưu ý: \
Trường when có thể có hoặc không có giờ phút giây, tùy thuộc vào ngân hàng.

Ví dụ : ACB thì when sẽ là "2020-11-02 00:00:00", còn vietinbank thì when sẽ là "2020-11-02 11:50:30"
{% endhint %}
{% endtab %}
{% endtabs %}

## Phát hành

* Release dự án lên internet
* Cập nhật lại Webhook URL trong cấu hình webhook
* Link môt tài khoản ngân hàng thật
* Chuyển tiền vào tài khoản ngân hàng (5,000 , 10,000 thôi)
* Xác nhận rằng Casso đã gọi qua Webhook và xử lý thành công

Và \
... Xin chúc mừng. **Bạn đã hoàn tất!!!!**\
\
Chúng tôi ở đây để làm cho thế giới đơn giản hơn. ^^


# Chứng thực API

Các phương pháp chứng thức với API của Casso.

## Các phương pháp chứng thực

| Phương pháp                                            | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [API Key ](/casso-api/chung-thuc/tao-api-key-thu-cong) | <ul><li>Dùng <strong>API Key</strong> để gọi các API của Casso. <strong>API Key</strong> sẽ được xem như là một <strong>Access token,</strong> chỉ khác nhau ở chỗ chỉ khi <strong>API Key</strong> bị xóa đi thì <strong>API Key</strong> này mới hết hạn, <a href="/pages/-MchCJYt6Wqz_h78ZhMR">tham khảo tài liệu này</a>.</li></ul>                                                                                                                                                                                                                                                                                                                                                   |
| [OAuth 2.0](broken://pages/-MchCrnygNiqB1UgtiJK)       | <ul><li>Cơ chế chứng thực <strong>OAuth 2.0</strong> cho phép <strong>người dùng cuối</strong> tự động phân quyền cho <strong>Nhà Phát Triển</strong> truy cập thông tin tài khoản của họ tại Casso.</li><li>Sau khi người dùng thực hiện quy trình phân quyền trên phần mềm của <strong>Nhà Phát Triển</strong>, thì một Authorization Code sẽ được tự động sinh ra.</li><li><strong>Nhà Phát triển</strong> sử dụng Authorization Code này gọi tới hệ thống Oauth 2.0 của Casso để lấy <strong>Access token</strong>. Sau đó dùng <strong>Access token</strong> mới nhận được để gọi tới các API của Casso, <a href="/pages/-MchCrnygNiqB1UgtiJK">tham khảo tài liệu này.</a></li></ul> |

[Phương pháp **API Key**](/casso-api/chung-thuc/tao-api-key-thu-cong) dành cho **người dùng cuối.** Là những doanh nghiệp, cá nhân đã sử dụng phần mềm **Casso** phục vụ nhu cầu quản lý thu chi. Và nay doanh nghiệp, cá nhân này cần tích hợp Casso vào hệ thống phần mềm khác mà doanh nghiệp cũng đang sử dụng.&#x20;

[Phương pháp **OAuth 2.0** ](broken://pages/-MchCrnygNiqB1UgtiJK)dành cho các **nhà phát triển phần mềm cho doanh nghiệp,** muốn tích hợp với Casso để cung cấp cho người dùng thêm lựa chọn **liên kết tài khoản Casso** vào phần mềm.

### Ví dụ với API Key:

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"API Key của bạn">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

### Ví dụ với Access token từ OAuth 2.0 Casso:

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer <"Access token nhận được từ OAuth 2.0 của Casso">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Nếu như các bạn đã có các thông tin ở trên như: **API Key**, **access token** từ [Oauth 2.0 Casso](broken://pages/-MchCrnygNiqB1UgtiJK). Các bạn đã có thể sử dụng các thông tin đó với [danh sách API của Casso.](/casso-api/api)
{% endhint %}


# Tạo API Key thủ công

Auth code được dùng để lấy access token cho phép ứng dụng bên ngoài truy cập và lấy thông tin trên hệ thống Casso.

## Cách tạo API Key&#x20;

Truy cập vào **Thiết lập** > **Api Keys** > **Tạo API Key > Tạo và xem API Key**

![](/files/-Me8f6FpQ-xh0BpS1Vlo)

## Cách sử dụng với API Key mới tạo

Nếu như các bạn đã quen với `v1` thì ở `v2` Casso đã bỏ đi bước [gọi lấy token](broken://pages/-MchBzabvDdqOWufUMb_) và Casso sẽ xem `API Key` này đầy đủ chức năng như là một `access token`. Điểm khác của `API Key` so với `access token` là  sẽ không có thời gian hết hạn và tiền tố  là **`<"Apikey">`** lúc bạn thêm `API Key` vào trường Authorization trên HTTP header. Ngoại trừ việc bạn xóa nó đi thì API Key đó được xem như là hết hạn. Để có thể biết cách hoạt động của API Key chúng ta sẽ xem một ví dụ ở dưới với [API lấy thông tin user v2](/casso-api/api/lay-thong-tin-user):

#### Ví dụ:

{% tabs %}
{% tab title="CURL" %}

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"API Key của bạn"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

Ở ví dụ trên, bạn sẽ thấy ở phần `header` chúng tôi sẽ sử dụng **`API Key`** trong trường `Authorization` kèm theo đó phía trước **`API Key`** mà bạn tạo sẽ có tiền tố `Apikey`. Với tiền tố này Casso sẽ phân biệt nó với **`access token`** mà bạn nhận được từ OAuth 2.0 của Casso.

{% hint style="info" %}
Với những API còn lại bạn đều có thể sử API Key để thay thế cho Access token, như [API lấy giao dịch](/casso-api/api/lay-giao-dich), [API thiết lập webhook](/casso-api/api/thiet-lap-webhook), ...
{% endhint %}

{% hint style="info" %}
Lưu ý: Những API Key mới được tạo ra sau ngày 31/08/2021 sẽ không thể chạy trên các [API v1](broken://pages/-MeB7KQQcxVvlhajVnKA), những API Key này chỉ chạy được trên [API v2](/casso-api/api/lay-thong-tin-user).
{% endhint %}


# Danh sách API

Danh sách các API của Casso

## Trước khi bắt đầu

Để có thể bắt đầu với các API sau yêu cầu các bạn chuẩn bị:

* Một tài khoản [Casso](https://my.casso.vn), đã liên kết một tài khoản ngân. Bạn có thể sử dụng tài [khoản ngân hàng Demo này.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Chọn một trong [phương pháp chứng thực API.](/casso-api/chung-thuc)

{% hint style="info" %}
Bạn có thể sử dụng một trong hai phương pháp chứng thức API của Casso đó là [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) và [Oauth 2.0](broken://pages/-MchCrnygNiqB1UgtiJK) để có thể sử dụng với các API dưới.
{% endhint %}

## Bảng danh sách các API

| API                                                         | Mô tả                                                                                            |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [Thông tin user](/casso-api/api/lay-thong-tin-user)         | Lấy thông tin chi tiết của tài khoản như: email, tên doanh nghiệp, danh sách liên kết ngân hàng. |
| [Thiết lập Webhook](/casso-api/api/thiet-lap-webhook)       | Thiết lập Webhook như: thêm, sửa và xóa                                                          |
| [Giao dịch ngân hàng](/casso-api/api/lay-giao-dich)         | Lấy giao dịch ngân hàng                                                                          |
| [Đồng bộ giao dịch mới](/casso-api/api/check-giao-dich-moi) | Gọi đồng bộ giao dịch mới với tài khoản tương ứng                                                |

{% hint style="info" %}
Lưu ý: Ở phần Authorization HTTP Header của các API trên, bạn phải sử dụng tiền tố phú hợp với mỗi kết quả từ các [phương thức chứng thực](/casso-api/chung-thuc). Như với [chứng thực API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) bạn phải sử dụng tiền tố **`Apikey + API key của bạn,`** với access token từ [Oauth 2.0 của Casso ](broken://pages/-MchCrnygNiqB1UgtiJK)bản phải sử dụng tiền tố là **`Bearer + access token nhận được từ Oauth 2.0.`**
{% endhint %}

{% hint style="success" %}
Mẹo hay với [API đồng bộ giao dịch](/casso-api/api/check-giao-dich-moi) mới đối với các doanh nghiệp/cá nhân bán hàng trực tuyến. Bạn có thể [xem chi tiết ở đây.](/tai-nguyen-khac/tich-hop-xac-nhan-thanh-toan)
{% endhint %}


# API lấy thông tin user

Dùng để lấy thông tin người dùng như: thông tin tài khoản, thông tin doanh nghiệp, danh sách các ngân hàng liên kết.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) để thiết lập ở trường Authorization HTTP Header.

## Lấy thông tin user

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/userInfo`

Lấy chi tiết thông tin tài khoản như: email, thông tin doanh nghiệp và thông tin tài khoản ngân hàng liên kết.

#### Headers

| Name          | Type   | Description                                                           |
| ------------- | ------ | --------------------------------------------------------------------- |
| Authorization | string | `Bearer <access token từ Oauth2>` **hoặc** `Apikey <API key của bạn>` |

{% tabs %}
{% tab title="200 Cake successfully retrieved." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "user": {
            "id": 1553,
            "email": "haonh@magik.vn"
        },
        "business": {
            "id": 1540,
            "name": "Hữu Hảo"
        },
        "bankAccs": [
            {
                "id": 69,
                "bank": {
                    "bin": 970416,
                    "codeName": "acb_digi"
                },
                "bankAccountName": null,
                "bankSubAccId": "17271687",
                "connectStatus": 1,
                "planStatus": 1
            },
            {
                "id": 63,
                "bank": {
                    "bin": 970454,
                    "codeName": "timoplus"
                },
                "bankAccountName": null,
                "bankSubAccId": "8007041023848",
                "connectStatus": 1,
                "planStatus": 0
            }
        ]
    }
}
```

{% endtab %}

{% tab title="401 Could not find a cake matching this query." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo' \
--header 'Authorization: Apikey <API Key của bạn> hoặc Bearer <access token từ OAuth2>'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/userInfo",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/userInfo")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

Ví dụ mẫu

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo' \
--header 'Authorization: Apikey AK_CS.0cf673d0406711ecb6579fe89ca48437.WT2EHXBpzTFpA2XBBJzuBJSGkIPJxtM8ShgSe059Wh2SDKmAkoueFdkqnjZJrUnEXj2F2CX2'
```

Kết quả trả về

```json
{
    "error": 0,
    "message": "success",
    "data": {
        "user": {
            "id": 1,
            "email": "demo@casso.vn"
        },
        "business": {
            "id": 1009,
            "name": "VinDemo"
        },
        "bankAccs": [
            {
                "id": 87,
                "bank": {
                    "bin": 970436,
                    "codeName": "vietcombank"
                },
                "bankAccountName": null,
                "bankSubAccId": "123456789",
                "balance": 64875755,
                "memo": "VCB NGUYEN VAN A23",
                "connectStatus": 1,
                "planStatus": 2
            }
            //... các tài khác tiếp theo
        ]
    }
}
```

{% hint style="success" %}
Mẹo: Bạn có thể sử dụng thông tin phản hồi của API này trong trường **`bankAccs`** để có thể tạo cho mình các mã [VietQR code ](https://www.vietqr.io/)tương ứng với các thông tin phản hồi này.
{% endhint %}


# API thiết lập webhook

Dùng để thiết lập webhook như: thêm, sửa và xóa.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có một endpoint/API để nhận sự kiện từ Casso đây được gọi là [Webhook](https://en.wikipedia.org/wiki/Webhook).
* Endpoint/API này phải public ra ngoài Internet. Nếu như bạn đang ở **local** bạn có thể [xem hương dẫn này](/webhook/gia-lap-giao-dich-den#su-dung-ngrok-de-public-webhook-o-local) để biết cách public endpoint của bạn.
* Bạn cần có [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) để thiết lập ở trường Authorization HTTP Header.

## Tạo webhook

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v2/webhooks`

Thực hiện tạo webhook tới server của bạn

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

#### Request Body

| Name          | Type    | Description                                                                      |
| ------------- | ------- | -------------------------------------------------------------------------------- |
| income\_only | boolean | Giá trị được thiết lập để gửi bắn sự kiện tới webhook đối với giao dịch tiền vào |
| secure\_token | string  | Mã bảo mật để mỗi lần gửi Event từ Casso sẽ được đính kèm trên header.           |
| webhook       | string  | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso             |

{% tabs %}
{% tab title="200 Response thông tin webhook đã tạo thành công." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 114,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạn." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request POST 'https://oauth.casso.vn/v2/webhooks' \
--header 'Authorization: Apikey <API Key của bạn> hoặc Bearer <access token từ OAuth2>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
    "secure_token": "@123#abc",
    "income_only": true
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'webhook' => 'https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php',
  'secure_token' => '@123#abc',
  'income_only' => true
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("webhook", "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php")
  .add("secure_token", "@123#abc")
  .add("income_only", true)
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xem chi tiết webhook

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Xem chi tiết các thông về webhook của bạn theo dựa theo `webhook Id`

#### Path Parameters

| Name | Type   | Description                        |
| ---- | ------ | ---------------------------------- |
| id   | string | `id webhook` bạn muốn xem chi tiết |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com.vn/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/webhooks/134' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/134",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/134")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Cập nhật một webhook

<mark style="color:orange;">`PUT`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Cập nhật các thông tin trong webhook đã được thiết lập trước đó

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

#### Request Body

| Name          | Type    | Description                                                          |
| ------------- | ------- | -------------------------------------------------------------------- |
| income\_only  | boolean | Xác nhận gửi webhook đối với tiền vào                                |
| secure\_token | string  | mã bảo mật                                                           |
| webhook       | string  | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://webhook-cua-ban.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request PUT 'https://oauth.casso.vn/v2/webhooks/111' \
--header 'Authorization: Apikey <API Key của bạn> Hoặc Bearer <access token từ OAuth2>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/api/bank",
    "secure_token": "@xyz@123",
    "income_only": "false"
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'webhook' => 'https://ten-mien-cua-ban.com/api/bank'
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/111",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "PUT",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("webhook", "https://ten-mien-cua-ban-new.com/wc-new/handler-bank-transfer.php")
  .add("secure_token", "@123#abc-new")
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/111")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xoá một webhook

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v2/webhooks/:id`

Thực hiện xóa một webhook bằng `id webhook` &#x20;

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://khanh-dep-trai.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request DELETE 'https://oauth.casso.vn/v2/webhooks/85' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks/85",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "DELETE",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks/85")
  .delete()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## &#x20;Xoá tất cả webhook trong đường dẫn &#x20;

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v2/webhooks`

Xóa tất cả các webhook đang tồn tại trong doanh nghiệp của bạn trên Casso tương ứng với giá trị webhook mà bạn yêu cầu.

#### Query Parameters

| Name    | Type   | Description                                                          |
| ------- | ------ | -------------------------------------------------------------------- |
| webhook | string | Đường dẫn(endpoint/API) nhận event(phát sinh giao dịch mới) từ Casso |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ OAuth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": [
        {
            "id": 108,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 109,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 110,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
    ]
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}

{% tab title="404 " %}

```
{
    "error": 12,
    "message": "Webhook not exists",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request DELETE 'https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "DELETE",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/webhooks?webhook=https://websitecuaban.com/api/webhook")
  .delete()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
Lưu ý: Khi bạn gọi API có thể sẽ xóa đi những webhook cũ mà bạn đã thiết lập trên hệ thống của Casso. Cân nhắc trước khi dùng tới API này.
{% endhint %}


# API lấy giao dịch

Dùng để lấy một hoặc nhiều giao dịch ngân hàng

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) để thiết lập ở trường Authorization HTTP Header.

## &#x20;Lấy giao dịch ngân hàng &#x20;

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/transactions`

API này cho phép lấy toàn bộ thông tin giao dịch ngân hàng.

#### Query Parameters

| Name     | Type    | Description                                                                             |
| -------- | ------- | --------------------------------------------------------------------------------------- |
| sort     | string  | Sắp xếp tăng hoặc giảm dần dựa theo thời gian của giao dịch. Mặc định là ASC(tăng dần). |
| pageSize | string  | Số lượng giao dịch trên một trang                                                       |
| page     | integer | Số thứ tự của trang                                                                     |
| fromDate | string  | Lấy giao dịch bắt đầu từ ngày. Định dạng: YYYY-MM-                                      |

#### Headers

| Name          | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| Authorization | string | `Bearer <"access token từ Oauth2">` **hoặc** `Apikey <"API key của bạn">` |

{% tabs %}
{% tab title="200 Response chi tiết các giao dịch ngân hàng" %}
{% tabs %}
{% tab title="Response theo page" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "page": 4,
        "pageSize": 10,
        "nextPage": 5,
        "prevPage": 3,
        "totalPages": 35,
        "totalRecords": 341,
        "records": [
            {
                "id": 5789,
                "tid": "TF2104152395814062",
                "description": "Khanhnm chuyen tien",
                "amount": -193000,
                "cusum_balance": 1070904,
                "when": "2021-04-15T00:00:00",
                "bankSubAccId": "8007041027107",
                "paymentChannel": "",
                "virtualAccount": "",
                "virtualAccountName": "",
                "corresponsiveName": "",
                "corresponsiveAccount": "",
                "corresponsiveBankId": "",
                "corresponsiveBankName": "",
                "accountId": 733,
                "bankCodeName": "acb_digi"
            },
            {
                "id": 5790,
                "tid": "TF2104152997602811",
                "description": "Chuyen tien nap momo",
                "amount": -350000,
                "cusum_balance": 720904,
                "when": "2021-04-15T00:00:00",
                "bankSubAccId": "8007041027107",
                "paymentChannel": "",
                "virtualAccount": "",
                "virtualAccountName": "",
                "corresponsiveName": "",
                "corresponsiveAccount": "",
                "corresponsiveBankId": "",
                "corresponsiveBankName": "",
                "accountId": 733,
                "bankCodeName": "acb_digi"
            },
        ]
    }
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạ" %}

```
```

{% endtab %}
{% endtabs %}

#### Chi tiết các tham số

| Tham số        | Mô tả                                                                                    | Gá trị mặc định |
| -------------- | ---------------------------------------------------------------------------------------- | --------------- |
| ***fromDate*** | Thời gian bắt đầu bạn muốn lấy giao dịch                                                | 7 ngày gần nhất |
| **toDate**     | Thời gian kết thúc bạn muốn lấy giao dịch                                                | Hôm nay         |
| ***page***     | Số thứ tự trang                                                                          | 1               |
| ***pageSize*** | Số giao dịch trên một trang                                                              | 10              |
| ***sort***     | Sắp xếp giao dịch, các giá trị gồm: ASC, DESC. Với ASC là tăng dần còn DESC là giảm dần. | ASC             |

{% hint style="info" %}
Nếu tham số nào không tồn tại thì sẽ lấy giá trị mặc định.
{% endhint %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&toDate=2022-07-05&page=4&pageSize=20&sort=ASC' \
--header 'Authorization: Apikey <API Key của bạn> hoặc Bearer <access token từ OAuth2>'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## Lấy chi tiết một giao dịch

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/transactions/:id`

API cho phép bạn xem chi tiết của một giao dịch ngân hàng.

#### Path Parameters

| Name | Type   | Description                          |
| ---- | ------ | ------------------------------------ |
| id   | number | ID của giao dịch trên hệ thống Casso |

#### Headers

| Name          | Type   | Description                                                |
| ------------- | ------ | ---------------------------------------------------------- |
| Authorization | string | `Bearer` + `access token nhận được từ OAuth 2.0 của Casso` |

{% tabs %}
{% tab title="200 Thông tin chi tiết của 1 giao dịch" %}

<pre><code>{
    "error": 0,
    "message": "success",
    "data": {
        "id": 314344,
        "tid": "TF210702253136879",
        "description": "DH220",
        "amount": -10000,
        "cusumBalance": 389460,
        "when": "2021-07-02T12:50:00",
        "bankSubAccId": "8007041023848",
        "paymentChannel": "",
        "virtualAccount": "",
        "virtualAccountName": "",
        "corresponsiveName": "",
        "corresponsiveAccount": "",
        "corresponsiveBankId": "",
        "corresponsiveBankName": "",
<strong>        "accountId": 733,
</strong>        "bankCodeName": "acb_digi"
    }
}
</code></pre>

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/transactions/123 \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/transactions/12",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/transactions/12")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Lưu ý về giới hạn gọi API Danh sách giao dịch:

* Gói **SPONSOR**: 2 yêu cầu/phút
* Gói **PIONEER**: 5 yêu cầu/phút
* Gói **STANDARD**: 20  yêu cầu/phút
  {% endhint %}


# API lấy thông tin tài khoản ngân hàng

Truy vấn một hoặc nhiều tài khoản ngân hàng đã kết nối và danh sách giao dịch của tài khoản đó.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **có thể** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) để thiết lập ở trường Authorization HTTP Header.

## Danh sách tài khoản ngân hàng

## Lấy danh sách các tài khoản ngân hàng

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/accounts`

Truy vấn danh sách các tài khoản ngân hàng đã liên kết

#### Headers

| Name                                            | Type   | Description                                                                                                                |
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | <p><code>Bearer <"access token từ Oauth2"></code> <strong>hoặc</strong> </p><p><code>Apikey <"API key của bạn"></code></p> |

{% tabs %}
{% tab title="200: OK Thành công" %}

```javascript
{
    "error": 0,
    "message": "Successful",
    "data": [
        {
            "id": 123,
            "accountNumber": "8007041027107",
            "accountName": "NGUYEN MINH KHANH",
            "accountType": "",
            "balance": 0,
            "currency": "VND",
            "swift": "",
            "citad": "",
            "serviceType": "personal",
            "bankName": "Timo Plus by Viet Capital Bank",
            "BIN": 970454,
            "bankCodeName": "timoplus",
            "memo": "",
            "connectStatus": 1,
            "beginningSettingDate": "2020-08-01",
            "beginningTxnDate": null,
            "beginningBalance": 0,
            "creditTxnTotal": 546403683,
            "creditTxnAmount": 0,
            "debitTxnTotal": 0,
            "debitTxnAmount": 0,
            "lockSyncDate": null,
            "endingBalance": 0,
            "endingTxnDate": "2023-01-05T00:00:00Z"
        },
        ...
    ]
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/accounts \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/accounts",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/accounts")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## Chi tiết tài khoản ngân hàng

## Chi tiết tài khoản ngân hàng

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/accounts/:accountId`

Truy vấn chi tiết tài khoản ngân hàng đã liên kết.

#### Path Parameters

| Name                                        | Type   | Description                          |
| ------------------------------------------- | ------ | ------------------------------------ |
| accountId<mark style="color:red;">\*</mark> | Number | Mã định danh của tài khoản ngân hàng |

#### Headers

| Name                                            | Type   | Description                                                                                                                |
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | <p><code>Bearer <"access token từ Oauth2"></code> <strong>hoặc</strong> </p><p><code>Apikey <"API key của bạn"></code></p> |

{% tabs %}
{% tab title="200 Thành công" %}

```
{
    "error": 0,
    "message": "Successful",
    "data": {
        "id": 122,
        "accountNumber": "8007041027107",
        "accountName": "NGUYEN MINH KHANH",
        "accountType": "",
        "balance": 123,
        "currency": "VND",
        "swift": "",
        "citad": "",
        "serviceType": "personal",
        "bankName": "Timo Plus by Viet Capital Bank",
        "BIN": 970454,
        "bankCodeName": "timoplus",
        "memo": "",
        "connectStatus": 1,
        "beginningSettingDate": "2020-08-01",
        "beginningTxnDate": null,
        "beginningBalance": 0,
        "creditTxnTotal": 546403683,
        "creditTxnAmount": 0,
        "debitTxnTotal": 0,
        "debitTxnAmount": 0,
        "lockSyncDate": null,
        "endingBalance": 0,
        "endingTxnDate": "2023-01-05T00:00:00Z"
    }
}
```

{% endtab %}

{% tab title="401 Unauthorized" %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/accounts/123 \
--header 'Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2"'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/accounts/123",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/accounts/123")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

## Danh sách giao dịch ngân hàng

## &#x20;Danh sách giao dịch của một tài khoản ngân hàng

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v2/accounts/:accountId/transactions`

Truy vấn danh sách giao dịch ngân hàng của một tài khoản đã liên kết.

#### Path Parameters

| Name                                        | Type   | Description            |
| ------------------------------------------- | ------ | ---------------------- |
| accountId<mark style="color:red;">\*</mark> | Number | Mã định danh tài khoản |

#### Query Parameters

| Name     | Type   | Description                                                                             |
| -------- | ------ | --------------------------------------------------------------------------------------- |
| sort     | String | Sắp xếp tăng hoặc giảm dần dựa theo thời gian của giao dịch. Mặc định là ASC(tăng dần). |
| pageSize | String | Số lượng giao dịch trên một trang                                                       |
| page     | Number | Số thứ tự của trang                                                                     |
| fromDate | String | Lấy giao dịch ngày bắt đầu. Định dạng: YYYY-MM-DD                                       |
| toDate   | String | Lấy giao dịch ngày kết thúc. Định dạng: YYYY-MM-DD                                      |

#### Headers

| Name                                            | Type   | Description                                                                                                                |
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | <p><code>Bearer <"access token từ Oauth2"></code> <strong>hoặc</strong> </p><p><code>Apikey <"API key của bạn"></code></p> |

{% tabs %}
{% tab title="200 Thành công" %}
{% tabs %}
{% tab title="Response theo page" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "page": 4,
        "pageSize": 10,
        "nextPage": 5,
        "prevPage": 3,
        "totalPages": 35,
        "totalRecords": 341,
        "records": [
            {
                "privateId": 199,
                "reference": "TF2104042",
                "bookingDate": "2021-04-04",
                "transactionDate": "2021-04-04",
                "transactionDateTime": "2021-04-04T21:10:00Z",
                "amount": -1000000,
                "description": "RUT TM TU ATM",
                "runningBalance": 23502022,
                "virtualAccountNumber": "",
                "virtualAccountName": "",
                "paymentChannel": "",
                "counterAccountNumber": "",
                "counterAccountName": "",
                "counterAccountBankId": "",
                "counterAccountBankName": ""
            },
            ...
        ]
    }
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Unauthorized" %}

```
```

{% endtab %}
{% endtabs %}

#### Chi tiết các tham số

| Tham số        | Mô tả                                                                                    | Gá trị mặc định |
| -------------- | ---------------------------------------------------------------------------------------- | --------------- |
| ***fromDate*** | Thời gian bắt đầu bạn muốn lấy giao dịch                                                | 7 ngày gần nhất |
| **toDate**     | Thời gian kết thúc bạn muốn lấy giao dịch                                                | Hôm nay         |
| ***page***     | Số thứ tự trang                                                                          | 1               |
| ***pageSize*** | Số giao dịch trên một trang                                                              | 10              |
| ***sort***     | Sắp xếp giao dịch, các giá trị gồm: ASC, DESC. Với ASC là tăng dần còn DESC là giảm dần. | ASC             |

{% hint style="info" %}

* Nếu tham số nào không tồn tại thì sẽ lấy giá trị mặc định.
* Xem chi tiết các trường của một giao dịch, [xem chi tiết](broken://pages/q5pMdvXBn9IBm4DxMuoq)
  {% endhint %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request GET 'https://oauth.casso.vn/v2/accounts/123/transactions?fromDate=2021-04-01&toDate=2022-07-05&page=4&pageSize=20&sort=ASC' \
--header 'Authorization: Apikey <API Key của bạn> hoặc Bearer <access token từ OAuth2>'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/accounts/123/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/accounts/123/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC")
  .get()
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}


# API buộc đồng bộ giao dịch mới ngay

Thay vì phải chờ hệ thống của Casso tự động đồng bộ giao dịch mới thì với API này sẽ giúp bạn xử lý các giao dịch mới mà hệ thống của Casso chưa đồng bộ kịp thời.

### Trước khi bắt đầu

Một số lưu ý trước khi bắt đầu với các API liên quan tới webhook:

* Một tài khoản [Casso](https://my.casso.vn) đã liên kết một tài khoản ngân hàng. Để test với API này **hạn chế** sử dụng [tài khoản demo.](broken://pages/-McjWDNXLnazsGil8Lw0)
* Bạn cần có [API Key](/casso-api/chung-thuc/tao-api-key-thu-cong) để thiết lập ở trường Authorization HTTP Header.

## Đồng bộ giao dịch mới

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v2/sync`

Đồng bộ giao dịch mới tương ứng với số tài khoản của bạn trong business

#### Headers

| Name                                            | Type   | Description                                                           |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | string | `Bearer <access token từ Oauth2>` **hoặc** `Apikey <API key của bạn>` |

#### Request Body

| Name                                            | Type   | Description                                                     |
| ----------------------------------------------- | ------ | --------------------------------------------------------------- |
| bank\_acc\_id<mark style="color:red;">\*</mark> | string | Số tài khoản ngân hàng của bạn liên kết trên hệ thống của Casso |

{% tabs %}
{% tab title="200 Sync successfully." %}
{% tabs %}
{% tab title="Đồng bộ giao dịch thành công" %}

```
{
    "error": 0,
    "message": "success",
    "data": null
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Token sai hoặc hết hạn" %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}

{% tab title="429: Too Many Requests Too many requests" %}

```javascript
{
    "error": 429,
    "message": "Doanh nghiệp của bạn đang gọi Đồng bộ quá nhiều, giới hạn mặc định 1 Tài khoản ngân hàng/request/phút. Ngoài ra, dựa vào gói dịch vụ đang sử dụng của doanh nghiệp để tính giới hạn số lượng yêu cầu trong 1 ngày. Liên hệ với chúng tôi qua https://casso.vn nếu như bạn muốn tăng số lượng yêu cầu trong ngày.",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Ví dụ:&#x20;

{% tabs %}
{% tab title="CURL" %}

```javascript
curl --location --request POST 'https://oauth.casso.vn/v2/sync' \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">' \
--header 'Content-Type: application/json' \
--data-raw '{
    "bank_acc_id": "Số tài khoản ngân hàng cần đồng bộ"
}'
```

{% endtab %}

{% tab title="PHP" %}

```php
$curl = curl_init();

$data = array(
  'bank_acc_id' => 'Số tài khoản ngân hàng cần đồng bộ',
);
$postdata = json_encode($data);

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://oauth.casso.vn/v2/sync",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $postdata),
  CURLOPT_HTTPHEADER => array(
    "Authorization: Apikey <"API Key của bạn"> Hoặc Bearer <"access token từ OAuth2">",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);
```

{% endtab %}

{% tab title="JAVA" %}

```java
OkHttpClient client = new OkHttpClient();

RequestBody formBody = new FormBody.Builder()
  .add("bank_acc_id", "Số tài khoản ngân hàng cần đồng bộ")
  .build();

Request request = new Request.Builder()
  .url("https://oauth.casso.vn/v2/sync")
  .post(formBody)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Apikey <"API Key của bạn"> hoặc Bearer <"access token từ OAuth2">")
  .build();

Response response = client.newCall(request).execute();
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Sau khi bạn gọi API này, nếu hệ thống của Casso phát hiện có một hoặc nhiều giao dịch mới được đồng bộ thì ngay lúc đó hệ thống của Casso sẽ đẩy một Event chứa các giao dịch mới đó tới [Webhook của bạn đã thiết lập](/casso-api/api/thiet-lap-webhook).
{% endhint %}

{% hint style="warning" %}
Lưu ý về giới hạn gọi Đồng bộ của một TK ngân hàng:

* Chỉ gọi 1 yêu cầu/1 phút.
* Dựa vào gói Doanh nghiệp đang sử dụng để tính số lượng yêu cầu trong ngày.
* Tài khoản ngân hàng MBBank BIZ (RPA) chỉ gọi 1 yêu cầu/15 phút
  {% endhint %}


# Tích hợp xác nhận thanh toán

Thực hành lập trình xử lý sự kiện webhook để xác nhận thanh toán

## Giới thiệu

Hiện tại [Casso](https://casso.vn/) đã hỗ trợ nhiều hình thức tích hợp xác nhận thanh toán thông qua các [API](https://restfulapi.net/) [Casso](https://casso.vn/) đã public. Để phần tích hợp thanh toán của bạn xịn hơn thì có thể dùng [VietQR](https://www.vietqr.io/) để tạo QR-Code cho phần thanh toán. [VietQR](https://www.vietqr.io/) là tiêu chuẩn quốc gia về mã QR ngân hàng. Mã này được chấp nhận bởi 50 ngân hàng Việt Nam. Có thể xem chi tiết tại [đây](https://www.vietqr.io)

{% hint style="info" %}
Bạn có thể dùng [payOS by Casso](https://payos.vn) để xác thanh toán.
{% endhint %}

{% hint style="info" %}
Hướng dẫn này sử dụng Tích hợp Webhook để thực hiện. Nếu bạn sử dụng Tích hợp Webhook V2 để xác nhận thanh toán, bạn vẫn có thể tham khảo hướng dẫn này. Tuy nhiên, có một số thay đổi đối với cấu trúc dữ liệu và hình thức kiểm tra tính toàn vẹn của dữ liệu webhook. Casso đã có cập nhật ở bài viết [Thiết lập Webhook thủ công](/webhook/thiet-lap-webhook-thu-cong)
{% endhint %}

## Trước khi bắt đầu

## Hướng dẫn tích hợp

Để có thể sử dụng và hiểu được các API này thì dưới đây Casso demo một server basic được viết bằng [NodeJS](https://nodejs.org/en/about/) + [Express](https://expressjs.com/)  basic về tích hợp thanh toán. Chi tiết source tại [Github](https://github.com/CassoHQ/Integrated-payment-confirmation/blob/main/routes/index.js).

Dưới đây là demo các bước về việc tạo webhook để lắng nghe có các giao dịch mới của Casso gửi qua và yêu cầu đồng bộ giao dịch tức thì từ phía app. Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:

### Cấu trúc file sever

![](/files/-MeFtZq8tCb2a6Cr7XK4)

### **Bước 1: Tạo file index.js**

Đầu tiên chúng ta sẽ tạo file `index.js` để xây dựng server lắng nghe các request. Server mình sẽ thiết lập với cổng **4300**

```javascript
require('dotenv').config({ path: '.env' });
let app = require('./app');
async function main() {
    app
    console.log(`Server on port ${process.env.PORT || 4300}`);
};
main();
```

### **Bước 2**: Tạo file app.js, config và xử lý lỗi

Các thứ cần thiết cho server như: `cors, json, urlencoded`và [Express error handling](https://expressjs.com/en/guide/error-handling.html)

```javascript
let express = require("express");
var cors = require('cors');
let app = express();
// Tạo cors
var corsOption = {
    origin: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
    exposedHeaders: ['x-auth-token']
  };
app.use(cors(corsOption));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/', require('./routes'));
// Endpoint not found
app.use(function (req, res, next) {
    res.status(404).json({
        code: 404,
        message: 'Endpoint not found'
    });
})
// Xử lí khi lỗi ở phía server
app.use(function (err, req, res, next) {
    res.status(500).json({
        code: 500, error: 'Something went wrong, please try again!'
    })
})
app.listen(process.env.PORT || 4300);
module.exports = app;
```

### **Bước 3: Tạo các routes và test hello world**

Ở đây mình sẽ tạo 3 route chính:

* `/webhook/handler-bank-transfer` Webhook để nhận thông tin giao dịch từ Casso
* `/register-webhook` Thực hiện đăng kí webhook và lấy token từ Casso
* `/users-paid` Thực hiện tính năng đồng bộ giao dịch tức thì qua Casso

```javascript
var express = require('express');
var router = express.Router();
//Router này sẽ là webhook nhận thông tin giao dịch từ casso gọi qua được bảo mật bằng secure_token trong header
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Router này sẽ thực hiện tính năng đồng bộ giao dịch tức thì.
// Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút tôi đã thanh toán thì nên xử lí gọi qua casso đề đồng bộ giao dịch vừa chuyển khoản
router.route('/users-paid')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Route này sẽ thực hiện đăng kí webhook dựa vào API KEY và lấy thông tin về business và banks
router.route('/register-webhook')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })

module.exports = router;
```

Kiểm tra với postman&#x20;

![](/files/-MexD2hlKQCo8-6ZjteV)

### **Bước 4:** Xây dựng các hàm hỗ trợ

Để có thể giao tiếp với server Casso sẽ dùng 1 [HTTP Client](https://tapit.vn/http-request-va-http-response-phuong-thuc-giao-tiep-giua-server-client/)  để gọi qua. Ở Demo này sẽ sử dụng [Axios](https://www.npmjs.com/package/axios) và [Query-string](https://www.npmjs.com/package/query-string).

```javascript
//utils/api.js
const axios = require("axios");
const queryString =  require("query-string");

const axiosClient = axios.create({
  baseURL: 'https://oauth.casso.vn/v2',
  headers: {
    "content-type": "application/json",
    "Authorization": `Apikey ${api_key}`,
  },
  paramsSerializer: (params) => queryString.stringify(params),
});
axiosClient.interceptors.request.use(async (config) => {
  return config;
});
axiosClient.interceptors.response.use(
  (response) => {
    if (response && response.data) return response.data;
    return response;
  },
  (error) => {
    throw error;
  }
);
module.exports =  axiosClient;
```

{% hint style="success" %}
**Mẹo**:  Bạn có thể thay thế giá trị của **Authorization** với **`Bearer + access token`** nhận được từ [xác thực Oauth 2.0 của Casso.](broken://pages/-MchCrnygNiqB1UgtiJK)
{% endhint %}

{% hint style="info" %}
Bạn thể [tham khảo tài liệu này](/casso-api/chung-thuc/tao-api-key-thu-cong), để lấy API Key của bạn trên Casso.
{% endhint %}

Sau khi code HTTP Client thì tiến hành dựng từng hàm tương ứng với từng API.

* Get `userInfo` bao gồm thông tin về business và banks. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-lay-thong-tin-user)

```javascript
/*utils/get_user_info.util.js*/
    getDetailUser: async () => {
        let res = await api.get(`/userInfo`);
        return res;
    },
```

* Đồng bộ dữ liệu mới nhất. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-check-giao-dich-moi)

```javascript
/*utils/sync.util.js*/
    syncTransaction: async (bankNumber, apiKey) => {
        let res = await api.post('/sync', { bank_acc_id: bankNumber });
        return res;
    }
```

* Các hàm thêm, xóa, sửa và xóa `webhook` Mô tả chi tiết tại [đây](https://developer.casso.vn/danh-sach-api/api-thiet-lap-webhook)

```javascript
/*webhook.util.js*/
    create: async (data) => {
        let res = await api.post('/webhooks', data);
        return res;
    },
    getDetailWebhookById: async (webhookId) => {
        let res = await api.get(`/webhooks/${webhookId}`);
        return res;
    },
    updateWebhookById: async (webhookId, data) => {
        let res = await api.put(`/webhooks/${webhookId}`, data);
        return res;
    },
    deleteWebhookById: async (webhookId) => {
        let res = await api.delete(`/webhooks/${webhookId}`);
        return res;
    },
    deleteWebhookByUrl: async (urlWebhook) => {
        // Thêm url vào query để delete https://oauth.casso.vn/v1/webhooks?webhook=https://website-cua-ban.com/api/webhook
        let query = { params: { webhook: urlWebhook } };
        let res = await api.delete(`/webhooks`, query);
        return res;
    },
```

* Parser `orderId` từ nội dung giao dịch và tiền tố giao dịch (`DH1231=> 1231`) và đồng thời cũng kiểm tra có phân biệt chữ hoa với thường trong nội dung giao dịch hay không?

```javascript
/*webhook.util.js*/
    parseOrderId: (caseInsensitive, transactionPrefix, description) => {
        // Ở đây mình ở sử dụng regex để parse nội dung chuyển khoản có chứa orderId
        // CASSO101 => orderId = 101
        let re = new RegExp(transactionPrefix);
        if (!caseInsensitive)
            re = new RegExp(transactionPrefix, 'i');
        let matchPrefix = description.match(re);
        // Không tồn tại tiền tố giao dịch
        if (!matchPrefix) return null;
        let orderId = parseInt(description.substring(transactionPrefix.length, description.length));
        return orderId;
    }
```

### Bước 5: Xây dựng các Route&#x20;

Mình cần định nghĩa một vài biến cần trong quá trình dựng

```javascript
//routes/index.js
//Tiền tố giao dịch
const transaction_prefix = 'CASSO';
// Phân biệt chữ hoa/thường trong tiền tố giao dịch
const case_insensitive = false;
//Hạn của đơn hàng là 3 ngày. Quá 3 ngày thì không xử lý
const expiration_date = 3;
// API KEY lấy từ casso
const api_key = '45e40320-e0b7-11eb-a12c-35cc867f21a0';
// secure_token đăng kí khi tạo webhook
const secure_token = 'R5G4cbnN7uSAwfTd'
```

1. Route tạo webhook  bằng API\_KEY và lấy thông tin user bao gồm Business và banks

```javascript
//routes/index.js
router.route('/register-webhook')
    .post(async (req, res, next) => {
        try {
            //Delete Toàn bộ webhook đã đăng kí trước đó với https://ten-mien-cua-ban.com/webhook/handler-bank-transfer
            await webhookUtil.deleteWebhookByUrl('https://ten-mien-cua-ban.com/webhook/handler-bank-transfer');
            //Tiến hành tạo webhook
            let data = {
                webhook: 'https://ten-mien-cua-ban.com/webhook/handler-bank-transfer',
                secure_token: secure_token,
                income_only: true
            }
            let newWebhook = await webhookUtil.create(data);
            // Lấy thông tin về userInfo
            let userInfo = await userUtil.getDetailUser();
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: {
                    webhook: newWebhook.data,
                    userInfo: userInfo.data
                }
            })
        } catch (error) {
            next(error)
        }
    })
```

```javascript
curl --location --request POST 'http://localhost:4300/register-webhook' \
--header 'Content-Type: application/json'
```

```javascript
{
    "code": 200,
    "message": "success",
    "data": {
        "webhook": {
            "id": 415,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/webhook/handler-bank-transfer",
            "param2": "R5G4cbnN7uSAwfTd",
            "sendOnlyIncome": 1
        },
        "userInfo": {
            "user": {
                "id": 1553,
                "email": "haonh@magik.vn"
            },
            "business": {
                "id": 1540,
                "name": "Hữu Hảo"
            },
            "bankAccs": [
                {
                    "id": 619,
                    "bank": {
                        "bin": 970416,
                        "codeName": "acb_digi"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "17271687",
                    "connectStatus": 1,
                    "planStatus": 1
                },
                {
                    "id": 623,
                    "bank": {
                        "bin": 970454,
                        "codeName": "timoplus"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "8007041023848",
                    "connectStatus": 1,
                    "planStatus": 0
                }
            ]
        }
    }
}
```

2\. Route này sẽ thực hiện tính năng đồng bộ giao dịch qua Casso.

Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút **tôi đã thanh toán** thì nên xử lí gọi qua Casso để đồng bộ giao dịch vừa được chuyển khoản. Có thể sử dụng cho tính năng **Tôi đã thanh toán** để xác nhận thanh toán ngay.

```javascript
//routes/index.js
router.route('/users-paid')
    .post(async (req, res, next) => {
        try {
            // Để thực hiện tính năng đồng bộ cần có Số tài khoản, Bạn có thể validate bằng schema ở middlewares
            // Hoặc có thể kiểm tra trong đây luôn
            if (!req.body.accountNumber) {
                return res.status(404).json({
                    code: 404,
                    message: 'Not foung Account number'
                })
            }
            // Tiến hành gọi hàm đồng bộ qua casso
            await syncUtil.syncTransaction(req.body.accountNumber);
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }

    })
```

3\. Tạo một webhook để Casso có thể gửi giao dịch qua khi có giao dịch mới (**quan trọng**):&#x20;

```javascript
//routes/index.js
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        try {
            // B1: Ở đây mình sẽ thực hiện check secure-token. Bình thường phần này sẽ nằm trong middlewares
            // Mình sẽ code trực tiếp tại đây cho dễ hình dung luồng. Nếu không có secure-token hoặc sai đều trả về lỗi
            if (!req.header('secure-token') || req.header('secure-token') != secure_token) {
                return res.status(401).json({
                    code: 401,
                    message: 'Missing secure-token or wrong secure-token'
                })
            }
            // B2: Thực hiện lấy thông tin giao dịch 
            for (let item of req.body.data) {
                // Lấy thông orderId từ nội dung giao dịch
                let orderId = webhookUtil.parseOrderId(case_insensitive, transaction_prefix, item.description);
                // Nếu không có orderId phù hợp từ nội dung ra next giao dịch tiếp theo
                if (!orderId) continue;
                // Kiểm tra giao dịch còn hạn hay không? Nếu không qua giao dịch tiếp theo
                if ((((new Date()).getTime() - (new Date(item.when)).getTime()) / 86400000) >= expiration_date) continue;
                // Bước quan trọng đây.
                // Sau khi có orderId Thì thực hiện thay đổi các trang thái giao dịch
                // Ví dụ như kiểm tra orderId có tồn tại trong danh sách các đơn hàng của bạn?
                // Sau đó cập nhật trạng thái theo orderId và amount nhận được: đủ hay thiếu tiền...
                // Và một số chức năng khác có thể tùy biến
            }
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }
    })
```

### Cảm ơn đã theo dõi


# Change log

**06/07/2022**

* [API lấy giao dịch](/casso-api/api/lay-giao-dich) hỗ trợ thời gian kết thúc lấy giao dịch (**toDate**)
* [API lấy giao dịch](/casso-api/api/lay-giao-dich) thêm thông tin đối ứng ngân hàng, kênh chuyển tiền, tài khoản ảo

**01/09/2021**&#x20;

Casso chính thức công bố API v2, bao gồm một số thay đổi:&#x20;

* Ra mắt OAuth 2
* Thay đổi cơ chế Api Keys

### 1/ Cơ chế Api Keys

Api keys ở v1 sẽ tương đương với authorization code. Api key v2 sẽ tương đương một access token (lifetime access token).

Với nâng cấp ở version 2 này,  Developer sẽ không cần phải gọi api /v1/token để đổi api key thành access token mà sử dụng access token này để authorize các api truy cập vào Casso  luôn.

Ở API v1, để gọi api /userInfo, bước 1 là bạn phải gọi api /token để đổi access token, sau đó dùng access token này gắn vào header để gọi api /userInfo

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v1/userInfo \
--header 'Authorization: <"Access token">'
```

Thì ở API /v2 , API key bạn đã tạo ra ở giao diện tích hợp của Casso sẽ được dùng trực tiếp để authen api luôn như ví dụ bên dưới.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"api_key_here">'
```

### 2/ Cơ chế OAuth 2.0&#x20;

Nếu như bạn nhận **`Access token`** từ việc xác thực ở OAuth 2.0 của Casso thì bạn có thể dùng **`Access token`** này gắn vào Authorization trên header để gọi với các API Resource của Casso tương ứng với [Version 2](/casso-api/api/lay-thong-tin-user), kèm theo tiền tố là **`Bearer`**.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```

**05/03/2024**

Casso ngừng hỗ trợ đối tác và khách hàng cơ chế OAuth 2


# Tổng quan

Chuyên trang dành cho lập trình viên

## Chào mừng bạn tới Casso Developer

Đây là nơi bạn có thể tìm thấy tất cả các tài liệu đặc tả, hướng dẫn, tài nguyên để **lập trình tích hợp** phần mềm của bạn với **Casso**

Casso được sinh ra với DNA là **bảo mật,  tự động hóa** và **tích hợp không giới hạn.** Chúng tôi coi **khả năng tích hợp** là giá trị cốt lõi của sản phẩm. Do đó, chúng tôi đã phát triển Casso theo hướng cung cấp đa dạng hình thức kết nối với các hệ thống phần mềm khác, phục vụ **nhiều mục đích** khác nhau.&#x20;

## Các phương pháp tích hợp

| Phương pháp                                                                                                              | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Thiết lập Webhook thủ công](/v1/webhook/thiet-lap-webhook-thu-cong)                                                     | <ul><li>Cấu hình thêm một <strong>webhook</strong> trên giao diện của Casso.</li><li>Mỗi khi tài khoản ngân hàng có một giao dịch mới, Casso sẽ <strong>bắn thông tin giao dịch</strong> vào webhook đã cấu hình</li></ul>                                                                                                                                                                                                                                                                |
| [Tạo Auth Co](/v1/auth-code/tao-authorization-code-thu-cong)[d  thủ công](/v1/auth-code/tao-authorization-code-thu-cong) | <ul><li>Tạo một <strong>Auth Code</strong> trên giao diện của Casso. </li><li>Sử dụng <strong>Auth Code</strong> để sinh <strong>Access Token .</strong> </li><li>Dùng <strong>Access Token</strong> để gọi các API của Casso</li></ul>                                                                                                                                                                                                                                                   |
| [OAuth 2](/v1/oauth-2/tich-hop-oauth2)                                                                                   | <ul><li>Cơ chế chứng thực <strong>OAuth 2</strong> cho phép <strong>người dùng cuối</strong> tự động phân quyền cho <strong>Nhà Phát Triển</strong> truy cập thông tin tài khoản của họ tại Casso.</li><li>Sau khi người dùng thực hiện quy trình phân quyền trên phần mềm của <strong>Nhà Phát Triển</strong>, thì một Auth Code sẽ được tự động sinh ra.</li><li><strong>Nhà Phát triển</strong> sử dụng Auth Code này tương tự như Auth Code tạo bởi  phương pháp  thủ công.</li></ul> |

Hai phương pháp đầu là dành cho **người dùng cuối.** Là những doanh nghiệp, cá nhân đã sử dụng phần mềm **Casso** phục vụ nhu cầu quản lý thu chi. Và nay doanh nghiệp, cá nhân này cần tích hợp Casso vào hệ thống phần mềm khác mà doanh nghiệp cũng đang sử dụng.&#x20;

Phương pháp **OAuth 2** dành cho các **nhà phát triển phần mềm cho doanh nghiệp,** muốn tích hợp với Casso để cung cấp cho người dùng thêm lựa chọn **liên kết tài khoản Casso** vào phần mềm.

## Kế hoạch dự kiến

Bên cạnh 3 phương pháp tích hợp trên, chúng tôi cũng đang làm việc để triển khai phương pháp thứ 4, đó là phát triển một bộ thư viện tích hợp tương tự như **Plaid cho Việt Nam,** được cung cấp cho các **nhà phát triển** phần mềm dưới dạng **thư viện mã nguồn**.&#x20;

Bộ thư viện này sẽ giúp các đơn vị này phát triển **tính năng liên kết ngân hàng** của người dùng vào phần mềm của họ, một cách đơn giản và bảo mật. Người dùng phần mềm sẽ ko cần tạo tài khoản bên Casso mà liên kết ngân hàng ngay trên web, app của **nhà phát triển**. Và **Nhà Phát Triển** không cần phải lo lắng về vấn đề bảo mật cho tài khoản và dữ liệu của người dùng.

Chúng tôi dự kiến sẽ ra mắt chính thức trong vào đầu năm 2022. *Vui lòng liên hệ nếu bạn muốn tham gia vào chương trình dùng thử Beta Test của chúng tôi.*


# Thiết lập Webhook thủ công

Casso cho phép tích hợp với một Webhook API gọi tới server của bạn. Mỗi khi có giao dịch mới, Casso sẽ thực hiện gọi tới API bạn đã thiết lập sẵn để gửi thông tin giao dịch này.

## Mô hình hoạt động

![](/files/-MfTt-1ZvnJb0f78pD1p)

## Trước khi bắt đầu

Bạn cần phải:

* Tạo một tài khoản tại [Casso](https://casso.vn)
* Liên kết một tài khoản ngân hàng vào Casso. Xem thêm [*Tài khoản ngân hàng test*](/v1/tai-nguyen-khac/tai-khoan-ngan-hang-demo)

## Thiết lập webhook trong Casso

Đăng nhập vào tài khoản tại [casso.vn](https://casso.vn)&#x20;

Truy cập vào **Thiết lập** > **Tích hợp**  và ấn vào nút **Thêm tích hợp**

![](/files/-McjhH7nzwpUep215BYP)

Trong danh sách **Lựa chọn ứng dụng để tích hợp ,** chọn **Webhook.** Sẽ mở ra giao diện **Thêm tích hợp Webhook**:&#x20;

![](/files/-McjlbWAK16mLz8QGw7l)

Ở mục **Ngân hàng nhận webhook** :

* Bạn chọn tài khoản ngân hàng sẽ được theo dõi để bắn thông tin giao dịch.&#x20;
* Bạn có thể chọn Tất cả để Hệ thống **Casso** bắn giao dịch của tất cả các tài khoản ngân hàng đã liên kết.

Ở bước **Nhập thông tin Webhook :**

* Thông số **Webhook URL** sẽ là đường dẫn tới API đầu nhận Webhook trên web server của bạn.
* Thông số **Key bảo mật** chứa một mã bí mật  mà mỗi lần gọi vào **Webhook URL**, Casso sẽ đính kèm key bảo mật này vào trong HTTP Header. Bạn có thể kiểm tra header lấy thông tin mã bí mật để xác thực việc gọi vào Webhook URL là hợp lệ.

{% hint style="danger" %}
Không sử dụng Webhook URL là **đường dẫn chỉ có thể truy cập tư mạng nội bộ** hoặc **localhost, 127.0.01, 192.160.1.x ...** Webhook URL buộc phải là một đường dẫn public trên Internet.
{% endhint %}

Bấm vào nút **gọi thử**, để hệ thống Casso bắn một giao dịch test vào Webhook URL.&#x20;

Nếu Casso bắn Webhook URL thành công, tức là cấu hình của bạn đã hợp lệ. Lúc này bạn có thể bấm vào nút **Lưu** để hệ thống lưu lại cấu hình này.

{% hint style="info" %}
**Strict mode**: là bước kiểm tra nâng cao, khi phản hồi về status 200, thì Casso sẽ kiểm tra thêm 1 bước nữa trong JSON trả về **success : 1** hoặc **success: true**. Nếu là 0 thì hệ thống sẽ hiểu là fail và Casso sẽ gửi lại webhook. \
Nếu không bật strict mode thì khi nhận phản hồi status 200 thì Casso sẽ lưu lại là đã gửi webhook thành công.
{% endhint %}

{% hint style="success" %}
**MẸO** : Trong quá trình lập trình tích hợp, bên cạnh Webhook tùy chỉnh trỏ tới website của bạn, bạn có thể đăng kí thêm 1 webhook tùy chỉnh khác sử dụng các dịch vụ như **pipedream.com**, **webhook.site**, **ngrok.com** để debug nội dung Casso gửi vào Webhook URL
{% endhint %}

## Yêu cầu của Webhook URL

Casso sẽ thực hiện việc gọi API vào Webhook URL mỗi khi có giao dịch mới. Webhook URL sẽ cần phải đáp ứng các yêu cầu sau:

#### Khả năng truy cập

* Phải là đường dẫn công khai có thể truy cập từ internet
* Đường dẫn sử dụng giao thức bảo mật **HTTPS**
* Nếu website sử dụng Cloudfare hoặc các dịch vụ ngăn chặn DDOS, lưu ý bạn phải whitelist IP của Casso.&#x20;

#### Phản hồi thành công

Sau khi xử lý, webhook của bạn phải phản hồi với status code là **200 OK**. Và đáp ứng thời gian phản hồi dưới 5 giây ( Casso sẽ thiết lập timeout cho request post bắn webhook là 5s)

#### Xử lý các trường hợp thất bại.

Nếu quá trình bắn webhook thất bại vì một lý do nào đó, Casso sẽ gọi lại liên tục webhook trong 12 giờ sau đó, lần đầu gọi sẽ sau 1 phút và thời gian chờ này sẽ tăng lên thành giá trị [**Fibonacci**](https://vi.wikipedia.org/wiki/D%C3%A3y_Fibonacci) kế tiếp sau mỗi lần thử lại thất bại.&#x20;

#### Chống trùng lắp

Để chống lại phương pháp tấn công **Replay Attack**, Webhook của bạn cần phải được xử lý chống trùng lặp thông qua kiểm tra xem một giao dịch mới đã được xử lý trước đây hay chưa? Mỗi giao dịch của Casso được định danh bởi một `id`. Với một webhook mới đến, bạn hãy kiểm tra xem `id` của giao dịch này đã được xử lý trước đây hay chưa, nếu đã có thì tức là giao dịch này đã bị Replay bởi một lý do nào đó, hãy bỏ qua nó.

#### Xử lý hậu kiểm

Dù tỉ lệ có thể sẽ rất thấp, nhưng sẽ luôn có khả năng webhook thất bại, để tránh trường hợp bị sót giao dịch. Nhà phát triển có thể cân nhắc cung cấp tính năng **Tra soát toàn bộ giao dịch** bắng cách sử dụng API để tải về các giao dịch và kiểm tra xem có giao dịch nào sót không. Xem thêm ở mục [Tạo Auth code thủ công](/v1/auth-code/tao-authorization-code-thu-cong) hoặc [OAuth 2 ](/v1/oauth-2/tich-hop-oauth2)

## Cấu trúc dữ liệu gửi qua Webhook

Casso sẽ bắn dữ liệu vào Webhook URL mà bạn đã khai báo, Dữ liệu định dạng JSON, trong đó trường data sẽ lưu một **mảng các giao dịch mới**.

```javascript
{
    "error": 0,
    "data": [
        {
            "id": 6785,        //mã định danh duy nhất của giao dịch (Casso quy định)
            "tid": "BANK_REF_ID", //Mã giao dịch từ phía ngân hàng
            "description": "giao dich thu nghiem", // nội dung giao dịch
            "amount": 79000, // số tiền giao dịch
            "cusum_balance": 20079000,  // số tiền còn lại sau giao dịch                 
            "when": "2020-10-14 00:34:57",    // thời gian ghi có giao dịch ở ngân hàng
            "bank_sub_acc_id": "123456789",   // Mã tài khoản ngân hàng mà giao dịch thuộc về
        },
    
    ]
}
```

{% hint style="warning" %}
Lưu ý : Nếu có một giao dịch mới, Casso vẫn sẽ gửi qua một mảng chứa 1 phần tử giao dịch mới.&#x20;
{% endhint %}

## Lập trình webhook

Một số tài nguyên ban có thể tham khảo để lập trình Module xử lý webhook **Webhook Event Handler.**

| STT | Tên                                                                                                     | Link                                                                                                   |
| --- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| 1   | Mã nguồn **Webhook Event Handler** sample viết bằng PHP                                                 | <https://github.com/CassoHQ/casso-webhook-handler-sample>                                              |
| 2   | Mã nguồn **Webhook Event Handler** sample viết bằng Java                                                | *Đang cập nhật. Liên hệ chúng tôi*                                                                     |
| 3   | Mã nguồn **Webhook Event Handler** sample viết bằng NodeJS                                              | *Đang cập nhật. Liên hệ chúng tôi*                                                                     |
| 4   | Mã nguồn chính thức của Plugin Woocommerce `Casso – Tự động xác nhận thanh toán chuyển khoản ngân hàng` | <https://plugins.trac.wordpress.org/browser/casso-tu-dong-xac-nhan-thanh-toan-chuyen-khoan-ngan-hang/> |

Hãy bắt đầu&#x20;


# Lập trình xử lý sự kiện Webhook

Hướng dẫn các bước lập trình một API xử lý sự kiện webhook. Có code mẫu bằng NodeJS

Tích hợp phương pháp webhook rất đơn giản, **tất cả mọi thứ bạn cần làm là lập trình một API xử lý sự kiện Webhook.** Sau khi bạn đã đăng kí URL của API này vào một [mục tích hợp webhook](/v1/webhook/thiet-lap-webhook-thu-cong) trong Casso.

Mỗi khi Casso phát hiện tài khoản ngân hàng liên kết có một giao dịch mới, Casso sẽ gọi vào API này

Đặc tả của API này là :&#x20;

## Xử lý giao dịch được gửi từ Casso

<mark style="color:green;">`POST`</mark> `https://websitecuaban.com/api/webhook-event-handler`

#### Headers

| Name         | Type   | Description                                       |
| ------------ | ------ | ------------------------------------------------- |
| secure-token | string | Key bảo mật để xác thực Webhook được gọi từ Casso |

#### Request Body

| Name  | Type   | Description                       |
| ----- | ------ | --------------------------------- |
| error | string | Mã lỗi.                           |
| data  | string | Mảng danh sách các giao dịch mới. |

{% tabs %}
{% tab title="200 " %}

```





```

{% endtab %}
{% endtabs %}

## Code

Bạn có thể sử dụng bất kì ngôn ngữ nào hỗ trợ xây dựng  restful API để Code.

Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:&#x20;

* Tạo dự án Restful API mới (Nodejs Express / Java Spring Boot / PHP single file, ...)
* Test in ra được helloword!
* Tạo controller mới xử lý một Post tên là /webhook-event-handler&#x20;
* Test : Dùng Curl Post một giao dịch mô phỏng lên /webhook-event-handler  và chỉnh code để in ra đúng được nội dung gửi lên (xem thêm phần Test bên dưới)
* Rút trích nội dung giao dịch
* Xử lý nội dung giao dịch
* Phản hồi HTTP status code 200 OK

Ví dụ bên dưới viết bằng NodeJS, log ra số giao dịch Webhook Api nhận dc. Bằng cách chỉnh sửa vài dòng  [ Hello World Sample của Node JS Express](https://expressjs.com/en/starter/hello-world.html)

{% tabs %}
{% tab title="First Tab" %}
{% code title="app.js" %}

```javascript
const express = require('express')
const app = express()
const port = 8080

app.use(express.json());
app.post('/api/webhook-event-handler', (req, res) => {
    let error = req.body.error;
    if (error != 0) {
        //Không làm gì cả.
        return;
    }
    
    //mảng chứa danh sách các giao dịch
    let transactions = req.body.data;
    
    console.log(`Received ${transactions.length} transactions`);
    
    //thêm code xử lý giao dịch ở đây.
    
    res.end("OK");
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})
```

{% endcode %}
{% endtab %}

{% tab title="Second Tab" %}

{% endtab %}
{% endtabs %}

Bạn có thể xem thêm cách code một [API xử lý sự kiện webhook cho tính năng Tích hợp xác nhận thanh toán](/v1/thuc-hanh/tich-hop-xac-nhan-thanh-toan)

## Test

Có 5 cách để giả lập giao dịch gửi vào API xử lý webhook bạn đang code như sau:

| STT | Môi trường     | Phương pháp                                                           |
| --- | -------------- | --------------------------------------------------------------------- |
| 1   | Local          | Tự gọi API bằng Curl  / Postman                                       |
| 2   | Dev \| Staging | Nút Gọi Thử Trong giao diện setup Webhook                             |
| 3   | Dev \| Staging | Nút đồng bộ giao dịch ngay trong giao diện 1 Tài khoản ngân hàng Demo |
| 4   | Live           | Tạo một lệnh chuyển tiền.                                             |

Tuy nhiên, chúng tôi khuyến cáo bạn hãy viết và test thật kĩ trên Local trước , và test nhanh bằng Postman hoặc Curl.&#x20;

{% tabs %}
{% tab title="Curl (Mac OS | Linux)" %}
Copy nội dung bên dưới, sau khi đã fix lại đường dẫn API xử lý webhook

Mở terminal&#x20;

```bash
curl --location --request POST 'http://localhost:8080/api/webhook-event-handler' \
--header 'secure-token: eogrBiWqaq' \
--header 'Content-Type: application/json' \
--data-raw '{
    "error": 0,
    "data": [
        {
            "id" : 1, 
            "when": "2020-11-02",
            "amount": 200500,
            "description": "DH35",
            "cusum_balance": 15900500,
            "tid": "TF80307914",
            "subAccId": "123456789",
            "order": "2020110200001"
        }
    ]
}'
```

Paste & Enter
{% endtab %}

{% tab title="Curl (Window)" %}

{% endtab %}

{% tab title="Postman" %}

{% endtab %}
{% endtabs %}

## Phát hành

* Release dự án lên internet
* Cập nhật lại Webhook URL trong cấu hình webhook
* Link môt tài khoản ngân hàng thật
* Chuyển tiền vào tài khoản ngân hàng (5,000 , 10,000 thôi)
* Xác nhận rằng Casso đã gọi qua Webhook và xử lý thành công

Và \
... Xin chúc mừng. **Bạn đã hoàn tất!!!!**\
\
Chúng tôi ở đây để làm cho thế giới đơn giản hơn. ^^


# Tạo API Key thủ công

Auth code được dùng để lấy access token cho phép ứng dụng bên ngoài truy cập và lấy thông tin trên hệ thống Casso.

## Các bước tạo Auth&#x20;

**Bước 1:** Truy cập vào **Thiết lập** > **Api Keys** > **Tạo API Key**

![](/files/-Me8f6FpQ-xh0BpS1Vlo)

Bước 2: Điền tên API Key > **Tạo và xem API Key**&#x20;

![](/files/-Me8gQ6s6TYmobf_bu3-)

**Bước 3:** Xem và Sao lưu API Key

![](/files/-Me8hamHqwBOl8eA71lD)

**Bước 4:** Sau khi đã sao chép và lưu API Key ở đâu đó an toàn > Xong, để xem danh sách API&#x20;

![](/files/-Me8iAkZoZRYNMJK8Ks8)

### Chỉnh sửa hoặc xoá một API Key&#x20;

![](/files/-Me8k4FrGjL_wASQPeXc)


# Tích hợp OAuth2

Cơ chế xác thực OAuth2 cho phép người dùng cuối tự động phân quyền cho Nhà Phát Triển truy cập thông tin tài khoản của họ trên Casso.

{% hint style="danger" %}
Lưu ý: **Access token** nhận được từ xác thức OAuth 2.0 của Casso chỉ hỗ trợ ở **v2**.
{% endhint %}

#### Trước khi bắt đầu

Trước khi bắt đầu sử dụng Oauth2 của Casso, bạn cần phải:

* Có một tài khoản Casso.
* [Đăng ký một ứng dụng liên kết ](https://forms.gle/9Q6cvPLLmXNwpo366)với tài khoản developer của bạn.

#### Cách hoạt động

Casso hỗ trợ [Oauth 2.0 Authorization Code grant type](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type), được chia thành 4 bước cơ bản như sau:

1. Ứng dụng của bạn sẽ mở một cửa sổ trình duyệt để đưa người dùng đến Casso OAuth2.
2. Người dùng xem xét các quyền được yêu cầu và cấp quyền truy cập ứng dụng.
3. Người dùng được chuyển hướng trở lại ứng dụng với mã ủy quyền(authorization code) trong chuỗi truy vấn(query params).
4. Ứng dụng gửi yêu cầu đến Casso OAuth2 để trao đổi mã ủy quyền(authorization code) để lấy **`access token`**.

#### Hướng dẫn

* [**Lấy OAuth2 token**](/v1/oauth-2/tich-hop-oauth2#lay-oauth2-token): Cách ủy quyền ứng dụng của bạn với người dùng.
* [**Sử dụng OAuth2 token**](/v1/oauth-2/tich-hop-oauth2#su-dung-oauth2-token): Cách thực hiện một truy vấn với token.
* [**Lấy lại OAuth2 token**](/v1/oauth-2/tich-hop-oauth2#lay-lai-oauth-2-token): Cách sử dụng refresh token do Casso cung cấp.

## Lấy OAuth2 token

#### Bước 1: Tạo một authorization URL và hướng người dùng đến Oauth2 của Casso.

Khi một người dùng truy vấn tới hệ thống Oauth2 của Casso, đầu tiên sẽ phải tạo một authorization URL. Điều này sẽ xác định ứng dụng và phạm vi tài nguyên mà ứng dụng yêu cầu quyền truy cập thay cho người dùng. Các tham số truy vấn bạn có thể truyền như một phần của authorization URL được hiển thị ở dưới.&#x20;

| Tham số         | Bắt buộc | Mô tả                                                                                                                                                                 | Ví dụ                                   |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `client_id`     | Có       | Client ID dùng để xác định ứng dụng của bạn.                                                                                                                          | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `scope`         | Có       | Các phạm vi ứng dụng của bạn đang yêu cầu, được phân tách bằng dấu cách được mã hóa URL.                                                                              | `webhook%20transaction`                 |
| `redirect_uri`  | Có       | URL mà người dùng sẽ được chuyển hướng đến sau khi họ ủy quyền cho ứng dụng của bạn trong các phạm vi được yêu cầu. Đối với các ứng dụng sản xuất, https là bắt buộc. | `https://www.example.com/auth-callback` |
| `response_type` | Có       | Loại phản hồi                                                                                                                                                         | `code`                                  |
| `state`         | Không    | Đây là thông số khi bạn gửi lên như nào thì lúc bạn nhận authorization code thì nó vẫn như vậy.                                                                       | `84be6ce9661042d59cf`                   |

Khi bạn đã tạo xong authorization URL của mình, hãy bắt đầu tiến trình OAuth2 bằng cách đưa người dùng đến URL đó.

#### Ví dụ

Sử dụng một server-side redirect:

```javascript
// Build the auth URL
const authUrl =
  'https://oauth.casso.vn/auth/authorize' +
  `?client_id=${encodeURIComponent(CLIENT_ID)}` +
  `&scope=${encodeURIComponent(SCOPES)}` +
  `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
  `&response_type=${encodeURIComponent(RESPONSE_TYPE)}`;

// Redirect the user
return res.redirect(authUrl);
```

Sử dụng đương dẫn HTML:

```javascript
<a href="https://oauth.casso.vn/auth/authorize?scope=webhook%20transaction&redirect_uri=https://www.example.com/auth-callback&client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">One click to Casso</a>
```

#### Bước 2: Casso nhắc nhở người dùng chấp thuận&#x20;

Casso hiển thị cửa sổ cho người dùng đồng ý, hiển thị tên ứng dụng của bạn và mô tả ngắn gọn về các dịch vụ API của Casso mà họ đang yêu cầu quyền truy cập. Sau đó, người dùng có thể cấp quyền truy cập doanh nghiệp của họ cho ứng dụng của bạn.

![](/files/-MiuCN3PSFhpIOblrkO1)

Ứng dụng của bạn không thực hiện bất kỳ điều gì ở giai đoạn này. Sau khi quyền truy cập được người dùng cấp, Casso OAuth2 sẽ gửi kết quả đến **`Callback URL`** được xác định trong authorization URL.

#### Bước 3: Xử lý phản hồi của OAuth2

Khi người dùng đã hoàn tất lời nhắc đồng ý từ Bước 2, OAuth 2.0 server sẽ gửi yêu cầu GET tới **redirect URI** được chỉ định trong authorization URL của bạn. Nếu không có vấn đề gì và người dùng chấp thuận yêu cầu truy cập, yêu cầu tới **redirect URI** sẽ được trả về với tham số truy vấn mã được đính kèm. Nếu người dùng không cấp quyền truy cập, sẽ gửi một yêu cầu lỗi về **redirect URI**.

#### Ví dụ:

```javascript
app.get('/oauth-callback', async (req, res) => {
  if (req.query.code) {
    // Handle the received code
  }
});
```

#### Bước 4: Trao đổi authorization code để lấy token

Sau khi ứng dụng của bạn nhận được **authorization code** từ OAuth server, ứng dụng có thể trao đổi mã đó để lấy **access token** và **refresh token** bằng cách gửi yêu cầu [POST URL-form encoded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#example) tới `https://oauth.casso.vn/auth/token` với các giá trị được hiển thị bên dưới.  Cung cấp base64 của **client\_*****id:client\_secret*** dưới dạng **`basic token`** trong Authorization HTTP Header.

| Tham số         | Mô tả                                                                 | Ví dụ                                   |
| --------------- | --------------------------------------------------------------------- | --------------------------------------- |
| `grant_type`    | Bắt buộc là`authorization_code`                                       | `authorization_code`                    |
| `client_id`     | Client ID của ứng dụng của bạn                                        | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `client_secret` | Client secret của ứng dụng của bạn                                    | `58dfc671-c650-457f-8a24-3d57bdeab5ac`  |
| `redirect_uri`  | Chuyển hướng tới URI này khi người dùng ủy quyền cho ứng dụng của bạn | `https://www.example.com/auth-callback` |
| `code`          | Authorization code nhận được từ Oauth2 server                         | `6be34af7-6699-41cb-9c41-e02c635bd354`  |

#### Ví dụ:

```javascript
const formData = {
  grant_type: 'authorization_code',
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  code: req.query.code
};

request.post(
  'https://oauth.casso.vn/auth/token', 
  { 
    form: formData,
    headers: {
      Authorization: `Basic ${Buffer.from(CLIENT_ID+":"+CLIENT_SECRET).toString('base64')}`
    } 
  }, (err, data) => {
  // Handle the returned tokens
}
```

Nội dung của phản hồi mã thông báo sẽ là dữ liệu JSON có dạng:&#x20;

```javascript
{
    "refresh_token":"f71345a6-f53d-4191-903c-3823d9adb9e",
    "access_token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxODI5IiwiZXhwIjoxNjMwOTQxMDI4LCeJpYXQiOjE2MzA5MTk0M9.mYA8HFw0HqyoLJAocIzffNw4aG2kA8sHlf2UYNIKhHlazWK2ajbj06Bil4_0NxS6Jiamw3E9Q28tpiU7f9tYA",
    "expires_in":21600,
    "token_type": "bearer"
}
```

{% hint style="info" %}
Note: Access token sẽ hết hạn sau số giây được cung cấp trong trường expires\_in của phản hồi (sáu giờ). Để biết thông tin về cách nhận access token mới, hãy xem [Lấy lại Oauth2 token](/v1/oauth-2/tich-hop-oauth2#lay-lai-oauth-2-token).
{% endhint %}

## Sử dụng OAuth2 token

Sau khi hoàn tất quy trình authorization code, ứng dụng của bạn được ủy quyền thay người dùng gửi request. Để thực hiện việc này, cung cấp access token dưới dạng bearer token trong Authorization HTTP Header.&#x20;

#### Ví dụ:

```javascript
request.get('https://oauth.casso.vn/v2/transactions?fromDate=2021-04-01&page=4',
  {
    headers: {
      'Authorization': `Bearer ${ACCESS_TOKEN}`,
      'Content-Type': 'application/json'
    }
  },
  (err, data) => {
    // Handle the API response
  }
);
```

## Lấy lại OAuth 2 token

OAuth access token hết hạn định kỳ. Điều này nhằm đảm bảo rằng nếu chúng bị xâm nhập, những kẻ tấn công sẽ chỉ có quyền truy cập trong một thời gian ngắn. Tuổi thọ của access token (sáu giờ theo mặc định) được chỉ định trong trường **`expires_in`** khi **`authorization code`** được trao đổi lấy access token.

Ứng dụng của bạn có thể trao đổi **`refresh token`** đã nhận để lấy **`access token`** mới bằng cách gửi yêu cầu [POST URL-form encoded](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#example) tới **`https://oauth.casso.com/auth/token`** với các giá trị bên dưới. Cung cấp base64 của **client\_*****id:client\_secret*** dưới dạng basic token trong Authorization HTTP Header.

| Tham số         | Mô tả                                                                 | Ví dụ                                   |
| --------------- | --------------------------------------------------------------------- | --------------------------------------- |
| `grant_type`    | Phải là `refresh_token`                                               | `refresh_token`                         |
| `client_id`     | Client ID của ứng dụng của bạn                                        | `84be6ce9-6610-42d5-9cf1-acd85a5574cb`  |
| `client_secret` | Client secret của ứng dụng của bạn                                    | `58dfc671-c650-457f-8a24-3d57bdeab5ac`  |
| `redirect_uri`  | Chuyển hướng tới URI này khi người dùng ủy quyền cho ứng dụng của bạn | `https://www.example.com/auth-callback` |
| `refresh_token` | Refresh token nhận được khi người dùng ủy quyền cho ứng dụng của bạn  | `6be34af7-6699-41cb-9c41-e02c635bd354`  |

#### Ví dụ:

```javascript
const formData = {
  grant_type: 'refresh_token',
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  refresh_token: REFRESH_TOKEN
};

request.post(
  'https://oauth.casso.vn/auth/token', 
  { 
    form: formData, 
    headers: {
      Authorization: `Basic ${Buffer.from(CLIENT_ID+":"+CLIENT_SECRET).toString('base64')}`
    } 
  }, (err, data) => {
  // Handle the returned tokens
}
```

Nội dung của phản hồi mã thông báo sẽ là dữ liệu JSON có dạng:&#x20;

```javascript
{
    "access_token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxODI5IiwiZXhwjsIjoxNjMwOTQyODc4LCJpYXQiOjE2MzA5MjEyNzh9.qh0_UkSudFUu_WabtW9wu_j57b3VJ5WEWASLpSklPfrb-EKzrYl4Z4PYkrPIPrLseCPnSXlIDsixp8OkBrh_BW4g",
    "token_type": "bearer",
    "expires_in": 21600
}
```

**`Access token`** mới có thể được sử dụng để thực hiện request thay cho người dùng. Khi **`access token`** mới hết hạn, bạn có thể thực hiện lại các bước tương tự để lấy mã mới.

{% hint style="info" %}
**Refresh token** không có thời gian hết hạn. Mỗi lần **`access token`** hết hạn, bạn thực hiện lại các bước tương tự với **refresh token** để lấy mã mới.
{% endhint %}


# Tích hợp xác nhận thanh toán

Thực hành lập trình xử lý sự kiện webhook để xác nhận thanh toán

## Giới thiệu

Hiện tại [Casso](https://casso.vn/) đã hỗ trợ nhiều hình thức tích hợp xác nhận thanh toán thông qua các [API](https://restfulapi.net/) [Casso](https://casso.vn/) đã public. Để phần tích hợp thanh toán của bạn xịn hơn thì có thể dùng [VietQR](https://www.vietqr.io/) để tạo QR-Code cho phần thanh toán. [VietQR](https://www.vietqr.io/) là tiêu chuẩn quốc gia về mã QR ngân hàng. Mã này được chấp nhận bởi 50 ngân hàng Việt Nam. Có thể xem chi tiết tại [đây](https://www.vietqr.io)

## Hướng dẫn tích hợp

Để có thể sử dụng và hiểu được các API này thì dưới đây Casso demo một server basic được viết bằng [NodeJS](https://nodejs.org/en/about/) + [Express](https://expressjs.com/)  basic về tích hợp thanh toán. Chi tiết source tại [Github](https://github.com/CassoHQ/Integrated-payment-confirmation/blob/main/routes/index.js).

Dưới đây là demo các bước về việc tạo webhook để lắng nghe có các giao dịch mới của Casso gửi qua và yêu cầu đồng bộ giao dịch tức thì từ phía app. Quá trình code có thể chỉ mất vài giờ nếu bạn đã quen với việc viết API. Bạn có thể làm theo kịch bản sau:

### Cấu trúc file sever

![](/files/-MeFtZq8tCb2a6Cr7XK4)

### **Bước 1: Tạo file index.js**

Đầu tiên chúng ta sẽ tạo file `index.js` để xây dựng server lắng nghe các request. Server mình sẽ thiết lập với cổng **4300**

```javascript
require('dotenv').config({ path: '.env' });
let app = require('./app');
async function main() {
    app
    console.log(`Server on port ${process.env.PORT || 4300}`);
};
main();
```

### **Bước 2**: Tạo file app.js, config và xử lý lỗi

Các thứ cần thiết cho server như: `cors, json, urlencoded`và [Express error handling](https://expressjs.com/en/guide/error-handling.html)

```javascript
let express = require("express");
var cors = require('cors');
let app = express();
// Tạo cors
var corsOption = {
    origin: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
    exposedHeaders: ['x-auth-token']
  };
app.use(cors(corsOption));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/', require('./routes'));
// Endpoint not found
app.use(function (req, res, next) {
    res.status(404).json({
        code: 404,
        message: 'Endpoint not found'
    });
})
// Xử lí khi lỗi ở phía server
app.use(function (err, req, res, next) {
    res.status(500).json({
        code: 500, error: 'Something went wrong, please try again!'
    })
})
app.listen(process.env.PORT || 4300);
module.exports = app;
```

### **Bước 3: Tạo các routes và test hello world**

Ở đây mình sẽ tạo 3 route chính:

* `/webhook/handler-bank-transfer` Webhook để nhận thông tin giao dịch từ Casso
* `/register-webhook` Thực hiện đăng kí webhook và lấy token từ Casso
* `/users-paid` Thực hiện tính năng đồng bộ giao dịch tức thì qua Casso

```javascript
var express = require('express');
var router = express.Router();
//Router này sẽ là webhook nhận thông tin giao dịch từ casso gọi qua được bảo mật bằng secure_token trong header
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Router này sẽ thực hiện tính năng đồng bộ giao dịch tức thì.
// Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút tôi đã thanh toán thì nên xử lí gọi qua casso đề đồng bộ giao dịch vừa chuyển khoản
router.route('/users-paid')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })
// Route này sẽ thực hiện đăng kí webhook dựa vào API KEY và lấy thông tin về business và banks
router.route('/register-webhook')
    .post(async (req, res, next) => {
        res.status(200).json({message: "Hello world"})
    })

module.exports = router;
```

Kiểm tra với postman&#x20;

![](/files/-MexD2hlKQCo8-6ZjteV)

### **Bước 4:** Xây dựng các hàm hỗ trợ

Để có thể giao tiếp với server Casso sẽ dùng 1 [HTTP Client](https://tapit.vn/http-request-va-http-response-phuong-thuc-giao-tiep-giua-server-client/)  để gọi qua. Ở Demo này sẽ sử dụng [Axios](https://www.npmjs.com/package/axios) và [Query-string](https://www.npmjs.com/package/query-string).

```javascript
//utils/api.js
const axios = require("axios");
const queryString =  require("query-string");
const axiosClient = axios.create({
  baseURL: 'https://oauth.casso.vn/v1',
  headers: {
    "content-type": "application/json",
  },
  paramsSerializer: (params) => queryString.stringify(params),
});
axiosClient.interceptors.request.use(async (config) => {
  return config;
});
axiosClient.interceptors.response.use(
  (response) => {
    if (response && response.data) return response.data;
    return response;
  },
  (error) => {
    throw error;
  }
);
module.exports =  axiosClient;
```

Sau khi code HTTP Client thì tiến hành dựng từng hàm tương ứng với từng API.

* Get token từ API key lấy từ Casso. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-lay-acess-token)

```javascript
/*utils/get_token.util.js*/
const api = require('./api');
module.exports = {
    getTokenByAPIKey: async (code) => {
            let token = await api.post('/token', { code: code });
        return token;
    }
}
```

* Get `userInfo` bao gồm thông tin về business và banks. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-lay-thong-tin-user)

```javascript
/*utils/get_user_info.util.js*/
    getDetailUser: async (accessToken) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.get(`/userInfo`);
        return res;
    },
```

* Đồng bộ dữ liệu mới nhất. Mô tả cụ thể về API tại [đây](https://developer.casso.vn/danh-sach-api/api-check-giao-dich-moi)

```javascript
/*utils/sync.util.js*/
    syncTransaction: async (bankNumber, accessToken) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.post('/sync', { bank_acc_id: bankNumber });
        return res;
    }
```

* Các hàm thêm, xóa, sửa và xóa `webhook` Mô tả chi tiết tại [đây](https://developer.casso.vn/danh-sach-api/api-thiet-lap-webhook)

```javascript
/*webhook.util.js*/
    create: async (data, accessToken) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.post('/webhooks', data);
        return res;
    },
    getDetailWebhookById: async (webhookId, accessToken) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.get(`/webhooks/${webhookId}`);
        return res;
    },
    updateWebhookById: async (webhookId, accessToken, data) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.put(`/webhooks/${webhookId}`, data);
        return res;
    },
    deleteWebhookById: async (webhookId, accessToken) => {
        api.defaults.headers.Authorization = accessToken;
        let res = await api.delete(`/webhooks/${webhookId}`);
        return res;
    },
    deleteWebhookByUrl: async (urlWebhook, accessToken) => {
        // Thêm url vào query để delete https://oauth.casso.vn/v1/webhooks?webhook=https://website-cua-ban.com/api/webhook
        let query = { params: { webhook: urlWebhook } };
        api.defaults.headers.Authorization = accessToken;
        let res = await api.delete(`/webhooks`, query);
        return res;
    },
```

* Parser `orderId` từ nội dung giao dịch và tiền tố giao dịch (`DH1231=> 1231`) và đồng thời cũng kiểm tra có phân biệt chữ hoa với thường trong nội dung giao dịch hay không?

```javascript
/*webhook.util.js*/
    parseOrderId: (caseInsensitive, transactionPrefix, description) => {
        // Ở đây mình ở sử dụng regex để parse nội dung chuyển khoản có chứa orderId
        // CASSO101 => orderId = 101
        let re = new RegExp(transactionPrefix);
        if (!caseInsensitive)
            re = new RegExp(transactionPrefix, 'i');
        let matchPrefix = description.match(re);
        // Không tồn tại tiền tố giao dịch
        if (!matchPrefix) return null;
        let orderId = parseInt(description.substring(transactionPrefix.length, description.length));
        return orderId;
    }
```

### Bước 5: Xây dựng các Route&#x20;

Mình cần định nghĩa một vài biến cần trong quá trình dựng

```javascript
//routes/index.js
//Tiền tố giao dịch
const transaction_prefix = 'CASSO';
// Phân biệt chữ hoa/thường trong tiền tố giao dịch
const case_insensitive = false;
//Hạn của đơn hàng là 3 ngày. Quá 3 ngày thì không xử lý
const expiration_date = 3;
// API KEY lấy từ casso
const api_key = '45e40320-e0b7-11eb-a12c-35cc867f21a0';
// secure_token đăng kí khi tạo webhook
const secure_token = 'R5G4cbnN7uSAwfTd'
```

1. Route tạo webhook  bằng API\_KEY và lấy thông tin user bao gồm Business và banks

```javascript
//routes/index.js
router.route('/register-webhook')
    .post(async (req, res, next) => {
        try {
            // Token có hạn 6h nên bạn có thể lưu lại khi nào hết thì gọi hàm lấy token lại
            let resToken = await getTokenUtil.getTokenByAPIKey(api_key);
            let accessToken = resToken.access_token;
            //Delete Toàn bộ webhook đã đăng kí trước đó với https://ten-mien-cua-ban.com/webhook/handler-bank-transfer
            await webhookUtil.deleteWebhookByUrl('https://ten-mien-cua-ban.com/webhook/handler-bank-transfer', accessToken);
            //Tiến hành tạo webhook
            let data = {
                webhook: 'https://ten-mien-cua-ban.com/webhook/handler-bank-transfer',
                secure_token: secure_token,
                income_only: true
            }
            let newWebhook = await webhookUtil.create(data, accessToken);
            // Lấy thông tin về userInfo
            let userInfo = await userUtil.getDetailUser(accessToken);
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: {
                    webhook: newWebhook.data,
                    userInfo: userInfo.data
                }
            })
        } catch (error) {
            next(error)
        }
    })
```

```javascript
curl --location --request POST 'http://localhost:4300/register-webhook' \
--header 'Content-Type: application/json'
```

```javascript
{
    "code": 200,
    "message": "success",
    "data": {
        "webhook": {
            "id": 415,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/webhook/handler-bank-transfer",
            "param2": "R5G4cbnN7uSAwfTd",
            "sendOnlyIncome": 1
        },
        "userInfo": {
            "user": {
                "id": 1553,
                "email": "haonh@magik.vn"
            },
            "business": {
                "id": 1540,
                "name": "Hữu Hảo"
            },
            "bankAccs": [
                {
                    "id": 619,
                    "bank": {
                        "bin": 970416,
                        "codeName": "acb_digi"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "17271687",
                    "connectStatus": 1,
                    "planStatus": 1
                },
                {
                    "id": 623,
                    "bank": {
                        "bin": 970454,
                        "codeName": "timoplus"
                    },
                    "bankAccountName": null,
                    "bankSubAccId": "8007041023848",
                    "connectStatus": 1,
                    "planStatus": 0
                }
            ]
        }
    }
}
```

2\. Route này sẽ thực hiện tính năng đồng bộ giao dịch qua Casso.

Ví dụ: Khi người dùng chuyển khoản cho bạn và họ ấn nút **tôi đã thanh toán** thì nên xử lí gọi qua Casso để đồng bộ giao dịch vừa được chuyển khoản. Có thể sử dụng cho tính năng **Tôi đã thanh toán** để xác nhận thanh toán ngay.

```javascript
//routes/index.js
router.route('/users-paid')
    .post(async (req, res, next) => {
        try {
            // Để thực hiện tính năng đồng bộ cần có Số tài khoản, Bạn có thể validate bằng schema ở middlewares
            // Hoặc có thể kiểm tra trong đây luôn
            if (!req.body.accountNumber) {
                return res.status(404).json({
                    code: 404,
                    message: 'Not foung Account number'
                })
            }
            let resToken = await getTokenUtil.getTokenByAPIKey(api_key);
            let accessToken = resToken.access_token;
            // Tiến hành gọi hàm đồng bộ qua casso
            await syncUtil.syncTransaction(req.body.accountNumber, accessToken);
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }

    })
```

3\. Tạo một webhook để Casso có thể gửi giao dịch qua khi có giao dịch mới (**quan trọng**):&#x20;

```javascript
//routes/index.js
router.route('/webhook/handler-bank-transfer')
    .post(async (req, res, next) => {
        try {
            // B1: Ở đây mình sẽ thực hiện check secure-token. Bình thường phần này sẽ nằm trong middlewares
            // Mình sẽ code trực tiếp tại đây cho dễ hình dung luồng. Nếu không có secure-token hoặc sai đều trả về lỗi
            if (!req.header('secure-token') || req.header('secure-token') != secure_token) {
                return res.status(401).json({
                    code: 401,
                    message: 'Missing secure-token or wrong secure-token'
                })
            }
            // B2: Thực hiện lấy thông tin giao dịch 
            for (let item of req.body.data) {
                // Lấy thông orderId từ nội dung giao dịch
                let orderId = webhookUtil.parseOrderId(case_insensitive, transaction_prefix, item.description);
                // Nếu không có orderId phù hợp từ nội dung ra next giao dịch tiếp theo
                if (!orderId) continue;
                // Kiểm tra giao dịch còn hạn hay không? Nếu không qua giao dịch tiếp theo
                if ((((new Date()).getTime() - (new Date(item.when)).getTime()) / 86400000) >= expiration_date) continue;
                // Bước quan trọng đây.
                // Sau khi có orderId Thì thực hiện thay đổi các trang thái giao dịch
                // Ví dụ như kiểm tra orderId có tồn tại trong danh sách các đơn hàng của bạn?
                // Sau đó cập nhật trạng thái theo orderId và amount nhận được: đủ hay thiếu tiền...
                // Và một số chức năng khác có thể tùy biến
            }
            return res.status(200).json({
                code: 200,
                message: 'success',
                data: null
            })
        } catch (error) {
            next(error)
        }
    })
```

### Cảm ơn đã theo dõi


# Change log

Từ 01/09/2021 , Casso chính thức công bố API v2, bao gồm một số thay đổi:&#x20;

* Ra mắt Oauth 2
* Thay đổi cơ chế Api Keys

### 1/ Cơ chế Api Keys

Api keys ở v1 sẽ tương đương với authorization code. Api key v2 sẽ tương đương một access token (lifetime access token).

Với nâng cấp ở version 2 này,  Developer sẽ không cần phải gọi api /v1/token để đổi api key thành access token mà sử dụng access token này để authorize các api truy cập vào Casso  luôn.

Ở API v1, để gọi api /userInfo, bước 1 là bạn phải gọi api /token để đổi access token, sau đó dùng access token này gắn vào header để gọi api /userInfo

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v1/userInfo \
--header 'Authorization: <"Access token">'
```

Thì ở API /v2 , API key bạn đã tạo ra ở giao diện tích hợp của Casso sẽ được dùng trực tiếp để authen api luôn như ví dụ bên dưới.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Apikey <"api_key_here">'
```

### 2/ Cơ chế OAuth 2.0&#x20;

Nếu như bạn nhận **`Access token`** từ việc xác thực ở OAuth 2.0 của Casso thì bạn có thể dùng **`Access token`** này gắn vào Authorization trên header để gọi với các API Resource của Casso tương ứng với [Version 2](broken://pages/-Mj7RTlqTXI63fbQJ32v), kèm theo tiền tố là **`Bearer`**.

#### Ví dụ:&#x20;

```bash
curl --location --request GET 'https://oauth.casso.vn/v2/userInfo \
--header 'Authorization: Bearer <"Access token nhận được từ OAuth 2.0 của Casso">'
```


# API lấy Acess-Token

Access-Token là mã truy cập do được khởi tạo từ Auth Code, để có thể truy cập dữ liệu của bạn trên hệ thống của Casso.

## &#x20;Get access token

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v1/token`

&#x20;Endpoint này dùng để lấy access token.

#### Request Body

| Name | Type   | Description |
| ---- | ------ | ----------- |
| code | string | API Key     |

{% tabs %}
{% tab title="200 " %}

```
{
    "refresh_token": "Refresh token",
    "access_token": "Access token",
    "expires_in": "Số giây access token hết hạn, mặc định là 21600 = 6 tiếng"
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request POST 'http://oauth.casso.vn/v1/token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "code": "API Key"
}'
```


# API lấy thông tin user

## Lấy thông tin user

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v1/userInfo`

Lấy chi tiết thông tin của user về bank và business

#### Headers

| Name          | Type   | Description  |
| ------------- | ------ | ------------ |
| Authorization | string | Access-Token |

{% tabs %}
{% tab title="200 Cake successfully retrieved." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "user": {
            "id": 1553,
            "email": "haonh@magik.vn"
        },
        "business": {
            "id": 1540,
            "name": "Hữu Hảo"
        },
        "bankAccs": [
            {
                "id": 69,
                "bank": {
                    "bin": 970416,
                    "codeName": "acb_digi"
                },
                "bankAccountName": null,
                "bankSubAccId": "17271687",
                "connectStatus": 1,
                "planStatus": 1
            },
            {
                "id": 63,
                "bank": {
                    "bin": 970454,
                    "codeName": "timoplus"
                },
                "bankAccountName": null,
                "bankSubAccId": "8007041023848",
                "connectStatus": 1,
                "planStatus": 0
            }
        ]
    }
}
```

{% endtab %}

{% tab title="401 Could not find a cake matching this query." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request GET 'https://oauth.casso.vn/v1/userInfo \
--header 'Authorization: Access token'
```


# API thiết lập webhook

Thay vì thiết lập webhook thủ công thì nay Casso cung cấp endpoint để có thể thiết lập webhook tự động.

## &#x20;Tạo webhook

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v1/webhooks`

Thực hiện tạo webhook tới server của bạn

#### Headers

| Name          | Type   | Description       |
| ------------- | ------ | ----------------- |
| Authorization | string | chứa Access-Token |

#### Request Body

| Name          | Type    | Description                                                            |
| ------------- | ------- | ---------------------------------------------------------------------- |
| income\_only | boolean | là giá trị được thiết lập để có gửi webhook đối với tiền vào hay không |
| secure\_token | string  | mã bảo mật                                                             |
| webhook       | string  | đường dẫn tới api đầu nhận webhook server của bạn                      |

{% tabs %}
{% tab title="200 Response thông tin webhook đã tạo thành công." %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 114,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạn." %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request POST 'https://oauth.casso.vn/v1/webhooks' \
--header 'Authorization: Access token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/wc/handler-bank-transfer.php",
    "secure_token": "@123#abc",
    "income_only": true
}'
```

## &#x20;Chi tiết

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v1/webhooks/:id`

Xem chi tiết các thông về webhook của bạn theo `webhook Id`

#### Path Parameters

| Name | Type   | Description                        |
| ---- | ------ | ---------------------------------- |
| id   | string | `id webhook` bạn muốn xem chi tiết |

#### Headers

| Name          | Type   | Description    |
| ------------- | ------ | -------------- |
| Authorization | string | `Access-Token` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://ten-mien-cua-ban.com.vn/wc/handler-bank-transfer.php",
        "param2": "",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request GET 'https://oauth.casso.vn/v1/webhooks/134' \
--header 'Authorization: Access-Token'
```

## &#x20;Cập nhật &#x20;

<mark style="color:orange;">`PUT`</mark> `https://oauth.casso.vn/v1/webhooks/:id`

Cập nhật các thông tin trong webhook đã được thiết lập trước đó

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description  |
| ------------- | ------ | ------------ |
| Authorization | string | access token |

#### Request Body

| Name          | Type    | Description                                       |
| ------------- | ------- | ------------------------------------------------- |
| income\_only  | boolean | xác nhận gửi webhook tiền vào                     |
| secure\_token | string  | mã bảo mật                                        |
| webhook       | string  | đường dẫn tới đầu api nhận webhook server của bạn |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://webhook-cua-ban.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request PUT 'https://oauth.casso.vn/v1/webhooks/111' \
--header 'Authorization: Access-Token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "webhook": "https://ten-mien-cua-ban.com/api/bank",
    "secure_token": "@xyz@123",
    "income_only": "false"
}'
```

## &#x20;Xoá một webhook

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v1/webhooks/:id`

Thực hiện xóa một webhook bằng `id webhook` &#x20;

#### Path Parameters

| Name | Type   | Description  |
| ---- | ------ | ------------ |
| id   | string | `id webhook` |

#### Headers

| Name          | Type   | Description    |
| ------------- | ------ | -------------- |
| Authorization | string | `Access-Token` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 111,
        "channel": "webhook",
        "param1": "https://khanh-dep-trai.com.vn",
        "param2": "sdf",
        "send_only_income": 1
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request DELETE 'https://oauth.casso.vn/v1/webhooks/85' \
--header 'Authorization: Access-Token'
```

## &#x20;Xoá tất cả webhook trong đường dẫn &#x20;

<mark style="color:red;">`DELETE`</mark> `https://oauth.casso.vn/v1/webhooks`

Xóa tất cả các webhook đang tồn tại trong đường dẫn webhook trùng với đường dẫn của bạn *( Nếu đã tạo trước đó rồi thì phải xóa mà đúng không! )*

#### Query Parameters

| Name    | Type   | Description                                       |
| ------- | ------ | ------------------------------------------------- |
| webhook | string | đường dẫn tới đầu api nhận webhook server của bạn |

#### Headers

| Name          | Type   | Description    |
| ------------- | ------ | -------------- |
| Authorization | string | `Access-Token` |

{% tabs %}
{% tab title="200 " %}

```
{
    "error": 0,
    "message": "success",
    "data": [
        {
            "id": 108,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 109,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
        {
            "id": 110,
            "channel": "webhook",
            "param1": "https://ten-mien-cua-ban.com/wc/handler.php",
            "param2": "",
            "send_only_income": 1
        },
    ]
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}

{% tab title="404 " %}

```
{
    "error": 12,
    "message": "Webhook not exists",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request DELETE 'https://oauth.casso.vn/v1/webhooks?webhook=https://websitecuaban.com/api/webhook' \
--header 'Authorization: Access-Token'
```


# API tải thông tin giao dịch

Lấy toàn bộ giao dịch dựa theo thời gian tuỳ chọn cho đến hiện tại.

## &#x20;Lấy thông tin giao dịch ngân hàng &#x20;

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v1/transactions`

API này cho phép lấy toàn bộ thông tin giao dịch ngân hàng theo `Query Parameters`

#### Query Parameters

| Name     | Type    | Description                                                                             |
| -------- | ------- | --------------------------------------------------------------------------------------- |
| sort     | string  | Sắp xếp tăng hoặc giảm dần dựa theo thời gian của giao dịch. Mặc định là ASC(tăng dần). |
| pageSize | string  | Kích thước của trang                                                                    |
| page     | integer | Số thứ tự trang                                                                         |
| fromDate | string  | Lấy giao dịch bắt đầu từ ngày. Định dạng: YYYY-MM-                                      |

#### Headers

| Name          | Type   | Description  |
| ------------- | ------ | ------------ |
| Authorization | string | Access-Token |

{% tabs %}
{% tab title="200 Response chi tiết các giao dịch ngân hàng" %}
{% tabs %}
{% tab title="Response giao dịch" %}

```
{
    "error": 0,
    "message": "success",
    "data": [
        {
            "id": 3267,
            "tid": "TF210403249039850",
            "description": "refund",
            "amount": 70000000,
            "cusum_balance": 7303904,
            "when": "2021-04-03"
        },
        {
            "id": 3268,
            "tid": "TF210403249040659",
            "description": "chuyen tien tro T4",
            "amount": 1767000,
            "cusum_balance": 5536904,
            "when": "2021-04-03"
        },
    ]
}
```

{% endtab %}

{% tab title="Response theo page" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "page": 4,
        "pageSize": 10,
        "nextPage": 5,
        "prevPage": 3,
        "totalPages": 35,
        "totalRecords": 341,
        "records": [
            {
                "id": 5789,
                "tid": "TF210415239581402",
                "description": "chuyen tien",
                "amount": -193000,
                "cusum_balance": 1070904,
                "when": "2021-04-15"
            },
            {
                "id": 5790,
                "tid": "TF210415299602811",
                "description": "Chuyen tien nap momo",
                "amount": -350000,
                "cusum_balance": 720904,
                "when": "2021-04-15"
            },
        ]
    }
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Access-Token không đúng hoặc đã hết hạn" %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

#### Chi tiết các tham số

| Tham số        | Mô tả                                                                                    | Gá trị mặc định |
| -------------- | ---------------------------------------------------------------------------------------- | --------------- |
| ***fromDate*** | Thời gian bắt đầu bạn muốn lấy giao                                                     | 7 ngày gần nhất |
| ***page***     | Số thứ tự trang                                                                          | 1               |
| ***pageSize*** | Số item trên một trang                                                                   | 10              |
| ***sort***     | Sắp xếp giao dịch, các giá trị gồm: ASC, DESC. Với ASC là tăng dần còn DESC là giảm dần. | ASC             |

{% hint style="info" %}
Nếu tham số nào không tồn tại thì sẽ lấy giá trị mặc định.
{% endhint %}

```
curl --location --request GET 'https://oauth.casso.vn/v1/transactions?fromDate=2021-04-01&page=4&pageSize=20&sort=ASC' \
--header 'Authorization: Access token'
```

## Lấy chi tiết thông tin giao dịch theo id giao dịch

<mark style="color:blue;">`GET`</mark> `https://oauth.casso.vn/v1/transactions/:id`

#### Path Parameters

| Name | Type   | Description                      |
| ---- | ------ | -------------------------------- |
| id   | number | `id của giao dịch trên hệ thống` |

#### Headers

| Name          | Type   | Description  |
| ------------- | ------ | ------------ |
| Authorization | string | Access-Token |

{% tabs %}
{% tab title="200 Thông tin chi tiết của 1 giao dịch" %}

```
{
    "error": 0,
    "message": "success",
    "data": {
        "id": 314344,
        "tid": "TF210702253136879",
        "description": "DH220",
        "amount": -10000,
        "cusumBalance": 389460,
        "when": "2021-07-02",
        "bankSubAccId": "8007041023848"
    }
}
```

{% endtab %}

{% tab title="401 " %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request GET 'https://oauth.casso.vn/v1/transactions/123 \
--header 'Authorization: Access token'
```


# API check giao dịch mới

## &#x20;Đồng bộ giao dịch với số tài khoản tương&#x20;

<mark style="color:green;">`POST`</mark> `https://oauth.casso.vn/v1/sync`

Đồng bộ giao dịch mới tương ứng với số tài khoản của bạn trong business

#### Headers

| Name           | Type   | Description |
| -------------- | ------ | ----------- |
| Authentication | string | Access      |

#### Request Body

| Name          | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| bank\_acc\_id | string | Số tài khoản liên kết trên hệ thống |

{% tabs %}
{% tab title="200 Sync successfully." %}
{% tabs %}
{% tab title="Đồng bộ giao dịch thành công" %}

```
{
    "error": 0,
    "message": "success",
    "data": null
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401 Token sai hoặc hết hạn" %}

```
{
    "error": 401,
    "message": "Unauthorized Access",
    "data": null
}
```

{% endtab %}
{% endtabs %}

```
curl --location --request POST 'https://oauth.casso.vn/v1/sync' \
--header 'Authorization: Access-Token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "bank_acc_id": "Số tài khoản ngân hàng cần đồng bộ"
}'
```


# Tài khoản ngân hàng Demo

Để thuận tiện trong quá trình phát triển, chúng tôi cung cấp một tài khoản ngân hàng test.&#x20;

Các tài khoản này sẽ được tạo sẵn giao dịch và thông tin tương tự như tài khoản thật, có thể để dùng để test

| Username     | Password |
| ------------ | -------- |
| bankusrdemo1 | (bất kì) |


