create_digest_watch
Register a scheduled webhook to receive daily or weekly curated summaries of pricing changes. Set-and-forget monitoring that provides periodic snapshots without requiring real-time subscriptions. Ideal for tracking pricing trends.
Instructions
Register a scheduled digest webhook that fires daily or weekly with a curated summary of pricing changes (regardless of whether anything dramatic happened). Costs 1 credit. Watch lives 90 days. Set-and-forget for agents that want a periodic snapshot without subscribing to realtime transitions.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cadence | Yes | How often the digest fires | |
| callback_url | Yes | HTTPS URL to POST to when the digest fires | |
| secret | No | Optional HMAC shared secret |
Implementation Reference
- mcp-server/src/index.ts:877-904 (handler)The MCP server tool registration and handler for 'create_digest_watch'. Defines the tool with cadence/callback_url/secret schema, calls fetchJSON to POST /premium/watches, and returns a confirmation text response.
server.tool( 'create_digest_watch', 'Register a scheduled digest webhook that fires daily or weekly with a curated summary of pricing changes (regardless of whether anything dramatic happened). Costs 1 credit. Watch lives 90 days. Set-and-forget for agents that want a periodic snapshot without subscribing to realtime transitions.', { cadence: z.enum(['daily', 'weekly']).describe('How often the digest fires'), callback_url: z.string().describe('HTTPS URL to POST to when the digest fires'), secret: z.string().optional().describe('Optional HMAC shared secret'), }, async ({ cadence, callback_url, secret }) => { const body: Record<string, unknown> = { spec: { type: 'digest', cadence }, callback_url, }; if (secret !== undefined) body.secret = secret; const data = (await fetchJSON('/premium/watches', { method: 'POST', body, auth: true })) as { watch: { id: string; expires_at: string }; billing?: { credits_remaining?: number }; }; return { content: [ { type: 'text' as const, text: `Created ${cadence} digest watch ${data.watch.id} (expires ${data.watch.expires_at}). First fire at the next 7am UTC daily cron. Credits remaining: ${data.billing?.credits_remaining ?? '?'}`, }, ], }; }, ); - mcp-server/src/index.ts:19-57 (helper)The fetchJSON helper function used by the handler to make authenticated API requests to the TensorFeed API.
async function fetchJSON(path: string, opts: FetchOptions = {}): Promise<unknown> { const headers: Record<string, string> = { 'User-Agent': `TensorFeed-MCP/${SDK_VERSION}`, }; if (opts.body !== undefined) headers['Content-Type'] = 'application/json'; if (opts.auth) { const token = process.env.TENSORFEED_TOKEN; if (!token) { throw new Error( 'TENSORFEED_TOKEN env var is not set. Premium MCP tools require a bearer token. ' + 'Buy credits at https://tensorfeed.ai/developers/agent-payments and pass the returned tf_live_... token via the TENSORFEED_TOKEN env var in your MCP client config.', ); } headers['Authorization'] = `Bearer ${token}`; } const res = await fetch(`${API_BASE}${path}`, { method: opts.method ?? 'GET', headers, ...(opts.body !== undefined ? { body: JSON.stringify(opts.body) } : {}), }); if (!res.ok) { let errPayload: unknown; try { errPayload = await res.json(); } catch { errPayload = await res.text().catch(() => ''); } if (res.status === 402) { throw new Error( `Payment required (402). Your token may be out of credits. Top up at https://tensorfeed.ai/developers/agent-payments. Detail: ${JSON.stringify(errPayload)}`, ); } if (res.status === 401) { throw new Error( `Token rejected (401). Check that TENSORFEED_TOKEN is set to a valid tf_live_... token. Detail: ${JSON.stringify(errPayload)}`, ); } throw new Error(`API error ${res.status}: ${JSON.stringify(errPayload)}`); } - mcp-server/src/index.ts:880-884 (schema)Zod schema for the tool's input parameters: cadence (enum daily/weekly), callback_url (string), and optional secret (string).
{ cadence: z.enum(['daily', 'weekly']).describe('How often the digest fires'), callback_url: z.string().describe('HTTPS URL to POST to when the digest fires'), secret: z.string().optional().describe('Optional HMAC shared secret'), }, - sdk/javascript/src/index.ts:1131-1143 (handler)JavaScript SDK method createDigestWatch - delegates to createWatch with spec type 'digest'.
async createDigestWatch(options: { cadence: 'daily' | 'weekly'; callbackUrl: string; secret?: string; fireCap?: number; }): Promise<WatchCreateResponse> { return this.createWatch({ spec: { type: 'digest', cadence: options.cadence }, callbackUrl: options.callbackUrl, secret: options.secret, fireCap: options.fireCap, }); } - sdk/python/tensorfeed/client.py:624-671 (handler)Python SDK method create_digest_watch - delegates to create_watch with spec type 'digest'.
def create_digest_watch( self, *, cadence: str, callback_url: str, secret: str | None = None, fire_cap: int | None = None, ) -> dict[str, Any]: """Register a scheduled digest watch. Costs 1 credit at registration. Fires on a fixed cadence (daily or weekly) with a curated summary of pricing changes, added/removed models, and total change count for the period, regardless of whether anything dramatic happened. Set-and-forget for agents that want a periodic snapshot without subscribing to realtime transitions. First fire happens at the next daily 7am UTC cron after registration. Daily watches re-fire roughly every 24 hours; weekly watches re-fire roughly every 7 days. A small slack window (1h for daily, 12h for weekly) absorbs cron drift. Same delivery contract as ``create_watch``: HMAC-SHA256 signed POST to callback_url with X-TensorFeed-Signature and X-TensorFeed-Watch-Id headers. The fire payload's ``match.type`` is ``'digest'`` so consumers can route on it. Args: cadence: 'daily' or 'weekly'. callback_url: HTTPS URL to POST to on each fire. secret: Optional HMAC shared secret. fire_cap: Max fires before auto-disable (default 100). Returns: Same shape as ``create_watch``: dict with ``watch`` (full record) and ``billing``. Raises: ValueError: if no token is set on the client PaymentRequired: if the token has insufficient credits TensorFeedError: 400 on invalid cadence or callback URL """ return self.create_watch( spec={"type": "digest", "cadence": cadence}, callback_url=callback_url, secret=secret, fire_cap=fire_cap, )