요금GitHub대시보드

Public API · Transaction watch

Transaction watch

A Tx watch follows one transaction hash on one network until it reaches the confirmations your account needs, fails, or turns out not to exist. You do not poll: a tx event is delivered to your webhook or WebSocket (if enabled) when the transaction is seen in a block, for each new confirmation, and when the watch ends; the watch stays readable here. This is not Address Watch: you add hashes you already know, and each watch ends once. All routes require signed headers (see Authentication) and use the base URL from the Overview. Success responses carry ok: true; failures carry ok: false, error_code and error.

transactionstx hashconfirmationstx-watchwebhook

← Public API

Flow diagram

A transaction watch is for a hash you already know. It follows the hash to a final result and ends once. On the way you are told when the transaction is seen in a block and of each new confirmation.

Your serverPublic APIRpcNodeBlockchain1. POST /v1/tx-watches {network_slug, tx_hash }2. { watch_id, status:pending }pending: the hash isnot seen in a blockyet. If the hash neverappears on thenetwork, the watchends as cancelled.3. The transaction isincluded in a block(start_height is set)4. tx event: detected (the first confirmation; thisone is charged)check: waiting forconfirmations. Atconfirm_at_height theresult is decided:confirmed or failed.If a chainreorganization removesthe transaction fromits block, the watchgoes back to pending.5. New blocks on top: onemore confirmation each6. tx event: confirmations (2, 3 … up to the onebefore the number needed; free)7. The requiredconfirmations are reached8. tx event: confirmed or failed (free). A hash nonode ever knew ends as cancelled instead (charged)9. GET/v1/tx-watches?tx_hash=…(read the ended watch)
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.

How a watch ends and how you are told

A watch moves pending (hash not seen yet) to check (found in a block, waiting for confirmations) to confirmed or failed once the chain reaches confirm_at_height and the result is decided. A hash that never appears on the network ends as cancelled. If the transaction disappears from its block (a chain reorganization), the watch goes back to pending and the process starts over.

A watch tells you how it goes with tx events: detected when the transaction is seen in a block (confirmations 1; again from the new block if a reorganization moves it), confirmations for each new confirmation from the second up to the one before the number you need, then confirmed or failed when the watch ends, or cancelled when no node ever knew the hash. With one confirmation needed you get detected and then the end. The events are delivered through the same channels as address events: the webhook (GET/PUT /v1/webhooks, a URL is required and the tx type follows the payment/payout network lists) and, if you enabled it, the WebSocket as event tx on your channel. See the Webhooks and WebSockets articles for signing, retries and the common header (schema_version, delivery_id, type, event, network).

A transaction is charged once, with its first event (detected): the tx watch webhook credits of the network (see network credits). The confirmations, confirmed and failed events that follow are free. A hash that no node ever knew ends as cancelled and is charged as one delivery. A transaction that failed on chain is as final as a successful one and is reported as event failed.

The body has the common header plus tx_hash and watch_id. For every event but cancelled it also carries the transaction as found in its block: block_height, block_hash, block_time, from_address, to_address, status, method, token, currency, amount, amount_raw, fee, fee_raw, confirmations, required_confirmations and confirmed. confirmations is the number the event is about; confirmed is true only on the confirmed and failed events that end the watch. Unknown values are omitted, not sent as null. There is no address or direction: the watch is about a hash, not an address. For cancelled there is no block, so only the header, tx_hash and watch_id remain.

tx event (confirmed)

{
  "schema_version": "2",
  "delivery_id": "…",
  "type": "tx",
  "event": "confirmed",
  "network": "ethereum",
  "tx_hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
  "block_height": 21540010,
  "block_hash": "0x…",
  "block_time": 1787393700,
  "watch_id": "7b1f5a52-52c0-4c4d-a1f0-0e5f2d6c9a31",
  "from_address": "0x…",
  "to_address": "0x…",
  "status": "success",
  "method": "transfer",
  "amount_raw": "30000000",
  "confirmations": 12,
  "required_confirmations": 12,
  "confirmed": true
}

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.tx_hash_required (400): network_slug or tx_hash 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.invalid_tx_status (400): the status filter is not one of the statuses above.

watch.tx_unavailable (403): the plan has no tx watch slots. watch.tx_limit (403): all slots are held by open watches; delete one or wait for it to end.

watch.ingest_unavailable (503): temporarily unavailable. On add, the watch is not created and holds no slot, so retry later; on delete, retry the delete.

