TypeScript SDK Guide
@0agent/0watch-sdk is a lightweight TypeScript client for the 0watch API. It wraps all public endpoints in typed methods, handles auth headers, and includes a verifyWebhookSignature utility for server-side verification.
Install
npm install @0agent/0watch-sdk
# or
pnpm add @0agent/0watch-sdk
# or
yarn add @0agent/0watch-sdk
Requires Node.js 20+. Works in any runtime with a global fetch (Node 18+ with --experimental-fetch, Bun, Deno, Cloudflare Workers).
Create a client
import { ZeroWatchClient } from '@0agent/0watch-sdk';
const client = new ZeroWatchClient({
apiKey: process.env.ZEROWATCH_API_KEY,
});
All options:
const client = new ZeroWatchClient({
apiKey: 'owk_...', // X-API-Key header
token: 'session_token', // Bearer token (alternative to apiKey)
baseUrl: 'https://watch.0agent.ai', // default
fetch: customFetchImpl, // custom fetch (e.g. for testing)
headers: { 'X-Custom': '1' }, // default headers on every request
});
You can update auth at runtime:
client.setApiKey('owk_new...');
client.setToken(null);
Common patterns
Sign up and start monitoring
import { ZeroWatchClient } from '@0agent/0watch-sdk';
const client = new ZeroWatchClient();
// 1. Create account
const signup = await client.signup({
email: 'dev@example.com',
password: 'StrongPassword123',
});
// 2. Authenticate with the returned API key
client.setApiKey(signup.apiKey);
console.log('Account:', signup.accountId);
// 3. Add wallets
await client.createWallet({
address: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
label: 'Treasury',
chain: 'base', // or chain ID: 8453
});
await client.createWallet({
address: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
label: 'Ops',
});
// 4. List what you're watching
const { wallets } = await client.listWallets();
console.log(`Monitoring ${wallets.length} wallets`);
Query transactions
const { transactions, count } = await client.getWalletTransactions(
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
{ limit: 50 }
);
for (const tx of transactions) {
// valueWei is a string — use BigInt for arithmetic
const eth = Number(BigInt(tx.valueWei)) / 1e18;
console.log(`${tx.txType}: ${eth.toFixed(4)} ETH — ${tx.hash}`);
}
Query anomaly alerts
const { alerts } = await client.getWalletAlerts(
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
{ limit: 20 }
);
const high = alerts.filter(a => a.severity === 'high' || a.severity === 'critical');
console.log(`${high.length} high/critical alerts`);
Alert severities: low, medium, high, critical.
Anomaly types: large_transfer, high_velocity, failed_tx.
Get a wallet activity summary
const summary = await client.getWalletSummary(
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
);
console.log({
totalTx: summary.totalTransactionsMonitored,
alertsTriggered: summary.alertsTriggered,
lastActivity: summary.lastActivityTimestamp
? new Date(summary.lastActivityTimestamp * 1000)
: null,
});
Set up a webhook
const webhook = await client.createWebhook({
url: 'https://your-server.example.com/hook',
wallet_address: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
threshold_eth: 0.5,
});
// Store signingSecret securely — it won't be returned again
console.log({ webhookId: webhook.id, signingSecret: webhook.signingSecret });
Rotate a webhook signing secret
const updated = await client.updateWebhook(webhook.id, {
rotate_signing_secret: true,
});
// The new signing secret is in updated.signingSecret
Check delivery history
const { deliveries } = await client.listDeliveries({
wallet: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
limit: 25,
});
const failed = deliveries.filter(d => d.status === 'failed');
if (failed.length > 0) {
console.warn(`${failed.length} failed deliveries`);
for (const d of failed) {
const attempts = await client.getDeliveryAttempts(d.id);
console.error(`Delivery ${d.id}: ${attempts.attempts.at(-1)?.error}`);
}
}
Dashboard stats
const stats = await client.getDashboardStats();
console.log({
wallets: stats.walletsMonitored,
alertsThisWeek: stats.alertsThisWeek,
indexerStatus: stats.uptime.status,
lastBlock: stats.uptime.lastSyncedBlock,
});
Webhook signature verification
When 0watch POSTs to your endpoint, it includes X-0Watch-Signature: sha256=<hex>. Verify it before processing the payload.
import { verifyWebhookSignature } from '@0agent/0watch-sdk';
// Works in any framework — example using the Fetch Request API (Bun, Cloudflare Workers, Deno)
async function handleWebhook(request: Request): Promise<Response> {
const rawBody = await request.text();
const valid = verifyWebhookSignature({
payload: rawBody,
signingSecret: process.env.ZEROWATCH_WEBHOOK_SECRET!,
signatureHeader: request.headers.get('x-0watch-signature'),
});
if (!valid) {
return new Response('Unauthorized', { status: 401 });
}
const payload = JSON.parse(rawBody);
// { event, walletAddress, valueEth, thresholdEth, transaction }
console.log(`Alert: ${payload.walletAddress} moved ${payload.valueEth} ETH`);
return new Response('OK', { status: 200 });
}
For Node.js + Express, read the raw body before verification:
import express from 'express';
import { verifyWebhookSignature } from '@0agent/0watch-sdk';
const app = express();
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
const valid = verifyWebhookSignature({
payload: req.body, // Buffer
signingSecret: process.env.ZEROWATCH_WEBHOOK_SECRET!,
signatureHeader: req.headers['x-0watch-signature'] as string,
});
if (!valid) return res.status(401).send('Unauthorized');
const payload = JSON.parse(req.body.toString());
// handle payload
res.sendStatus(200);
});
You can also generate a signature manually (useful for testing):
import { createWebhookSignature } from '@0agent/0watch-sdk';
const body = JSON.stringify({ event: 'test', walletAddress: '0x...' });
const signature = createWebhookSignature(body, 'your-signing-secret');
// sha256=<hex>
Error handling
All API errors throw ZeroWatchApiError:
import { ZeroWatchApiError } from '@0agent/0watch-sdk';
try {
await client.createWallet({
address: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
label: 'Treasury',
});
} catch (err) {
if (err instanceof ZeroWatchApiError) {
console.error(`API error ${err.status}: ${err.message}`);
if (err.status === 402) {
console.error(`Wallet limit reached. Upgrade required: ${err.data?.upgradeRequired}`);
}
if (err.status === 429) {
const retryAfter = err.data?.retryAfterSeconds;
console.error(`Rate limited. Retry after ${retryAfter}s`);
}
} else {
throw err;
}
}
ZeroWatchApiError properties:
status— HTTP status codemessage— error string from the APIdata— parsed response body (includescode,tier,limit,upgradeRequired,retryAfterSecondswhere relevant)
Common error codes:
402— wallet or API call limit for your tier404— wallet or resource not found429— rate limit exceeded
Billing and usage
// Check subscription and wallet usage
const { subscription, usage } = await client.getSubscription();
console.log({
tier: subscription.tier,
status: subscription.status,
wallets: `${usage.watchedWallets} / ${usage.walletLimit ?? 'unlimited'}`,
});
// Detailed rate limit stats
const usageDetail = await client.getUsage({ limit: 10 });
console.log({
remaining: usageDetail.rateLimit.remaining,
resetAt: new Date(usageDetail.rateLimit.resetAt * 1000),
});
// Start a crypto checkout payment request (Developer or Team tier)
const checkout = await client.createCheckout({
tier: 'developer',
success_url: 'https://yourapp.com/billing/success',
cancel_url: 'https://yourapp.com/billing',
});
// Redirect to checkout.url or use checkout.paymentRequest for custom confirmation UX
API key management
// List active keys
const { keys } = await client.listApiKeys();
// Create an additional key
client.setOwnerEmail('you@example.com');
const { apiKey } = await client.createApiKey({ name: 'ci-pipeline' });
// Rotate (creates a new key, old key enters grace period)
const rotated = await client.rotateApiKey();
// Revoke a key by ID
await client.revokeApiKey(keys[0].id);
ownerEmail is required when creating or rotating keys. Set it via the constructor (ownerEmail option) or client.setOwnerEmail().
TypeScript types
All request and response types are exported from the package root:
import type {
ZeroWatchClientOptions,
WalletRecord,
TransactionRecord,
AlertRecord,
WebhookRecord,
CreatedWebhookRecord,
AlertSeverity,
AnomalyType,
BillingTier,
ZeroWatchApiError,
} from '@0agent/0watch-sdk';
The Address and TransactionHash types are branded strings:
import type { Address, TransactionHash } from '@0agent/0watch-sdk';
function process(addr: Address) { /* ... */ }
process('0xabc...' as Address);
Next steps
- Quickstart — REST examples with curl, JS, and Python; alert rule conditions
- Webhook Cookbook — Slack, Discord, PagerDuty, ngrok setup
- API Reference — full endpoint catalog