ТарифыGitHubКабинет

Public API · Address Watch

Address Watch

Address Watch lets you subscribe to on-chain addresses and read the events they produce: value that arrived (payment), value that left (payout), and other transactions that touched the address. All routes require signed headers (see Authentication) and use the base URL from the Overview. Success responses carry ok: true plus the fields below; failures carry ok: false, error_code and error. Delivery of the same events to your server (webhook or WebSocket) is configured separately, see Webhooks and WebSockets.

addresseseventswebhookAddress Watch

← Public API

Flow diagram

How an address is watched and how its transactions reach you. You add an address once; every transaction that touches it produces events until you remove it.

Your serverPublic APIRpcNodeBlockchain1. POST/v1/address-watches {network_slug, address }2. { watch_id, status:active }, takes anaddress slot3. New block with atransaction to or fromthe address4. event=detected, type payment (in), payout (out) oraddress (other); charged once5. pending, confirmations, then confirmed or failed(free)Answer 2xx to awebhook. Usedelivery_id to ignorerepeats: the sameevent always has thesame delivery_id.Reconciling and stopping6. GET/v1/address-watches/events?before_id=…to read what you missed7. DELETE/v1/address-watches/{watchId}to stop watching and freethe slot
Solid arrows are requests, dashed arrows are answers, green arrows are what RpcNode pushes to you (webhook or WebSocket). Steps are numbered in time order.

Errors

Failed calls answer { ok: false, error_code, error } with an HTTP status. A request that cannot be accepted (wrong body, bad query value) is 400 with an errors list: every field that failed is named in it, and error_code is common.validation_failed when more than one field failed.

watch.network_required and watch.address_required (400): network_slug or address is empty or too long. watch.scan_not_enabled (400): the network key cannot be watched. watch.no_plan (400): the account has no plan.

watch.address_unavailable (403): the plan has no address slots. watch.address_limit (403): all slots are taken. watch.quota (429): too many adds or deletes today, this week or this month.

watch.invalid_event_type (400): event_type is not payment, payout or other. watch.not_found (404): unknown watch_id on delete.

watch.ingest_unavailable (503): temporarily unavailable, retry later. watch.save_failed (500): the watch could not be saved, retry.

Validation error

{
  "ok": false,
  "error_code": "common.validation_failed",
  "error": "Validation failed",
  "errors": [
    { "field": "per_page", "error_code": "common.validation_failed", "error": "per_page must be a whole number, from 1 to 100." },
    { "field": "before_id", "error_code": "common.validation_failed", "error": "before_id must be a uuid." }
  ]
}

GET /v1/address-watches/account

Address slots of the plan: how many there are and how many are taken, plus the webhook state.

Поля ответа

ИмяТипОписание
account.webhook_address_slotsnumberPlan cap for concurrently watched addresses. 0 means Address Watch is not available on the plan.
account.address_slots_usednumberNumber of active watched addresses.
account.webhook_urlstringConfigured webhook URL. Absent when none is set. (необязательно)
account.webhook_enabledbooleanWhether outbound webhook delivery is enabled (false when no webhook is configured).
  • Read-only summary. To change the webhook URL, secret or event networks use the Webhooks article (GET/PUT /v1/webhooks).

Пример запроса

import { createHash, createHmac } from 'node:crypto'

const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'

// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
  const timestamp = Math.floor(Date.now() / 1000)
  const bodyHash = createHash('sha256').update(body).digest('hex')
  const signature = createHmac('sha256', SECRET)
    .update([timestamp, method, path, bodyHash].join('\n'))
    .digest('hex')
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': String(timestamp),
      'X-Signature': signature,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body || undefined,
  })
  return res.json()
}

console.log(await call('GET', '/v1/address-watches/account'))

Запрос подписывается прямо в примере — правила подписи описаны в разделе Authentication.

Пример ответа

{
  "ok": true,
  "account": {
    "webhook_address_slots": 10,
    "address_slots_used": 2,
    "webhook_url": "https://example.com/hooks/rpcnode",
    "webhook_enabled": true
  }
}

GET /v1/address-watches

List watched addresses (paginated, newest first). Filter by network and/or part of the address.

Параметры запроса