Slots exhausted

{
  "ok": false,
  "error_code": "watch.tx_limit",
  "error": "Tx watch slots limit reached (10). Upgrade your plan to add more."
}

GET /v1/tx-watches

List your tx watches, newest first: the open ones and the ones that ended. Also returns the slots of the plan.

쿼리 매개변수

이름타입설명
network_slugstringExact watch network key (trimmed, lowercased), e.g. ethereum. Max 255. (선택)
statusstringpending, check, stopped, confirmed, failed or cancelled. Anything else returns 400 watch.invalid_tx_status. (선택)
tx_hashstringCase-insensitive prefix of the transaction hash. Max 255. (선택)
pageintegerPage number, 1–10000 (default 1). (선택)
per_pageintegerPage size, 1–100 (default 20). (선택)

응답 필드

이름타입설명
items[].watch_idstringPublic watch identifier (uuid). Also sent as watch_id in the tx event. Use it to delete the watch.
items[].network_slugstringWatch network key: the base slug on mainnet (ethereum), {network}-{env} elsewhere (ethereum-sepolia).
items[].tx_hashstringTransaction hash, trimmed and lowercased.
items[].statusstringpending (not seen in a block yet), check (seen, waiting for confirmations), confirmed, failed (the transaction failed on chain) or cancelled (the hash never appeared on the network).
items[].start_heightnumberHeight of the block the transaction was found in. 0 until it is found.
items[].confirm_at_heightnumberChain height at which the result is decided (block height plus required confirmations). While the watch is still pending it holds the number of confirmations required instead.
items[].required_confirmationsnumberConfirmations the watch waits for: your account setting for the network, or the network default (at least 1).
items[].confirmationsnumberConfirmations the transaction has now. The block that holds it is the first one, so it is 0 only while the transaction is not in a block (pending, cancelled). It grows while the watch is in check and stops at the block that decided the result once the watch has ended (confirmed, failed).
items[].confirmedbooleantrue once the watch has ended with its confirmations: status confirmed, or failed (a transaction that failed on chain is as final as a successful one; status tells which). false while the watch is pending or in check, and for cancelled.
items[].final_blocknumberChain height at which the result is decided (the block of the transaction plus required_confirmations). Absent until a block has shown the transaction. (선택)
items[].network_feestringFee paid, in the network coin as a decimal string. Absent until the watch ends with a result. (선택)
items[].checked_heightnumberChain height at which the transaction was last checked. Absent before the first check. (선택)
items[].created_atstringWhen the watch was created, ISO 8601 with offset.
slotsnumberPlan cap for concurrently open tx watches. 0 means Tx Watch is not available on the plan.
slots_usednumberOpen watches (pending or check) that hold a slot now.
pagination.pagenumberCurrent page.
pagination.per_pagenumberPage size used for this response.
pagination.totalnumberTotal number of matching watches.
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.
  • Open watches (pending, check) have no time limit and each holds one slot. Ended ones (confirmed, failed, cancelled) hold no slot.
  • slots_used counts only open watches, so it is not the same as pagination.total.

요청 예시

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/tx-watches'))

요청은 예제 코드 안에서 직접 서명됩니다. 서명 규칙은 Authentication에서 확인하세요.

응답 예시

{
  "ok": true,
  "items": [
    {
      "watch_id": "7b1f5a52-52c0-4c4d-a1f0-0e5f2d6c9a31",
      "network_slug": "ethereum",
      "tx_hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
      "status": "check",
      "start_height": 21540010,
      "confirm_at_height": 21540022,
      "required_confirmations": 12,
      "confirmations": 5,
      "confirmed": false,
      "final_block": 21540022,
      "checked_height": 21540014,
      "created_at": "2026-08-22T10:15:00+00:00"
    },
    {
      "watch_id": "c9fd242d-525b-4b81-9a99-b2a95be331c9",
      "network_slug": "tron",
      "tx_hash": "bb08e86bca3219613b2d10f8b731c139aebc74c7a85f2a736b18bed50a2c320c",
      "status": "confirmed",
      "start_height": 85558636,
      "confirm_at_height": 85558655,
      "required_confirmations": 19,
      "confirmations": 20,
      "confirmed": true,
      "final_block": 85558655,
      "network_fee": "13.3",
      "checked_height": 85558655,
      "created_at": "2026-08-22T09:40:12+00:00"
    }
  ],
  "slots": 10,
  "slots_used": 1,
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 2,
    "has_more": false
  }
}

