---
name: cas-balance-hook
description: "Integrate Cas Balance Hook (scopes: qrpay, virtual_account): integration steps, the APIs to call and the pre-production checklist."
---

# Cas — Balance Hook

> Source: https://cas.so/en/product/balance-hook · Markdown: https://cas.so/en/product/balance-hook.md

_This skill is generated from the Cas documentation. When you need details (schemas, error codes, examples), fetch the latest Markdown from the links below instead of guessing._

## When to use this skill

When integrating, extending or debugging Cas **Balance Hook** in your system.

## Product summary

Balance Hook is an event webhook provided by Cas to instantly notify you of any balance changes on a linked bank account or virtual account (VA).

Whenever a user deposits, withdraws, or triggers a transaction that alters the account balance, your system will receive a POST call from Cas. This allows you to process transactions quickly and automatically without the need for constant polling.

## Scopes

`qrpay` · `virtual_account`

## Integration flow

Below are the steps to integrate the Balance Hook into your product.

1. Create a permission [/grant/token](https://cas.so/en/general/api/grant/create.md) with the `scopes` value set to `qrpay` or `virtual_account`.
   - **user** (optional): the customer information already stored in your system, used to prefill the linking form
     on Cas Link and to help verify the account information. [See details](#user-info)

2. Open the Cas Link interface using the returned grantToken to let users link their bank accounts. See details

3. Receive the publicToken once the user completes the linking process, and use it to obtain an accessToken.

4. Configure the webhook endpoint to receive notifications — CAS.SO will send balance change data whenever a new transaction occurs.

#### Customer information (`user`) {#user-info}

`user` is an **optional** field when creating a grant. If your system already stores the customer's information, send it so that Cas Link can:

- **Prefill the linking form**: Cas Link fills in the account holder name, identification number, phone number and email,
so the user does not have to re-enter what you already have.
- **Validate the bank account**: with `scopes` set to `qrpay`, Cas Link compares the information you send with the account
information returned by the bank; if the account holder name or the identification number does not match, the linking flow
is stopped and an error is shown to the user.

| Field | Type | Description |
| --- | --- | --- |
| `legalName` | string | Account holder name (individual) |
| `idNumber` | string | Personal identification number (ID card) of the account holder |
| `companyName` | string | Company name |
| `companyLegalId` | string | Tax code / business registration number |
| `mobileNumber` | string | Phone number registered with the bank |
| `email` | string | Customer email |

:::note
Depending on whether the financial service is of type **personal** or **enterprise**, send either
`legalName`/`idNumber` or `companyName`/`companyLegalId`. Any field you omit is skipped during the comparison.
:::

## APIs used in this flow

- [Create grant token](https://cas.so/en/general/api/grant/create.md)
- [Exchange public token for an access token](https://cas.so/en/general/api/grant/exchange.md)
- [Webhook](https://cas.so/en/general/api/webhook.md)

## Read before writing code

- [Cas core](https://cas.so/en/skills/cas-core/SKILL.md)
- [Cas Link](https://cas.so/en/general/link.md)
- [Webhook](https://cas.so/en/general/api/webhook.md)
- [Errors](https://cas.so/en/errors.md)

## Rules you must follow when writing code

- `clientId` / `secretKey` live on the server in environment variables only — never ship them to a client, never commit them.
- Request only the `scopes` the product needs; extra scopes mean extra cost and risk.
- Avoid duplicate grants: check your database for a live grant before opening Cas Link again.
- Store `accessToken` and `grantId` encrypted and linked to your user; one user may hold several grants. Never surface these values in the UI.
- Log `requestId` (on every response) and `grantId` (on grant-related responses) for every call — this is what Cas support needs to trace an issue.
- Every API call needs a timeout and backoff retry for transient failures; never blindly retry money-moving calls (use your own idempotency key).
- Webhooks: accept them only from Cas IPs, return 2xx fast and process asynchronously, and make handling idempotent — deliveries can repeat or arrive out of order.
- Handle `GRANT_LOGIN_REQUIRED` by reopening Cas Link in Update mode instead of making the user relink from scratch.
- Handle `GRANT` webhooks: `USER_PERMISSION_REVOKED`, `GRANT_DELETED`, `GRANT_PAUSED`, `DEFAULT_UPDATE` — reflect the link state in your system.
- Call `/grant/remove` when a user unlinks in your app, and handle the OTP-verification branch.
- Run the whole flow on `https://sandbox.bankhub.dev` first; switch to `https://production.bankhub.dev` together with the production secrets.

## Before going to production

Verify against the **entire** production checklist: https://cas.so/en/launch-checklist.md

For every checklist item, point at the code (file path + line) that proves it is handled, or state why it does not apply. Never tick an item without evidence.

## Other Cas skills

Full catalogue (use it to add more Cas products later):

https://cas.so/en/skills/index.json