ИмяТипОписание
network_slugstringExact watch network key (trimmed, lowercased), e.g. ethereum or ethereum-sepolia. Max 255. (необязательно)
addressstringCase-insensitive substring of the address (not only a prefix), after the same normalization as add. Max 255. (необязательно)
pageintegerPage number, 1–10000 (default 1). (необязательно)
per_pageintegerPage size, 1–100 (default 20). (необязательно)

Поля ответа

ИмяТипОписание
items[].watch_idstringPublic watch identifier (uuid). Use it to delete the watch and to filter events.
items[].network_slugstringWatch network key: the base slug on mainnet (ethereum), {network}-{env} elsewhere (ethereum-sepolia).
items[].addressstringWatched address in its normalized form (see the add method).
items[].statusstringWatch status: active or stopped.
items[].created_atstringCreation time, ISO 8601 with offset.
pagination.pagenumberCurrent page.
pagination.per_pagenumberPage size used for this response.
pagination.totalnumberTotal number of matching rows.
pagination.has_morebooleanTrue if more pages exist after this one.
  • Sign the path together with the query string (see Authentication): the query is part of the signature.
  • A page, per_page or text value outside its bounds is rejected with 400 and an errors list naming the parameter; it is never replaced by a default.
  • Only active and stopped watches are listed; deleted ones are not.

Пример запроса

import { createHash, createHmac } from 'node:crypto'

const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'

// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
  const timestamp = Math.floor(Date.now() / 1000)
  const bodyHash = createHash('sha256').update(body).digest('hex')
  const signature = createHmac('sha256', SECRET)
    .update([timestamp, method, path, bodyHash].join('\n'))
    .digest('hex')
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': String(timestamp),
      'X-Signature': signature,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body || undefined,
  })
  return res.json()
}

console.log(await call('GET', '/v1/address-watches'))

Запрос подписывается прямо в примере — правила подписи описаны в разделе Authentication.

Пример ответа

{
  "ok": true,
  "items": [
    {
      "watch_id": "c9fd242d-525b-4b81-9a99-b2a95be331c9",
      "network_slug": "ethereum",
      "address": "0x28c6c06298d514db089934071355e5743bf21d60",
      "status": "active",
      "created_at": "2026-08-22T10:15:00+00:00"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "has_more": false
  }
}

POST /v1/address-watches

Start watching an address on a network. Takes one address slot.

Тело запроса

ИмяТипОписание
network_slugstringWatch network key (max 80, trimmed, lowercased). Mainnet is the base network slug (ethereum); other environments are {network}-{env} (ethereum-sepolia). The environment must be available for watching, otherwise the request fails with watch.scan_not_enabled.
addressstringAddress to watch (max 255, trimmed). 0x… addresses are lowercased (32-byte addresses such as Aptos/Sui/Starknet are written with all 64 digits); other encodings (Tron T…, Bitcoin, Solana) keep their case.

Поля ответа

ИмяТипОписание
addressobjectThe created watch: the same fields as a list item.
address.watch_idstringPublic watch identifier (uuid). Use it to delete the watch and to filter events.
address.network_slugstringWatch network key: the base slug on mainnet (ethereum), {network}-{env} elsewhere (ethereum-sepolia).
address.addressstringWatched address in its normalized form (see the add method).
address.statusstringWatch status: active or stopped.
address.created_atstringCreation time, ISO 8601 with offset.
  • Body fields are exact: a misspelled or unknown field is rejected with 400 and named in errors. Send Content-Type: application/json and sign the raw body.
  • Adding an address that is already watched is not an error: the existing active watch is returned and no extra slot is taken. Adding an address again after deleting it takes a slot again.
  • Adds and deletes are rate-limited per account (day, week and month budgets that grow with the number of slots); over the budget the call fails with 429 watch.quota.

Пример запроса

import { createHash, createHmac } from 'node:crypto'

const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'

// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
  const timestamp = Math.floor(Date.now() / 1000)
  const bodyHash = createHash('sha256').update(body).digest('hex')
  const signature = createHmac('sha256', SECRET)
    .update([timestamp, method, path, bodyHash].join('\n'))
    .digest('hex')
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': String(timestamp),
      'X-Signature': signature,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body || undefined,
  })
  return res.json()
}

console.log(await call('POST', '/v1/address-watches', '{"network_slug":"string","address":"string"}'))

Запрос подписывается прямо в примере — правила подписи описаны в разделе Authentication.

Пример ответа

