PolyPay logoPolyPay.ai
Beginner5 min read

Wallet Monitoring

Monitor transfers into and out of public on-chain addresses without setting them up as PolyPay receiving wallets.

Receiving wallets and monitored addresses

A receiving wallet participates in payment routing. A monitored address only records chain activity and triggers alerts. The same network and address may have both roles, but disabling or deleting either role never changes the other.

Set up monitoring

To edit a monitored address, select Edit in the address list. The shared address page opens with the saved settings and an Edit title; saving returns you to the list.

  1. Choose Add monitored address in Wallet Monitoring to open /wallet-monitoring/add. Click “Import from merchant wallets” to the right of Address to open the wallet selector, then choose a merchant and receiving wallet. Saving, cancelling, or going back returns to Getting Started when opened there, or to the address list when opened from the list.
  2. Choose an enabled chain and one or more currency/contracts from the blockchain configuration, then confirm that the address format matches the chain. Invalid Tron addresses are rejected. PolyPay never requests a private key.
  3. Turn on the address switch to start monitoring. Templates are managed independently from channels and events. Select a configured channel and one reusable template; a channel or template can be selected more than once.
  4. Optionally create a separate wallet-monitoring Webhook. New endpoints remain disabled until the saved configuration passes a signed test.

Notifications and templates

Configure templates and channels from the gear entries in the address form. Management lists open in panels; Add and Edit open dialogs that preserve the address draft. The Send test button uses only its own row’s saved channel and selected template. It does not save the address or prove that a real transfer was detected. When a monitored address is disabled, deleted, or paused for billing, failed channel alerts stop retrying and manual resends are blocked. Messages already sent are not recalled.

Wallet monitoring sends notifications only for transactions whose on-chain time is within the past 72 hours. This limit applies to initial scans, catch-up notifications, and retries. Older transactions can remain in transaction history, but no in-app, external-channel, or Webhook notifications are sent.

Configure custom contracts

Custom contracts require an active paid wallet-monitoring plan, including pay-as-you-go. Configure custom contracts for Ethereum, BSC, Polygon, Base, Arbitrum or Optimism when the network and its RPC are enabled. ERC-20 transfers with 0–18 decimals are supported. Token identity is the network and contract address, so identical symbols remain separate. Metadata must be verified on-chain. Remove every address reference before changing or deleting a contract. Records and notifications include the actual contract address. Open Wallet monitoring → Custom contracts to select a network and add, edit or delete contracts. The configuration button in the address form opens a right-side panel on the current page; saving refreshes the selectable contracts. Add and edit contracts in the right-side panel. When the plan expires or becomes inactive, custom-contract monitoring and notifications pause; contract records are retained. Free plans can view the custom contracts page. Selecting Add prompts you to upgrade to a premium plan. The list shows all networks by default and supports filtering by network. To add a contract, select its network, enter its address, resolve it, then save. Editing preselects the contract’s network. After identification, you can edit the name, symbol and decimals (an integer from 0 to 18). Saved overrides apply only to your contract records; shared scanning continues to use original on-chain metadata.

Wallet monitoring quick start

The wallet-monitoring Quick start uses your saved addresses, optional notification routes and observed transactions. A successful test validates message delivery only and is shown for the current session. Real monitoring is confirmed only after a detected transfer. Account timezone controls displayed timestamps.

Independent Webhook

Manage one wallet-monitoring Webhook in the Webhook section below the templates in Notification Settings. It does not reuse payment Webhook configuration or notification-channel Webhooks. The configuration has its own event and address scope, secret, HMAC-SHA256 signature, retry state, and fixed versioned JSON payload. Changes to the URL, scope, events, or secret disable it until it passes another test. Legacy channel Webhooks are read-only; use their migration action to create and test the configuration.

Verify the signature

Verify each request with the raw request body before parsing JSON. Read X-PolyPay-Timestamp and X-PolyPay-Signature (t=<timestamp>,v1=<hex>), calculate HMAC-SHA256 with the complete whsec_... secret over <timestamp>.<raw body>, and compare the bytes in constant time. Reject timestamps more than 5 minutes away from the current time and process each payload id only once. Every test request uses a unique test event ID.

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

const rawBody = await request.text();
const timestamp = request.headers.get('x-polypay-timestamp') ?? '';
const signature = request.headers.get('x-polypay-signature') ?? '';
const match = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(signature);
if (!match || match[1] !== timestamp) throw new Error('Invalid signature header');

if (Math.abs(Date.now() / 1000 - Number(match[1])) > 300) {
  throw new Error('Stale webhook');
}

const expected = createHmac('sha256', process.env.WALLET_WEBHOOK_SECRET!)
  .update(match[1] + '.' + rawBody)
  .digest();
const received = Buffer.from(match[2], 'hex');
if (received.length !== expected.length || !timingSafeEqual(received, expected)) {
  throw new Error('Invalid signature');
}

const event = JSON.parse(rawBody);
// Store event.id before applying the event so retries are processed once.

Account email notifications

Plan activation, renewal results, expiry and monitoring interruptions generate account emails and in-app notifications without using the monitoring quota. Expiry reminders are sent within 7, 3 and 1 day of expiry. Delivery follows the account email language preference, and expiry times use the account time zone.

Notification usage alerts are sent at 80% and 100% of the UTC calendar-month allowance. After the allowance, eligible plans continue with pay-as-you-go charges if the balance is sufficient. Insufficient funds trigger an alert. Address pause and recovery notices are grouped by account and reason over a five-minute window; recovery is reported only after chain synchronization succeeds. Expired plans use free-plan entitlements; custom-contract monitoring requires an active paid plan. These quotas apply only to human notification channels; independent wallet-monitoring Webhooks remain unlimited.

Plans and usage

Payment notifications and wallet-monitoring Webhooks are unlimited. Only successful wallet-monitoring human-channel deliveries consume the account-level notification allowance per destination. Failed delivery and monitoring without human-channel delivery do not consume quota. Manage this plan on the dedicated Wallet Monitoring Plan page; shared funds and records remain on the separate account Balance page. Paid wallet-monitoring plans support monthly, quarterly, semiannual and yearly billing. Quarterly costs three times the monthly price; semiannual costs six times. Yearly uses the listed yearly price. Automatic renewal uses the purchased billing cycle and account balance. Auto-renewal is enabled by default in purchase confirmation and can be turned off before confirming.

Pay as you go

$0.50/address/month · $0.002/successful notification delivery

Each enabled address is billed for one calendar month in advance. Reactivating within its paid period is free. Disabled addresses do not renew. Insufficient balance pauses the affected address; monitoring resumes after funding, checked every minute. Each successful human-channel delivery costs $0.002 per destination; failures release the hold and retries do not duplicate charges. Before stopping PAYG, reduce enabled addresses to the Free plan limit.