zcash_watch_payment
Poll a ZAP1 invoice until payment is confirmed or timeout expires. Returns paid status, transaction ID, block height, and confirmed amount.
Instructions
Poll a ZAP1 invoice until it is paid or the timeout expires. Returns paid status, txid, block height, and confirmed amount.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| invoice_id | Yes | Invoice ID returned by zcash_create_invoice | |
| timeout_seconds | No | Maximum seconds to wait for payment (default 300) |
Implementation Reference
- src/tools/watch.ts:16-78 (handler)The async handler that polls the ZAP1 /invoice/{invoice_id} endpoint until paid or timeout. Returns paid status, txid, height, and amount on success; returns timeout result or error otherwise.
async ({ invoice_id, timeout_seconds }) => { const deadline = Date.now() + timeout_seconds * 1000; try { while (Date.now() < deadline) { const res = await fetch(`${ZAP1_API}/invoice/${invoice_id}`, { signal: AbortSignal.timeout(API_TIMEOUT_MS), }); if (!res.ok) { const text = await res.text(); throw new Error(`${res.status}: ${text}`); } const data = await res.json(); if (data.status === "paid") { return { content: [ { type: "text" as const, text: JSON.stringify( { paid: true, txid: data.txid ?? null, height: data.height ?? null, amount: data.amount ?? null, }, null, 2 ), }, ], }; } const remaining = Math.ceil((deadline - Date.now()) / 1000); if (remaining <= 0) break; await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS)); } return { content: [ { type: "text" as const, text: JSON.stringify( { paid: false, txid: null, height: null, amount: null, reason: "timeout" }, null, 2 ), }, ], }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true, }; } } ); - src/tools/watch.ts:12-15 (schema)Input schema for zcash_watch_payment: invoice_id (string) and timeout_seconds (positive int, default 300).
{ invoice_id: z.string().describe("Invoice ID returned by zcash_create_invoice"), timeout_seconds: z.number().int().positive().default(300).describe("Maximum seconds to wait for payment (default 300)"), }, - src/tools/watch.ts:8-79 (registration)Registration of the tool via server.tool() with name 'zcash_watch_payment' and its description.
export function registerWatchTool(server: McpServer) { server.tool( "zcash_watch_payment", "Poll a ZAP1 invoice until it is paid or the timeout expires. Returns paid status, txid, block height, and confirmed amount.", { invoice_id: z.string().describe("Invoice ID returned by zcash_create_invoice"), timeout_seconds: z.number().int().positive().default(300).describe("Maximum seconds to wait for payment (default 300)"), }, async ({ invoice_id, timeout_seconds }) => { const deadline = Date.now() + timeout_seconds * 1000; try { while (Date.now() < deadline) { const res = await fetch(`${ZAP1_API}/invoice/${invoice_id}`, { signal: AbortSignal.timeout(API_TIMEOUT_MS), }); if (!res.ok) { const text = await res.text(); throw new Error(`${res.status}: ${text}`); } const data = await res.json(); if (data.status === "paid") { return { content: [ { type: "text" as const, text: JSON.stringify( { paid: true, txid: data.txid ?? null, height: data.height ?? null, amount: data.amount ?? null, }, null, 2 ), }, ], }; } const remaining = Math.ceil((deadline - Date.now()) / 1000); if (remaining <= 0) break; await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS)); } return { content: [ { type: "text" as const, text: JSON.stringify( { paid: false, txid: null, height: null, amount: null, reason: "timeout" }, null, 2 ), }, ], }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error: ${msg}` }], isError: true, }; } } ); } - src/index.ts:43-43 (registration)Invocation of registerWatchTool(server) to register the tool on the MCP server.
registerWatchTool(server); - src/tools/watch.ts:4-6 (helper)Constants: ZAP1_API base URL, POLL_INTERVAL_MS (5s), and API_TIMEOUT_MS (10s).
const ZAP1_API = process.env.ZAP1_API_URL ?? "https://pay.frontiercompute.io"; const POLL_INTERVAL_MS = 5_000; const API_TIMEOUT_MS = 10_000;