B2B Address Notification Service

Coin & Token Transfer Watcher

This document explains how to use the Watched Addresses system to receive real-time webhook notifications for W Chain coin (WCO) transfers and ERC-20 token transfers involving your registered addresses.

The system provides:

  • A CRUD API to manage watched addresses and webhook URLs

  • Real-time POST webhooks on transfers matching your watch rules

  • Automatic retries with exponential backoff on delivery failures

All user-facing addresses and hashes in API responses and webhooks are 0x-prefixed. Internally, addresses are stored lowercase without the 0x prefix.

Authentication

All endpoints require an API key via the HTTP Authorization header:

  • Authorization: Bearer YOUR_API_KEY

If the key is valid, the server resolves your watcher_id and authorizes the request. If invalid or missing, the server returns 401 Unauthorized.

Base Path

  • Base URL: https://oracle.w-chain.com/api

Address Normalization

  • Input (create/update): You may send addresses with or without the 0x prefix. The server normalizes by stripping 0x if present and storing lowercase hex without 0x.

  • Output (list/get/update responses and webhooks): All addresses and transaction hashes are 0x-prefixed for consistency with wallets and explorers.

Endpoints

Create a watched address

  • Method: POST

  • Path: /notifications/watched-addresses

  • Body fields:

    • address (string, required): Address with or without 0x; must be 40 hex characters when normalized

    • watch_coin (boolean, optional, default true): Watch native coin (WCO) transfers

    • watch_token (boolean, optional, default true): Watch ERC-20 token transfers

    • webhook_url (string, required): HTTPS URL to receive webhooks

Example:

curl -X POST https://oracle.w-chain.com/api/notifications/watched-addresses \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "address": "0xabc1234567890abcdefabc1234567890abcdef0",
        "watch_coin": true,
        "watch_token": true,
        "webhook_url": "https://yourapp.example.com/watched-address-webhook"
      }'

Success response (200):

{
  "success": true,
  "data": {
    "id": "...",
    "watcher_id": 123,
    "address": "0xabc1234567890abcdefabc1234567890abcdef0",
    "watch_coin": true,
    "watch_token": true,
    "webhook_url": "https://yourapp.example.com/watched-address-webhook",
    "created_at": "...",
    "updated_at": "..."
  }
}

List watched addresses

  • Method: GET

  • Path: /notifications/watched-addresses

Example:

curl -X GET https://oracle.w-chain.com/api/notifications/watched-addresses \
  -H "Authorization: Bearer YOUR_API_KEY"

Success response (200):

{
  "success": true,
  "data": [
    {
      "id": "...",
      "watcher_id": 123,
      "address": "0xabc1234567890abcdefabc1234567890abcdef0",
      "watch_coin": true,
      "watch_token": true,
      "webhook_url": "https://yourapp.example.com/watched-address-webhook",
      "created_at": "...",
      "updated_at": "..."
    }
  ]
}

Get a watched address by ID

  • Method: GET

  • Path: /notifications/watched-addresses/:id

Example:

curl -X GET https://oracle.w-chain.com/api/notifications/watched-addresses/ID_HERE \
  -H "Authorization: Bearer YOUR_API_KEY"

Success response (200):

{
  "success": true,
  "data": {
    "id": "...",
    "watcher_id": 123,
    "address": "0xabc1234567890abcdefabc1234567890abcdef0",
    "watch_coin": true,
    "watch_token": true,
    "webhook_url": "https://yourapp.example.com/watched-address-webhook",
    "created_at": "...",
    "updated_at": "..."
  }
}

Update a watched address

  • Method: PATCH

  • Path: /notifications/watched-addresses/:id

  • Body: Any subset of the create fields (address, watch_coin, watch_token, webhook_url)

Example:

curl -X PATCH https://oracle.w-chain.com/api/notifications/watched-addresses/ID_HERE \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "watch_token": false }'

Success response (200):

{
  "success": true,
  "data": {
    "id": "...",
    "watcher_id": 123,
    "address": "0xabc1234567890abcdefabc1234567890abcdef0",
    "watch_coin": true,
    "watch_token": false,
    "webhook_url": "https://yourapp.example.com/watched-address-webhook",
    "created_at": "...",
    "updated_at": "..."
  }
}

Delete a watched address

  • Method: DELETE

  • Path: /notifications/watched-addresses/:id

Example:

curl -X DELETE https://oracle.w-chain.com/api/notifications/watched-addresses/ID_HERE \
  -H "Authorization: Bearer YOUR_API_KEY"

Success response (200):

{ "success": true }

Webhook Delivery

When a transfer involving any of your watched addresses occurs, we send a POST request with JSON to the webhook_url configured for that watched address.

  • Method: POST

  • Headers:

    • Content-Type: application/json

    • Authorization: Bearer <api_key> this is the same API Key used by the Watcher identity, should be used to ensure the authenticity of the webhook request

  • Timeout: 10 seconds. If your endpoint does not respond within 10 seconds, it is treated as a failure and retried.