{
  "ok": true,
  "address": {
    "watch_id": "c9fd242d-525b-4b81-9a99-b2a95be331c9",
    "network_slug": "tron",
    "address": "TU4vEruvZwLLkSfV9bNw12EJTPvNr7Pvaa",
    "status": "active",
    "created_at": "2026-08-22T10:15:00+00:00"
  }
}

DELETE /v1/address-watches/{watchId}

Stop watching an address. The watch id goes in the path; there is no request body.

  • watchId is the watch_id returned by add or list (a uuid). An unknown, foreign or malformed id returns 404 watch.not_found.
  • Deleting frees the slot at once, but counts against the delete budget (429 watch.quota when exceeded).
  • Events already recorded for the watch stay readable through the events route.

Пример запроса

import { createHash, createHmac } from 'node:crypto'

const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'

// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
  const timestamp = Math.floor(Date.now() / 1000)
  const bodyHash = createHash('sha256').update(body).digest('hex')
  const signature = createHmac('sha256', SECRET)
    .update([timestamp, method, path, bodyHash].join('\n'))
    .digest('hex')
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': String(timestamp),
      'X-Signature': signature,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body || undefined,
  })
  return res.json()
}

console.log(await call('DELETE', '/v1/address-watches/00000000-0000-0000-0000-000000000000'))

Запрос подписывается прямо в примере — правила подписи описаны в разделе Authentication.

Пример ответа

{
  "ok": true
}

GET /v1/address-watches/events

Recent events of your watched addresses, newest first. The transaction details are flattened onto each event (no nested payload).

Параметры запроса

ИмяТипОписание
watch_idstringOnly events of this watch. Must be a uuid. (необязательно)
network_slugstringExact watch network key (lowercased), e.g. tron. Max 255. (необязательно)
addressstringCase-insensitive prefix of the event address, after address normalization. Max 255. (необязательно)
event_typestringpayment, payout or other. Anything else returns 400 watch.invalid_event_type. (необязательно)
tx_hashstringCase-insensitive prefix of the transaction hash. Max 255. (необязательно)
before_idstringCursor: the id (uuid) of an event; only events older than it are returned. An id that matches no event returns an empty page. (необязательно)
pageintegerPage number, 1–10000 (default 1). (необязательно)
per_pageintegerPage size, 1–100 (default 50). (необязательно)

Поля ответа

ИмяТипОписание
items[].idstringEvent id (uuid). Use it as before_id.
items[].watch_idstringWatch the event belongs to (uuid).
items[].network_slugstringWatch network key.
items[].addressstringWatched address the event is about.
items[].tx_hashstringTransaction hash.
items[].block_heightnumberBlock height of the transaction; 0 while it is only in the mempool.
items[].created_atstringWhen the event was recorded, ISO 8601 with offset.
items[].schema_versionstringEvent format version, always "2".
items[].networkstringNetwork slug of the event.
items[].typestringpayment (value came to the address), payout (value left it) or other.
items[].directionstringin, out or self, relative to address.
items[].is_paymentbooleanTrue for payment and payout, false for other.
items[].from_addressstringSender.
items[].to_addressstringRecipient.
items[].tokenobject | null{ contract, standard, symbol, decimals } for a token transfer, null for the native coin. symbol and decimals are null when the token is not in the network catalog.
items[].currencystring | nullTicker (USDT, or the native coin such as TRX). null when unknown.
items[].amountstring | nullHuman-readable amount as a decimal string ("30"). null when the ticker or decimals are unknown; use amount_raw then.
items[].amount_rawstring | nullAmount in the smallest unit, as a string.
items[].feestring | nullNetwork fee in the native coin.
items[].fee_rawstring | nullNetwork fee in the smallest unit.
items[].statusstringTransaction status as seen when the event was recorded (check, success or failed). For progress use confirmation_status.
items[].methodstring | nullContract method (transfer…); null for a native transfer.
items[].block_hashstring | nullBlock hash; null while in the mempool.
items[].block_timenumber | nullBlock time, Unix seconds; null while in the mempool.
items[].riskarrayRisk flags. Currently always an empty array.
items[].confirmation_statusstringpending (mempool), seen (in a block), confirming, finalized or failed. Updated as the transaction progresses.
items[].confirmationsnumberConfirmations counted so far (0 while pending).
items[].required_confirmationsnumberConfirmations this account needs on this network.
items[].final_blocknumberBlock height at which the transaction is final (block_height + required_confirmations - 1); 0 while pending.
items[].confirmedbooleanTrue only when confirmation_status is finalized.
pagination.pagenumberCurrent page.
pagination.per_pagenumberPage size used for this response.
pagination.totalnumberTotal number of matching rows.
pagination.has_morebooleanTrue if more pages exist after this one.
  • Sign the path together with the query string (see Authentication).
  • This is a recent log, not an archive. Use a webhook or WebSocket for delivery.
  • The id of an event is a uuid and is stable: the same transaction event always has the same id. To read the log page by page without gaps while new events arrive, pass the id of the last event you received as before_id instead of increasing page.
  • Empty or unknown values are never written as empty strings: unknown fields are null or absent (see the field list). The set of keys after created_at follows the Address Watch event format (schema_version "2"), the same keys as the webhook body.