POST /v1/tx-watches

Start watching a transaction hash on a network. Takes one tx slot until the watch ends.

요청 본문

이름타입설명
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.
tx_hashstringTransaction hash to follow (max 128). It is trimmed and lowercased.

응답 필드

이름타입설명
itemobjectThe created (or already open) watch: the same fields as a list item.
item.watch_idstringPublic watch identifier (uuid). Also sent as watch_id in the tx event. Use it to delete the watch.
item.network_slugstringWatch network key: the base slug on mainnet (ethereum), {network}-{env} elsewhere (ethereum-sepolia).
item.tx_hashstringTransaction hash, trimmed and lowercased.
item.statusstringpending (not seen in a block yet), check (seen, waiting for confirmations), confirmed, failed (the transaction failed on chain) or cancelled (the hash never appeared on the network).
item.start_heightnumberHeight of the block the transaction was found in. 0 until it is found.
item.confirm_at_heightnumberChain height at which the result is decided (block height plus required confirmations). While the watch is still pending it holds the number of confirmations required instead.
item.required_confirmationsnumberConfirmations the watch waits for: your account setting for the network, or the network default (at least 1).
item.confirmationsnumberConfirmations the transaction has now. The block that holds it is the first one, so it is 0 only while the transaction is not in a block (pending, cancelled). It grows while the watch is in check and stops at the block that decided the result once the watch has ended (confirmed, failed).
item.confirmedbooleantrue once the watch has ended with its confirmations: status confirmed, or failed (a transaction that failed on chain is as final as a successful one; status tells which). false while the watch is pending or in check, and for cancelled.
item.final_blocknumberChain height at which the result is decided (the block of the transaction plus required_confirmations). Absent until a block has shown the transaction. (선택)
item.network_feestringFee paid, in the network coin as a decimal string. Absent until the watch ends with a result. (선택)
item.checked_heightnumberChain height at which the transaction was last checked. Absent before the first check. (선택)
item.created_atstringWhen the watch was created, 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.
  • The hash may be added before it reaches the network: the watch starts as pending. A hash that never appears on the network ends as cancelled.
  • A hash that is already being watched is not an error: the open watch is returned and no extra slot is taken. A hash whose earlier watch ended is watched again as a new watch (new watch_id) and replaces the old one in the list.
  • Required confirmations come from your account setting for that network, or the network default (at least 1). For a pending watch confirm_at_height holds that number; once the transaction is found it becomes the block height plus required confirmations.

요청 예시

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/tx-watches', '{"network_slug":"string","tx_hash":"string"}'))

요청은 예제 코드 안에서 직접 서명됩니다. 서명 규칙은 Authentication에서 확인하세요.

응답 예시

{
  "ok": true,
  "item": {
    "watch_id": "7b1f5a52-52c0-4c4d-a1f0-0e5f2d6c9a31",
    "network_slug": "ethereum",
    "tx_hash": "0x4e3a3754410177e6937ef1f84bba68ea139e8d1a2258c5f85db9f1cd715a1bdd",
    "status": "pending",
    "start_height": 0,
    "confirm_at_height": 12,
    "required_confirmations": 12,
    "confirmations": 0,
    "confirmed": false,
    "created_at": "2026-08-22T10:15:00+00:00"
  }
}

DELETE /v1/tx-watches/{watchId}

Stop watching a transaction and remove the watch. The watch id goes in the path; there is no request body.

  • watchId is the watch_id returned by add or list (a uuid).
  • Deleting is idempotent: an unknown, foreign, malformed or already removed id still returns ok: true. An ended watch can be deleted too; it disappears from the list.
  • A deleted open watch frees its slot and no tx event is sent for it.

요청 예시

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/tx-watches/00000000-0000-0000-0000-000000000000'))

요청은 예제 코드 안에서 직접 서명됩니다. 서명 규칙은 Authentication에서 확인하세요.

응답 예시

{
  "ok": true
}

팁

  • 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).
  • Add the hash right after you broadcast it; there is no need to wait until it appears on chain. Remember that every open watch holds a slot until it ends.
  • DELETE takes the watch id in the path (/v1/tx-watches/{watchId}) and no body.
  • Fields without a value are not written. Read an absent network_fee or checked_height as "not known yet".
  • Listing is a convenience, not the delivery channel: rely on the webhook or WebSocket event and use the list to reconcile.