# Thiết lập Webhook blockchain: Chữ ký, loại bỏ trùng lặp và phát lại

> Source: https://docs.blockvectra.com/vi/guides/webhook-push/

Theo dõi địa chỉ ví EVM và nhận các giao dịch chuyển đồng gốc, chuyển token và log hợp đồng phù hợp tại endpoint HTTPS của bạn để nhận thông báo hoạt động ví hoặc giám sát sự kiện hợp đồng thông minh. Nhà phát triển và AI Agent sử dụng cùng một API đăng ký qua HTTP. Đối với thông báo thanh toán ERC-20 USDT / USDC, hãy làm theo [đầu nhận thanh toán stablecoin](https://docs.blockvectra.com/en/guides/stablecoin-payments/#receive-payments-with-webhooks).

## Các nhiệm vụ hướng dẫn này giúp bạn hoàn thành

* [Nhận hoạt động địa chỉ ví](#connect-wallet-address-activity) bằng cách tạo một đăng ký đã xác thực, thêm các địa chỉ được theo dõi và xác minh các sự kiện gửi đến.
* [Giám sát các log hợp đồng phù hợp](#event-format) bằng cách kiểm tra các sự kiện `log` cho các địa chỉ được theo dõi và lọc `address`, `topics` cùng `data` trong đầu nhận của bạn.
* [Khôi phục quá trình chuyển phát bị gián đoạn](#delivery-retries-and-replay) bằng cách kiểm tra tiến độ đăng ký và phát lại các mục khớp được lưu giữ, sau đó backfill các khoảng trống nằm ngoài cửa sổ phát lại.

Một đăng ký kết hợp một URL nhận HTTPS, một chuỗi secret ký, các địa chỉ EVM được theo dõi và một đối tượng `chains` bắt buộc. Các địa chỉ áp dụng cho mọi chuỗi trong đối tượng đó. Sử dụng API với header `x-api-key`; bất kỳ key đang hoạt động nào trong tài khoản của bạn đều có thể quản lý tất cả các đăng ký của nó. [Lấy API key](https://blockvectra.com/en/get-api-key/) trước khi bắt đầu. [Push OpenAPI](https://docs.blockvectra.com/openapi/push.yaml) liệt kê mọi thao tác và lược đồ webhook.

## Kết nối hoạt động địa chỉ ví

1. Triển khai một đầu nhận [xác minh nội dung yêu cầu gốc](#verify-signatures), lưu bền vững các sự kiện theo `id` và xác nhận chúng trong vòng 10 giây.
2. Đọc `GET /v1/push/chains`, sau đó [tạo một đăng ký](#create-a-subscription) với URL HTTPS của bạn và các chuỗi đã chọn. Lưu `id` và `secret` được trả về.
3. [Thêm các địa chỉ ví](#add-and-list-addresses). Chờ cho đến khi `applied_version >= change_version` và ghi lại `applied_from_block` của từng chuỗi; việc khớp sự kiện bắt đầu từ đó.
4. Xử lý các giao dịch chuyển và log, đồng thời [khôi phục các khoảng trống hoặc các khối bị thay thế](#delivery-retries-and-replay). Lọc các hợp đồng token, người nhận và số tiền nguyên trước khi sử dụng thông báo trong xử lý thanh toán.

## Chọn Webhook, WebSocket hoặc polling

* **Webhook** gửi các sự kiện của địa chỉ được theo dõi đến một đầu nhận HTTPS, với tính năng thử lại chuyển phát và phát lại các mục khớp được lưu giữ.
* **[WebSocket](https://docs.blockvectra.com/en/guides/websocket-subscriptions/)** truyền luồng `newHeads` và `logs` đã lọc qua một kết nối liên tục. Kết nối lại, đăng ký lại và truy vấn các khối bị bỏ lỡ sau khi ngắt kết nối.
* **[Polling](https://docs.blockvectra.com/en/guides/stablecoin-payments/)** truy vấn `eth_getLogs` trong các khoảng khối có giới hạn bằng cursor của riêng bạn; sử dụng phương thức này để giám sát thanh toán hoặc backfill các log bị thiếu.

Kiểm tra `ws` và `subscriptions` trong `GET /v1/chains` để biết khả năng hỗ trợ WebSocket. Nếu `ws` là false, webhook địa chỉ vẫn là một lựa chọn khi chuỗi đó xuất hiện trong danh sách `GET /v1/push/chains` có xác thực. Chỉ riêng việc hỗ trợ RPC không xác lập việc hỗ trợ Push.

## Dung lượng địa chỉ

Tự phục vụ hỗ trợ tối đa 1,000,000 địa chỉ cho mỗi đăng ký và có sẵn ngay sau khi đăng ký. Một đăng ký bao phủ nhiều chuỗi với một URL nhận. Dung lượng doanh nghiệp hỗ trợ 10,000,000 / 100,000,000 địa chỉ cho mỗi đăng ký; [liên hệ với chúng tôi để kích hoạt](https://blockvectra.com/en/contact/). Nhà phát triển và AI Agent có cùng lựa chọn dung lượng và mức giá. Cả hai gói đều sử dụng cùng mức giá theo địa chỉ-ngày và sự kiện đã chuyển phát được hiển thị trong [bảng giá](https://blockvectra.com/en/pricing/).

## Tạo đăng ký

Đọc `GET /v1/push/chains` để biết các chuỗi khả dụng cùng số lượng xác nhận tối thiểu, mặc định và tối đa của chúng. Một khối được giải phóng khi `head - block + 1 >= confirmations`. Mỗi chuỗi có thể sử dụng giá trị mặc định của nó bằng cách cung cấp `{}`. Bắt buộc phải có ít nhất một chuỗi; các chuỗi mới không tự động tham gia vào các đăng ký hiện có.

Lưu ví dụ sau thành `create.json`, thay thế URL bằng đầu nhận của bạn và chọn các chuỗi từ danh sách chuỗi. URL phải sử dụng HTTPS trên cổng 443, một hostname thay vì IP dạng chuỗi, và không chứa thông tin người dùng hoặc fragment.

```json
{
  "url": "https://hooks.example.com/push",
  "chains": {
    "bsc_mainnet": {
      "confirmations": 1
    },
    "base_mainnet": {}
  }
}
```

Thiết lập `BLOCKVECTRA_API_KEY` trong môi trường của bạn, sau đó chạy:

```bash
PUSH_URL='https://api.blockvectra.com/v1/push'
curl --fail-with-body -sS "$PUSH_URL/chains" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
curl --fail-with-body -sS "$PUSH_URL/subscriptions" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d @create.json > subscription.json
```

Một lần tạo thành công trả về HTTP 201 và một đăng ký `online` không có địa chỉ nào. Lưu trữ `id` dạng số và `secret` của nó một cách an toàn. Secret chỉ được trả về khi tạo hoặc khi gọi `POST /subscriptions/{subscription_id}/rotate-secret`; việc xoay vòng secret có hiệu lực ngay lập tức trên tất cả các chuỗi mà không có khoảng gối đầu. Không có tin nhắn thử nghiệm nào được gửi.

## Thêm và liệt kê địa chỉ

Lưu một đợt địa chỉ dưới dạng `addresses.json`, thay thế các địa chỉ mẫu bằng các địa chỉ bạn theo dõi:

```json
{
  "addresses": [
    "0x9725db73f2cd8657f3e1841e5689f210ee54a92d",
    "0x99d47bB552ae095159C251836De6A5d524076872"
  ]
}
```

Đặt `SUBSCRIPTION_ID` thành ID đăng ký được trả về:

```bash
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID/addresses/add" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' -d @addresses.json
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID/addresses" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```

Mỗi lệnh gọi thêm chấp nhận tối đa 10,000 địa chỉ. Địa chỉ đầu vào là chữ thường hoặc chữ hoa chữ thường kết hợp EIP-55 hợp lệ; đầu vào không hợp lệ sẽ từ chối toàn bộ lô. Các địa chỉ lặp lại được tính là `unchanged`, do đó việc gửi lại cùng một yêu cầu thêm là an toàn. Danh sách địa chỉ sử dụng `limit` và `page_token`; `next_page_token: null` đánh dấu trang cuối cùng.

Việc thêm địa chỉ trả về `change_version`. Polling hoặc kiểm tra `GET /subscriptions/{subscription_id}` cho đến khi `applied_version >= change_version`; các thay đổi thường mất khoảng 1 giây để áp dụng. `applied_from_block` của từng chuỗi xác định khối có hiệu lực mà từ đó các giao dịch on-chain và log được khớp. Địa chỉ mới không được khớp hồi tố.

Việc tạo đăng ký trả về HTTP 201 để xác nhận tài nguyên đăng ký đã được tạo; HTTP 201 không có nghĩa là đầu nhận của bạn đã nhận được bất kỳ đợt push webhook nào. Nền tảng không gửi tin nhắn xác minh hoặc thử nghiệm khi tạo hoặc khi đăng ký địa chỉ. Bạn phải chờ cho đến khi hoạt động on-chain phù hợp xảy ra trên các địa chỉ và chuỗi được theo dõi để xác minh việc chuyển phát tại đầu nhận của bạn.

## Định dạng sự kiện

Mỗi yêu cầu POST có `type: push.events`, `created_at` và `data`. `data` chứa `subscription_id`, một `chain`, `complete_through_block` và `events`. Ghi lại tiến độ theo từng chuỗi: một khối có thể trải rộng trên nhiều tin nhắn, do đó số hiệu khối của từng sự kiện đơn lẻ không phải là dấu mốc hoàn thành. Mỗi tin nhắn chứa tối đa 1,000 sự kiện, 1 MiB và 50 khối.

```json
{
  "type": "push.events",
  "created_at": "2026-10-02T03:00:05Z",
  "data": {
    "subscription_id": 48213,
    "chain": "bsc_mainnet",
    "complete_through_block": 64000121,
    "events": [
      {
        "id": "evt_payvsqb6ogymhmehrs2wl5xcky",
        "type": "native.transfer",
        "ref": "eip155:56:0x7b19944dc683c33e8dedba259cb6939f7271f70f2eeb6ca5e456cccb57cc1eff:tx",
        "from": "0xe0a2100d7dad33f70c4bb765323cb96b2400c844",
        "to": "0x9725db73f2cd8657f3e1841e5689f210ee54a92d",
        "amount": "150000000000000000",
        "block_number": 64000120,
        "block_hash": "0x327892a3e5699a43981f0fbcc5e490628641d92c040eb0429fb550ba3a73c3bf",
        "block_timestamp": "2026-10-02T03:00:00Z",
        "tx_hash": "0x7b19944dc683c33e8dedba259cb6939f7271f70f2eeb6ca5e456cccb57cc1eff",
        "tx_index": 3,
        "matched": [
          {
            "address": "0x9725db73f2cd8657f3e1841e5689f210ee54a92d",
            "role": "to"
          }
        ]
      },
      {
        "id": "evt_lgcdattb6l2k3ejuhe4mtdljkm",
        "type": "token.transfer",
        "ref": "eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:7",
        "standard": "erc20",
        "token": "0x55d398326f99059ff775485246999027b3197955",
        "from": "0x0f94e5283c41c29a8f4dff8c17f68bdfb59f07df",
        "to": "0x99d47bb552ae095159c251836de6a5d524076872",
        "token_id": null,
        "amount": "25000000000000000000",
        "batch_index": null,
        "block_number": 64000121,
        "block_hash": "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15",
        "block_timestamp": "2026-10-02T03:00:00Z",
        "tx_hash": "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76",
        "tx_index": 5,
        "log_index": 7,
        "matched": [
          {
            "address": "0x99d47bb552ae095159c251836de6a5d524076872",
            "role": "to"
          }
        ]
      },
      {
        "id": "evt_sgliw3ficdf6gaa6zzx4ew6vni",
        "type": "log",
        "ref": "eip155:56:0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76:8",
        "address": "0xb54ffbe723264b84cf74947127a6914cf87fc593",
        "topics": [
          "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
          "0x00000000000000000000000099d47bb552ae095159c251836de6a5d524076872",
          "0x000000000000000000000000b54ffbe723264b84cf74947127a6914cf87fc593"
        ],
        "data": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "block_number": 64000121,
        "block_hash": "0x6a8146159162f182c091d17eac7d03e95dc92ce80de704c958ca2528306aff15",
        "block_timestamp": "2026-10-02T03:00:00Z",
        "tx_hash": "0x3be3448e6f54ebfa928d5997a0cb2d5e9d3186c5ebfa293ad45b7edc72483a76",
        "tx_index": 5,
        "log_index": 8,
        "matched": [
          {
            "address": "0x99d47bb552ae095159c251836de6a5d524076872",
            "role": "topic1"
          }
        ]
      }
    ]
  }
}
```

| Loại sự kiện       | Nội dung cần xử lý                                                                                                                                                                                                                                            |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `native.transfer`  | Các giao dịch chuyển đồng gốc cấp cao nhất thành công liên quan đến một địa chỉ được theo dõi; `amount` là một chuỗi thập phân số nguyên. Các giao dịch chuyển đồng gốc nội bộ không bao gồm.                                                                 |
| `token.transfer`   | Chuyển giao ERC-20, ERC-721 và ERC-1155 liên quan đến các địa chỉ được theo dõi; kiểm tra `standard`, `token`, `token_id`, `amount` và `batch_index`. Chuyển giao theo lô ERC-1155 tạo ra một sự kiện cho mỗi mục.                                            |
| `log`              | Các log khác ghi nhận một địa chỉ được theo dõi là hợp đồng phát ra hoặc nằm trong topics 1–3; kiểm tra `address`, `topics`, `data` và `matched`.                                                                                                             |
| `subscription.gap` | Một khoảng từ `from_block` đến `to_block` không khả dụng để chuyển phát, với `reason: retention_expired`; hãy backfill bằng Data API hoặc `eth_getLogs`.                                                                                                      |
| `chain.reorg`      | Thông báo reorg miễn phí: các khối đã chuyển phát trong `from_block`–`to_block` đã bị thay thế. Đánh dấu hoặc loại bỏ các sự kiện cũ của chúng theo `ref`, sau đó giữ các sự kiện chính thức (canonical) được tự động gửi lại và loại bỏ trùng lặp theo `id`. |

Trong một đăng ký, hãy loại bỏ trùng lặp theo `id` sự kiện; giữa các đăng ký, hãy sử dụng `ref` và `type`. Bỏ qua các trường và loại sự kiện không xác định. Xác minh các sự kiện on-chain trước khi thực hiện hành động tài chính.

## Xác minh chữ ký

Các header là `webhook-id`, `webhook-timestamp`, `webhook-signature` và `bv-subscription-id`. Chỉ chọn secret từ các đăng ký bạn đã tạo; từ chối các ID không xác định. Xác minh HMAC-SHA256 trên `webhook-id.webhook-timestamp.raw-body`, sử dụng các byte của nội dung yêu cầu gốc, trước khi phân tích cú pháp JSON. Chữ ký có dạng `v1,<base64>`; cho phép độ lệch timestamp khoảng 5 phút và so sánh theo thời gian không đổi (constant time).

Hàm Node.js này chấp nhận nội dung gốc dưới dạng `Buffer`, các header yêu cầu và một map chứa ID đăng ký ánh xạ tới các secret đã lưu trữ:

```js
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyPush(rawBody, headers, secrets) {
  const subscriptionId = headers['bv-subscription-id'];
  const id = headers['webhook-id'];
  const timestamp = headers['webhook-timestamp'];
  const signature = headers['webhook-signature'];
  if ([subscriptionId, id, timestamp, signature].some(v => typeof v !== 'string')) return false;
  const secret = secrets.get(subscriptionId);
  if (typeof secret !== 'string' || !secret.startsWith('whsec_')) return false;
  if (!/^\d{10}$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const match = /^v1,([A-Za-z0-9+/]{43}=)$/.exec(signature);
  if (!match) return false;
  const received = Buffer.from(match[1], 'base64');
  const expected = createHmac('sha256', Buffer.from(secret.slice(6), 'base64'))
    .update(`${id}.${timestamp}.`).update(rawBody).digest();
  return received.length === expected.length && timingSafeEqual(received, expected);
}
```

Sau khi xác minh, hãy phân tích cú pháp nội dung, lưu bền vững việc xử lý và trả về 2xx trong vòng 10 giây. Header ID đăng ký là không đáng tin cậy cho đến khi chữ ký được xác minh.

## Xác minh sự kiện đầu tiên của bạn

Giữ đăng ký ở trạng thái online. Sau khi thay đổi địa chỉ được áp dụng, hãy chờ hoạt động on-chain phù hợp và kiểm tra xem đầu nhận của bạn có xác minh và lưu trữ bền vững sự kiện hay không.

## Dừng lắng nghe sau khi xác minh

<a id="stop-listening-and-clean-up" />

Để dừng theo dõi các địa chỉ, hãy lưu các địa chỉ cần xóa trong `addresses.json` và gọi `POST /subscriptions/{subscription_id}/addresses/remove`:

```bash
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID/addresses/remove" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' -d @addresses.json
```

Mỗi lệnh gọi xóa chấp nhận tối đa 10,000 địa chỉ. Một địa chỉ hiện không được theo dõi sẽ được tính là `unchanged`. Lệnh gọi trả về `change_version`. Khi `applied_version >= change_version`, các khối từ khối có hiệu lực đó trở đi sẽ không còn khớp với các địa chỉ đã xóa. Các sự kiện đã khớp trước đó (đang trên đường gửi, đang thử lại hoặc đang xếp hàng) vẫn sẽ được chuyển phát; các sự kiện đã được chuyển phát sẽ không bị thu hồi.

Để tạm thời dừng lắng nghe mà không xóa cấu hình hoặc địa chỉ, hãy đặt `status` thành `offline`:

```bash
curl --fail-with-body -sS -X PATCH "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"offline"}'
```

Một đăng ký `offline` sẽ dừng lắng nghe và chuyển phát, dỡ các địa chỉ khỏi chỉ mục khớp, và không phát sinh phí địa chỉ cho bất kỳ ngày UTC trọn vẹn nào mà nó duy trì trạng thái offline. Tất cả cấu hình (URL, secret, địa chỉ, chuỗi và số xác nhận) đều được giữ nguyên. Cập nhật `{"status":"online"}` sẽ tiếp tục lắng nghe từ khối có hiệu lực hiện tại và không backfill khoảng thời gian offline.

Sử dụng JSON Merge Patch trên `PATCH /subscriptions/{subscription_id}` để thay đổi `url`, `key_id`, `status` hoặc `chains`: một đối tượng chuỗi sẽ thêm hoặc cập nhật nó, và `null` sẽ xóa nó. Phải giữ lại ít nhất một chuỗi. Để xóa vĩnh viễn đăng ký:

```bash
curl --fail-with-body -sS -X DELETE "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```

`DELETE` xóa vĩnh viễn đăng ký, dừng chuyển phát trên tất cả các chuỗi ngay lập tức, và hủy secret cùng các địa chỉ.

## Chuyển phát, thử lại và phát lại

Việc chuyển phát diễn ra ít nhất một lần. Chuỗi của mỗi đăng ký được sắp xếp theo khối và vị trí trong khối; các lô thất bại sẽ chặn các sự kiện sau đó trên chuỗi đó. Các chuỗi khác nhau có tiến độ độc lập và có thể POST đồng thời. Lần thử lại của một lô giống hệt nhau giữ nguyên `webhook-id`, nhưng một lô bị thay đổi có thể có ID mới: hãy loại bỏ trùng lặp sự kiện, không phải theo lô.

Bất kỳ mã 2xx nào trong vòng 10 giây đều xác nhận việc xử lý bền vững. Chuyển hướng không được tuân theo; 3xx và 410 được coi là thất bại. Sau một thất bại, các lần thử lại tuân theo các khoảng thời gian ngay lập tức, 5 giây, 30 giây, 2 phút, 10 phút, 30 phút và 1 giờ, sau đó là hàng giờ. Mã 429 kèm `Retry-After` có thể kéo dài thời gian chờ lên tới một giờ. Kiểm tra `condition`, `last_error` và `next_attempt_at` của từng chuỗi khi việc chuyển phát dừng lại. Các trạng thái condition bao gồm `receiver_failing`, `insufficient_balance` và `key_revoked`; trường hợp cuối cùng yêu cầu patch `key_id` sang một key tài khoản đang hoạt động khác.

Các sự kiện chưa được chuyển phát sẽ hết hạn ngoài cửa sổ lưu giữ và tạo ra `subscription.gap`. `POST /subscriptions/{subscription_id}/replay` nhận `chain` và `from_block`; hãy tham khảo `replayable_from_block` trong `GET /push/chains` và tiến độ của đăng ký. Replay chuyển phát các mục khớp hiện có và không thể khôi phục các sự kiện từ trước khi một địa chỉ hoặc chuỗi được thêm vào.

`chain.reorg` thông báo cho bạn rằng các khối đã được chuyển phát trước đó đã bị thay thế; nó không biểu thị một khoảng trống chuyển phát. Các đợt reorg nông hơn số xác nhận của bạn sẽ vô hình. Đối với các đợt reorg ảnh hưởng đến các khối đã chuyển phát sâu tới 1,024 khối, các sự kiện chính thức (canonical) sẽ được tự động chuyển phát lại với `id` mới. Đánh dấu hoặc loại bỏ các sự kiện bị thay thế theo `ref`, giữ lại các sự kiện chính thức và loại bỏ trùng lặp theo `id`; đối với các bản ghi thanh toán, hãy đối chiếu theo `ref` và `tx_hash`. Một đợt reorg sâu hơn sẽ tạm dừng chuỗi: kiểm tra `halted` trong `GET /push/chains`; việc chuyển phát lại sự kiện chính thức sẽ tiếp tục sau khi chuỗi được khôi phục. Sự kiện điều khiển không làm tăng `complete_through_block`.

Truy vấn các sự kiện dữ liệu đã chuyển phát bằng `GET /subscriptions/{subscription_id}/events?chain=...`, có thể thêm tùy chọn `from_block`, `to_block`, `limit` và `page_token`. Các hàng lịch sử chứa `event`, `replay_epoch`, `orphaned` và `delivered_at`; `orphaned: true` đánh dấu một khối sau đó đã bị thay thế. Việc chấp nhận lịch sử có thể trả về 402 `insufficient_balance` (`data.reason`: `balance_exhausted` hoặc `free_grant_exhausted`), 403 `key_cap_exhausted` (`data.cu_cap`), hoặc 429 `rate_limited` (`key_rate_limit` hoặc `free_plan_call_limit`). Lỗi 429 `cost_exceeds_burst` có reason `request_exceeds_burst` và `data.max`: hãy tăng dung lượng burst trước khi thử lại. Xem [xử lý lỗi](https://docs.blockvectra.com/en/errors/) để biết các phạm vi không hợp lệ và hướng dẫn thử lại.

## Tính phí và ví dụ

Trọng số lấy từ `GET /v1/plans`. Các sự kiện dữ liệu đã chuyển phát, các yêu cầu lịch sử thành công và địa chỉ-ngày có các trọng số riêng biệt; các lệnh gọi quản lý khác ngoài lịch sử, sự kiện điều khiển, các lần chuyển phát thất bại và các lần thử lại tự động đều miễn phí. Mỗi sự kiện đã chuyển phát chỉ bị tính phí một lần; replay của khách hàng và việc chuyển phát lại sự kiện chính thức sẽ phát sinh phí chuyển phát mới.

Thanh toán địa chỉ sử dụng số lượng địa chỉ lớn nhất của mỗi đăng ký trong khoảng thời gian online của nó trong ngày UTC, sau hạn mức địa chỉ miễn phí của tài khoản được chia sẻ trên các đăng ký (đăng ký cũ hơn được ưu tiên trước). Cùng một địa chỉ trong hai đăng ký được tính hai lần; việc thêm chuỗi làm thay đổi phí sự kiện, không làm thay đổi phí địa chỉ. Một đăng ký offline trong toàn bộ ngày UTC sẽ không có phí địa chỉ.

| Mức sử dụng | Đơn vị thanh toán | CU |
| --- | --- | --- |
| `push.address_day` | Địa chỉ-ngày tính phí | 33 |
| `push.history` | Yêu cầu lịch sử thành công | 25 |
| `push.log` | Sự kiện dữ liệu đã gửi | 150 |
| `push.native_transfer` | Sự kiện dữ liệu đã gửi | 150 |
| `push.token_transfer` | Sự kiện dữ liệu đã gửi | 150 |

Địa chỉ miễn phí mỗi tài khoản mỗi ngày UTC: 1000

Hạn mức địa chỉ miễn phí cho mỗi tài khoản trong mỗi ngày UTC, được chia sẻ bởi tất cả các nhóm đăng ký bất kể gói dịch vụ. Đối với mỗi nhóm, tính số lượng địa chỉ tối đa khi trực tuyến trong ngày đó; phân bổ hạn mức theo thứ tự ID nhóm tăng dần. Cùng một địa chỉ trong hai nhóm được tính hai lần; số lượng chuỗi trong một nhóm không làm nhân số lượng địa chỉ. Một nhóm ngoại tuyến hoặc bị xóa trong cả ngày sẽ không đóng góp gì. Đối với mỗi nhóm, số lượng còn lại sau phần hạn mức sẽ được nhân với trọng số CU `push.address_day` trong `method_weights`. Hạn mức được định cấu hình hiện tại xuất phát từ cùng chính sách giá dùng cho phí địa chỉ-ngày; đây không phải là giới hạn dung lượng tài khoản hay hạn mức riêng cho từng nhóm.

Ví dụ: 10 sự kiện native.transfer đã gửi, 2 yêu cầu lịch sử thành công và 10 địa chỉ-ngày tính phí có chi phí 10 × 150 + 2 × 25 + 10 × 33 = 1880 CU. Địa chỉ-ngày tính phí được tính sau hạn mức địa chỉ miễn phí của tài khoản.

Xem [quy tắc thanh toán](https://docs.blockvectra.com/en/guides/billing-rules/) và [trang bảng giá](https://blockvectra.com/en/pricing/) để biết cách đo lường và quy đổi CU.

## Tài nguyên liên quan

* So sánh các sự kiện được hỗ trợ, độ bao phủ chuỗi và giá cả trong phần [Tổng quan về Blockchain Webhook API](https://blockvectra.com/en/webhooks/).