Payload fields

These fields are sent in the request body. Values are formatted for user-facing consumption as described.

  • id (number): Internal notification ID

  • watched_addresses_id (string, UUID): The watched_addresses row ID

  • watcher_id (number): Your watcher ID

  • hash (string): 0x-prefixed transaction hash

  • type (string enum): COIN_TRANSFER or TOKEN_TRANSFER

  • sender (string): 0x-prefixed sender address

  • receiver (string): 0x-prefixed receiver address. For contract creations or transactions without a to, this may be an empty string.

  • amount (number | null):

    • COIN_TRANSFER: Amount is in wei, as a JSON number. Note: very large values may exceed JavaScript’s exact integer range; handle carefully if you require exact arithmetic.

    • TOKEN_TRANSFER: Raw token units as a JSON number (decimals not applied). Fetch the token’s decimals and normalize on your side if needed.

  • asset (string):

    • COIN_TRANSFER: The literal string WCO

    • TOKEN_TRANSFER: 0x-prefixed token contract address

  • timestamp (string): Timestamp of notification row creation as produced by Postgres (timestamp without time zone). Treat as a textual timestamp; convert/timezone as desired on your side.

  • webhook_url (string): The target URL (provided for your reference)

  • api_key (string | null): The API key stored for your watcher, if any (also sent via the Authorization header)

  • next_retry_at (string | null): Scheduled time for the next retry (if previously failed), else null

Example payload:

{
  "id": 12345,
  "watched_addresses_id": "a1b2c3d4-1111-2222-3333-abcdefabcdef",
  "watcher_id": 678,
  "hash": "0x3fa9e1...c1d2",
  "type": "TOKEN_TRANSFER",
  "sender": "0x1111111111111111111111111111111111111111",
  "receiver": "0x2222222222222222222222222222222222222222",
  "amount": 2500000000000000000,
  "asset": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
  "timestamp": "2025-09-10 08:00:00.000000",
  "webhook_url": "https://yourapp.example.com/watched-address-webhook",
  "api_key": "YOUR_API_KEY_OR_NULL",
  "next_retry_at": null
}

Retry Policy (Exponential Backoff)

If a webhook delivery fails (non-2xx response, timeout, or network error), the system schedules a retry using the following backoff (minutes):

  • 1, 3, 10, 15, 60

On the Nth failure, the Nth interval is used; after the 5th failure, retries continue every 60 minutes.

  • retry_count increments on each failure.

  • next_retry_at is set to now + interval.

  • On a successful 2xx response, processed_at is set and the notification will not be retried further.

The retry worker selects unprocessed notifications whose next_retry_at is due.

Implementation Notes

  • Address formatting

    • Inputs accept with or without 0x; stored lowercase without 0x internally.

    • API responses (create/list/get/update) return addresses with 0x.

    • Webhook payload prefixes hash, sender, receiver, and (for tokens) asset with 0x.

  • Receiver may be empty string

    • For coin transfers where to is null (e.g., contract creation), receiver is emitted as an empty string.

  • Amount type

    • Currently sent as a JSON number. If exact precision is required in your system, convert or handle carefully to avoid precision loss in JavaScript environments.

  • Asset field

    • WCO for native coin transfers; otherwise the token contract address (0x-prefixed) for token transfers.

  • Timeouts

    • Webhook POSTs time out in 10 seconds (treated as failure).

  • Authorization header on webhook

    • If an API key is present for the watcher, the webhook request to your server includes Authorization: Bearer <api_key>.

Example Receiver (Pseudocode)

import express from 'express';
const app = express();
app.use(express.json());

app.post('/watched-address-webhook', (req, res) => {
  // Optionally verify Authorization header matches what you expect
  // const auth = req.headers['authorization'];

  const n = req.body; // See payload fields above

  // Handle idempotency if you store notifications (e.g., by `n.id`)

  if (n.type === 'COIN_TRANSFER') {
    // n.asset === 'WCO'
    // n.amount is wei (number); beware precision in JS
  } else if (n.type === 'TOKEN_TRANSFER') {
    // n.asset is token contract address (0x-prefixed)
    // n.amount is raw units; fetch token decimals to normalize
  }

  res.status(200).send('ok');
});

app.listen(3000);

Troubleshooting

  • 401 Unauthorized on API calls

    • Ensure Authorization: Bearer YOUR_API_KEY is present and valid.

  • Webhook not received

    • Confirm your server is reachable over HTTPS and returns 200 within 10 seconds.

    • Check if retries are scheduled by inspecting your logs or querying notifications with processed_at IS NULL and next_retry_at in the past.

  • Amount precision issues

    • The amount is sent as a JSON number; for exact arithmetic, convert or handle using big number libraries on your side.

Change Log

  • 2025-09: Added asset to notification schema and payload. For coin transfers set to WCO; for token transfers set to the token contract address.

  • 2025-09: Standardized 0x-prefix formatting in API responses and webhook payloads (hash, sender, receiver, token asset).

Last updated