Пример запроса

import { createHash, createHmac } from 'node:crypto'

const API_KEY = process.env.PUBLIC_API_KEY! // cabinet UUID
const SECRET = process.env.PUBLIC_API_SECRET! // sk_live_…
const BASE = 'https://api.rpcnode.dev'

// path: as the server receives it, with the query; body: the exact string that is sent
async function call(method: string, path: string, body = '') {
  const timestamp = Math.floor(Date.now() / 1000)
  const bodyHash = createHash('sha256').update(body).digest('hex')
  const signature = createHmac('sha256', SECRET)
    .update([timestamp, method, path, bodyHash].join('\n'))
    .digest('hex')
  const res = await fetch(BASE + path, {
    method,
    headers: {
      'X-Api-Key': API_KEY,
      'X-Timestamp': String(timestamp),
      'X-Signature': signature,
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    },
    body: body || undefined,
  })
  return res.json()
}

console.log(await call('GET', '/v1/address-watches/events'))

Запрос подписывается прямо в примере — правила подписи описаны в разделе Authentication.

Пример ответа

{
  "ok": true,
  "items": [
    {
      "id": "3f0c1a52-7a4e-3d0f-9a1b-52c7f4a8e611",
      "watch_id": "c9fd242d-525b-4b81-9a99-b2a95be331c9",
      "network_slug": "tron",
      "address": "TU4vEruvZwLLkSfV9bNw12EJTPvNr7Pvaa",
      "tx_hash": "bb08e86bca3219613b2d10f8b731c139aebc74c7a85f2a736b18bed50a2c320c",
      "block_height": 85558636,
      "created_at": "2026-08-22T10:15:03+00:00",
      "schema_version": "2",
      "network": "tron",
      "block_hash": "0000000005193f6c0f1e2b6d5c4e8a7b1d3c9e2f4a6b8c0d1e2f3a4b5c6d7e8f",
      "block_time": 1787393700,
      "from_address": "TU4vEruvZwLLkSfV9bNw12EJTPvNr7Pvaa",
      "to_address": "TH7uGJPN4Dy8XBBNkSuPtiZL1QMTB7jsJv",
      "type": "payout",
      "token": { "contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "symbol": "USDT", "standard": "trc20", "decimals": 6 },
      "currency": "USDT",
      "amount": "30",
      "amount_raw": "30000000",
      "fee": "13.3",
      "fee_raw": "13300000",
      "status": "check",
      "method": "transfer",
      "is_payment": true,
      "direction": "out",
      "risk": [],
      "confirmation_status": "finalized",
      "required_confirmations": 19,
      "confirmations": 19,
      "final_block": 85558654,
      "confirmed": true
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 50,
    "total": 1,
    "has_more": false
  }
}

Советы

  • network_slug is the watch network key: the base catalog slug on mainnet (ethereum, tron) and {network}-{env} on other environments (ethereum-sepolia, tron-nile). Only environments available for watching can be used.
  • DELETE takes the watch id in the path (/v1/address-watches/{watchId}) and no body. The old body-based form no longer exists.
  • Fields without a value are not written. Read an absent field as "no value", for example account.webhook_url when no webhook is configured.
  • The query string is part of the signed path, so sign exactly the path and query you send.
  • Event delivery (webhook URL, secret, which networks fire) is configured with GET/PUT /v1/webhooks, not here. See the Webhooks article; for a live socket see WebSockets.