@tallyforagents/sdk 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +457 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +397 -2
- package/dist/index.d.ts +397 -2
- package/dist/index.js +457 -2
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/agents.ts","../src/resources/payments.ts","../src/resources/webhooks.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Tally SDK error types. The server returns a consistent shape on every\n// failure — see src/lib/api-errors.ts in the web app — and the SDK turns\n// it into typed exceptions consumers can catch and branch on.\n//\n// Usage in consumer code:\n//\n// try {\n// await tally.agents.upsert({ id: \"research-bot\", display_name: \"...\" });\n// } catch (e) {\n// if (e instanceof AuthenticationError) { /* rotate key */ }\n// if (e instanceof ValidationError) { /* fix input */ }\n// throw e;\n// }\n\nexport type ApiErrorPayload = {\n type: string;\n message: string;\n code?: string;\n details?: unknown;\n};\n\nexport class TallyError extends Error {\n readonly type: string;\n readonly code?: string;\n readonly status: number;\n readonly details?: unknown;\n\n constructor(opts: {\n type: string;\n message: string;\n status: number;\n code?: string;\n details?: unknown;\n }) {\n super(opts.message);\n this.name = \"TallyError\";\n this.type = opts.type;\n this.code = opts.code;\n this.status = opts.status;\n this.details = opts.details;\n }\n}\n\nexport class AuthenticationError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class NotFoundError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"ValidationError\";\n }\n}\n\nexport class RateLimitError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"RateLimitError\";\n }\n}\n\nexport class ConflictError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"ConflictError\";\n }\n}\n\n// Maps server error.type → typed exception class.\nexport function makeError(payload: ApiErrorPayload, status: number): TallyError {\n switch (payload.type) {\n case \"unauthenticated\":\n case \"forbidden\":\n return new AuthenticationError(payload, status);\n case \"not_found\":\n return new NotFoundError(payload, status);\n case \"validation_failed\":\n return new ValidationError(payload, status);\n case \"rate_limited\":\n return new RateLimitError(payload, status);\n case \"conflict\":\n return new ConflictError(payload, status);\n default:\n return new TallyError({ ...payload, status });\n }\n}\n","import { makeError, TallyError, type ApiErrorPayload } from \"./errors\";\n\n// Thin HTTP client used by every resource. Centralizes:\n// - Authorization header\n// - JSON request/response handling\n// - Error mapping (server error.type → typed exception)\n//\n// Uses Node 18+'s native fetch. Works in browsers too if you ever want to\n// hit the API from one — though the more common pattern is server-to-server\n// from the consumer's agent infrastructure.\n\nexport type ClientOptions = {\n /** Tally API key (begins with `tly_`). */\n apiKey: string;\n /** Base URL of the Tally API. Defaults to https://app.tallyforagents.com. Override for local dev or self-hosting. */\n baseUrl?: string;\n /** Custom fetch implementation. Useful for tests or non-Node runtimes. */\n fetch?: typeof fetch;\n};\n\nexport class TallyClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly #fetch: typeof fetch;\n\n constructor(opts: ClientOptions) {\n if (\n !opts.apiKey ||\n (!opts.apiKey.startsWith(\"tly_test_\") && !opts.apiKey.startsWith(\"tly_live_\"))\n ) {\n throw new TallyError({\n type: \"validation_failed\",\n message:\n \"Invalid API key. Tally keys start with 'tly_test_' (test mode) or 'tly_live_' (live mode).\",\n status: 0,\n });\n }\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? \"https://app.tallyforagents.com\").replace(/\\/$/, \"\");\n this.#fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this.#fetch !== \"function\") {\n throw new TallyError({\n type: \"internal\",\n message: \"fetch is not available in this runtime. Provide one via `fetch` option.\",\n status: 0,\n });\n }\n }\n\n async request<T>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const res = await this.#fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n if (!res.ok) {\n let payload: { error?: ApiErrorPayload } = {};\n try {\n payload = await res.json();\n } catch {\n // Non-JSON error body — fall back to a generic message.\n }\n const err = payload.error ?? {\n type: \"internal\",\n message: `Request failed with status ${res.status}.`,\n };\n throw makeError(err, res.status);\n }\n\n // 204 No Content (e.g., future delete endpoints)\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n","import type { TallyClient } from \"../client\";\n\nexport type AgentWallet = {\n /** Wallet address (lowercased EVM hex) the agent can spend from. */\n address: string;\n /** Friendly name the wallet was given in the dashboard. */\n display_name: string;\n /** Optional role label (e.g., \"main\", \"treasury\"); null if unset. */\n role_label: string | null;\n /** Max per-tx spend in USDC as a decimal string. */\n max_per_tx_usdc: string;\n /** Daily cap in USDC as a decimal string, null if uncapped. */\n daily_cap_usdc: string | null;\n};\n\nexport type Agent = {\n /** Stable user-provided identifier (e.g., \"research-bot\"). */\n id: string;\n /** \"active\" — at least one activated (non-revoked) signer is attached.\n * \"no_permissions\" — no activated signer (may still have pending\n * grants — see pending_signers). */\n status: \"no_permissions\" | \"active\";\n mode: \"test\" | \"live\";\n /** ISO 8601 timestamp. */\n created_at: string;\n /** The account slug this agent belongs to. Surfaced so callers can\n * build dashboard deep-links (e.g., when telling the user to grant\n * a permission). */\n account_slug: string;\n /** Count of non-revoked, activated signers. */\n active_signers: number;\n /** Count of non-revoked, not-yet-activated signers. */\n pending_signers: number;\n /** Wallets this agent has active permission to spend from, with the\n * per-wallet caps from the permission. Empty array if no active\n * grants. Pick one to pass as `wallet` to tally.payments.create(). */\n wallets: AgentWallet[];\n};\n\nexport type AgentUpsertInput = {\n /** User-provided stable string identifier (e.g., \"research-bot\"). */\n id: string;\n};\n\n// agents.upsert / list / get — Phase 2's full surface.\n// Future phases will add: agents.delete, agents.permissions.*, etc.\n\nexport class AgentsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Creates the agent if it doesn't exist; no-op if it does.\n *\n * Scope: the active API key's account + mode. Same id can exist\n * independently in test and live mode for the same account.\n */\n async upsert(input: AgentUpsertInput): Promise<Agent> {\n const { agent } = await this.client.request<{ agent: Agent }>(\n \"POST\",\n \"/v1/agents\",\n input,\n );\n return agent;\n }\n\n async list(): Promise<Agent[]> {\n const { agents } = await this.client.request<{ agents: Agent[] }>(\n \"GET\",\n \"/v1/agents\",\n );\n return agents;\n }\n\n async get(id: string): Promise<Agent> {\n const { agent } = await this.client.request<{ agent: Agent }>(\n \"GET\",\n `/v1/agents/${encodeURIComponent(id)}`,\n );\n return agent;\n }\n}\n","import type { TallyClient } from \"../client\";\n\nexport type Payment = {\n id: string;\n /** \"pending\" until the on-chain tx confirms; updated by a follow-up\n * GET (planned) or webhook (Phase 6). */\n status: \"pending\" | \"confirmed\" | \"failed\";\n /** Transaction hash on the underlying chain. Set as soon as Privy\n * accepts the signed RPC; the SDK does not wait for receipt. */\n tx_hash: string | null;\n amount_usdc: string;\n to: string;\n from: string;\n memo: string | null;\n idempotency_key: string | null;\n created_at: string;\n};\n\nexport type PaymentCreateInput = {\n /** Agent's user-provided id (the externalId), e.g. \"research-bot\". */\n agent_id: string;\n /** Sender wallet address. Must be in this API key's account+mode and\n * must have an active permission grant for the agent. */\n wallet: string;\n /** Recipient EVM address. */\n to: string;\n /** Decimal USDC amount as a string, e.g. \"10\" or \"2.50\". */\n amount_usdc: string;\n /** Optional memo (max 200 chars), stored alongside the transaction. */\n memo?: string;\n /** Optional idempotency key (max 64 chars). Scoped to (account, mode);\n * retries with the same key return the original Payment without\n * resubmitting on-chain. */\n idempotency_key?: string;\n};\n\n// payments.create — single endpoint for Phase 4.\n// Future phases will add: list, get (with chain status refresh), retry.\n\nexport class PaymentsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Submits a USDC payment from one of the agent's granted wallets.\n *\n * Enforcement happens in two layers:\n * 1. Tally checks policy (per-tx max, recipient/contract allowlist,\n * expiry, daily cap) and rejects with a structured error before\n * any Privy call.\n * 2. Privy's secure enclave independently checks the per-tx max and\n * recipient/contract conditions encoded in the signer's policy.\n *\n * Returns immediately with `status: \"pending\"` and the on-chain\n * `tx_hash` once Privy accepts the signed RPC. The SDK does not wait\n * for block confirmation; the Transaction row is updated by a\n * separate confirmation flow (forthcoming).\n */\n async create(input: PaymentCreateInput): Promise<Payment> {\n const { payment } = await this.client.request<{ payment: Payment }>(\n \"POST\",\n \"/v1/payments\",\n input,\n );\n return payment;\n }\n\n /**\n * Fetches the current state of a payment by id. If still pending on\n * Tally's side, this call lazily refreshes from the chain — so polling\n * this is the canonical way to wait for `confirmed` / `failed`.\n */\n async get(id: string): Promise<Payment> {\n const { payment } = await this.client.request<{ payment: Payment }>(\n \"GET\",\n `/v1/payments/${encodeURIComponent(id)}`,\n );\n return payment;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\n// Webhook helpers for SDK consumers. Tally signs every delivery with\n// HMAC-SHA256 over `${timestamp}.${body}` and sends the signature in\n// the `tally-signature` header:\n//\n// tally-signature: t=<unix_seconds>,v1=<hex_lowercase>\n//\n// Receivers MUST verify before trusting any payload — otherwise a\n// known URL is forge-able. Pass the RAW request body (not the\n// JSON-parsed object) so the bytes match what Tally signed.\n//\n// The verifier is intentionally duplicated from the server-side\n// implementation (src/lib/webhook-sign.ts) to keep the SDK\n// self-contained — external consumers shouldn't depend on Tally's\n// server code.\n\nconst SIGNATURE_VERSION = \"v1\";\nexport const DEFAULT_TOLERANCE_SECONDS = 300; // 5 minutes\n\nexport type WebhookVerifyResult =\n | { ok: true }\n | {\n ok: false;\n reason:\n | \"missing_header\"\n | \"malformed_header\"\n | \"no_v1_signature\"\n | \"timestamp_out_of_tolerance\"\n | \"signature_mismatch\";\n };\n\nexport type WebhookVerifyInput = {\n /** Raw request body the receiver got — string, exactly the bytes\n * Tally signed. Don't pass a JSON-parsed object. */\n body: string;\n /** Value of the `tally-signature` header on the incoming request. */\n header: string | null | undefined;\n /** The plaintext signing secret you saved at webhook creation\n * (`whsec_<mode>_<base64url>`). */\n secret: string;\n /** Unix seconds. Defaults to now. Pin for tests. */\n now?: number;\n /** How far the header timestamp may drift from `now`. Defaults to\n * 300s (5 min). Tighten or loosen to taste; the wider the window,\n * the longer a stolen signature stays replayable. */\n toleranceSeconds?: number;\n};\n\nexport class WebhooksResource {\n /**\n * Verify a `tally-signature` header against the request body. Use in\n * your webhook handler before processing the payload.\n *\n * @example\n * ```ts\n * const body = await req.text(); // raw, not JSON-parsed\n * const result = tally.webhooks.verifySignature({\n * body,\n * header: req.headers.get(\"tally-signature\"),\n * secret: process.env.TALLY_WEBHOOK_SECRET!,\n * });\n * if (!result.ok) return new Response(\"invalid signature\", { status: 400 });\n * const event = JSON.parse(body);\n * // ... handle event\n * ```\n */\n verifySignature(input: WebhookVerifyInput): WebhookVerifyResult {\n return verifySignature(input);\n }\n}\n\nexport function verifySignature(input: WebhookVerifyInput): WebhookVerifyResult {\n const { body, header, secret } = input;\n const now = input.now ?? Math.floor(Date.now() / 1000);\n const tolerance = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n\n if (!header) return { ok: false, reason: \"missing_header\" };\n\n let timestamp: number | null = null;\n let v1: string | null = null;\n for (const part of header.split(\",\")) {\n const [k, v] = part.split(\"=\", 2);\n if (k === \"t\") {\n const n = Number(v);\n if (Number.isFinite(n)) timestamp = n;\n } else if (k === SIGNATURE_VERSION) {\n v1 = v;\n }\n }\n\n if (timestamp === null) return { ok: false, reason: \"malformed_header\" };\n if (!v1) return { ok: false, reason: \"no_v1_signature\" };\n\n if (Math.abs(now - timestamp) > tolerance) {\n return { ok: false, reason: \"timestamp_out_of_tolerance\" };\n }\n\n const expected = createHmac(\"sha256\", secret)\n .update(`${timestamp}.${body}`)\n .digest(\"hex\");\n\n if (expected.length !== v1.length) {\n return { ok: false, reason: \"signature_mismatch\" };\n }\n const a = Buffer.from(expected, \"utf8\");\n const b = Buffer.from(v1, \"utf8\");\n if (!timingSafeEqual(a, b)) {\n return { ok: false, reason: \"signature_mismatch\" };\n }\n return { ok: true };\n}\n","// @tallyforagents/sdk — the financial OS for AI agents.\n//\n// Usage:\n// import { Tally } from \"@tallyforagents/sdk\";\n//\n// const tally = new Tally({ apiKey: process.env.TALLY_API_KEY! });\n// await tally.agents.upsert({ id: \"research-bot\", display_name: \"Research Bot\" });\n\nimport { TallyClient, type ClientOptions } from \"./client\";\nimport { AgentsResource } from \"./resources/agents\";\nimport { PaymentsResource } from \"./resources/payments\";\nimport { WebhooksResource } from \"./resources/webhooks\";\n\nexport class Tally {\n readonly agents: AgentsResource;\n readonly payments: PaymentsResource;\n readonly webhooks: WebhooksResource;\n\n // Expose the underlying client for advanced use (custom retries, etc.).\n // Internal callers go through the resource classes instead.\n private readonly client: TallyClient;\n\n constructor(opts: ClientOptions) {\n this.client = new TallyClient(opts);\n this.agents = new AgentsResource(this.client);\n this.payments = new PaymentsResource(this.client);\n this.webhooks = new WebhooksResource();\n }\n}\n\nexport type { ClientOptions } from \"./client\";\nexport type { Agent, AgentUpsertInput, AgentWallet } from \"./resources/agents\";\nexport type { Payment, PaymentCreateInput } from \"./resources/payments\";\nexport type {\n WebhookVerifyInput,\n WebhookVerifyResult,\n} from \"./resources/webhooks\";\nexport { verifySignature } from \"./resources/webhooks\";\nexport {\n TallyError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ConflictError,\n} from \"./errors\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/resources/agents.ts","../src/pagination.ts","../src/resources/payments.ts","../src/resources/permissions.ts","../src/resources/wallets.ts","../src/resources/webhooks.ts","../src/resources/x402.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Tally SDK error types. The server returns a consistent shape on every\n// failure — see src/lib/api-errors.ts in the web app — and the SDK turns\n// it into typed exceptions consumers can catch and branch on.\n//\n// Usage in consumer code:\n//\n// try {\n// await tally.agents.upsert({ id: \"research-bot\", display_name: \"...\" });\n// } catch (e) {\n// if (e instanceof AuthenticationError) { /* rotate key */ }\n// if (e instanceof ValidationError) { /* fix input */ }\n// throw e;\n// }\n\nexport type ApiErrorPayload = {\n type: string;\n message: string;\n code?: string;\n details?: unknown;\n};\n\nexport class TallyError extends Error {\n readonly type: string;\n readonly code?: string;\n readonly status: number;\n readonly details?: unknown;\n\n constructor(opts: {\n type: string;\n message: string;\n status: number;\n code?: string;\n details?: unknown;\n }) {\n super(opts.message);\n this.name = \"TallyError\";\n this.type = opts.type;\n this.code = opts.code;\n this.status = opts.status;\n this.details = opts.details;\n }\n}\n\nexport class AuthenticationError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"AuthenticationError\";\n }\n}\n\nexport class NotFoundError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"NotFoundError\";\n }\n}\n\nexport class ValidationError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"ValidationError\";\n }\n}\n\nexport class RateLimitError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"RateLimitError\";\n }\n}\n\nexport class ConflictError extends TallyError {\n constructor(payload: ApiErrorPayload, status: number) {\n super({ ...payload, status });\n this.name = \"ConflictError\";\n }\n}\n\n// Maps server error.type → typed exception class.\nexport function makeError(payload: ApiErrorPayload, status: number): TallyError {\n switch (payload.type) {\n case \"unauthenticated\":\n case \"forbidden\":\n return new AuthenticationError(payload, status);\n case \"not_found\":\n return new NotFoundError(payload, status);\n case \"validation_failed\":\n return new ValidationError(payload, status);\n case \"rate_limited\":\n return new RateLimitError(payload, status);\n case \"conflict\":\n return new ConflictError(payload, status);\n default:\n return new TallyError({ ...payload, status });\n }\n}\n","import { makeError, TallyError, type ApiErrorPayload } from \"./errors\";\n\n// One-shot warning when the API key being used is in its rotation\n// grace window. The server sets `Tally-Rotation-Grace-Until` on every\n// /v1/* response when grace is active; we surface it on stderr so the\n// developer notices before the key actually expires. Throttled to\n// once per process per (key + grace_until) tuple so high-volume\n// callers don't get spammed.\nconst warnedRotations = new Set<string>();\nfunction warnRotationOnce(key: string, until: string) {\n const id = `${key.slice(0, 12)}:${until}`;\n if (warnedRotations.has(id)) return;\n warnedRotations.add(id);\n const remaining = (() => {\n const ms = new Date(until).getTime() - Date.now();\n if (ms <= 0) return \"shortly\";\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n return h > 0 ? `${h}h ${m}m` : `${m}m`;\n })();\n // Use stderr so it doesn't pollute the program's normal output.\n // eslint-disable-next-line no-console\n console.warn(\n `[tally] API key is in its rotation grace window (ends in ~${remaining}, at ${until}). Switch to the rotated key before then to avoid 401s.`,\n );\n}\n\n// Thin HTTP client used by every resource. Centralizes:\n// - Authorization header\n// - JSON request/response handling\n// - Error mapping (server error.type → typed exception)\n//\n// Uses Node 18+'s native fetch. Works in browsers too if you ever want to\n// hit the API from one — though the more common pattern is server-to-server\n// from the consumer's agent infrastructure.\n\nexport type ClientOptions = {\n /** Tally API key (begins with `tly_`). */\n apiKey: string;\n /** Base URL of the Tally API. Defaults to https://app.tallyforagents.com. Override for local dev or self-hosting. */\n baseUrl?: string;\n /** Custom fetch implementation. Useful for tests or non-Node runtimes. */\n fetch?: typeof fetch;\n};\n\nexport class TallyClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly #fetch: typeof fetch;\n\n constructor(opts: ClientOptions) {\n if (\n !opts.apiKey ||\n (!opts.apiKey.startsWith(\"tly_test_\") && !opts.apiKey.startsWith(\"tly_live_\"))\n ) {\n throw new TallyError({\n type: \"validation_failed\",\n message:\n \"Invalid API key. Tally keys start with 'tly_test_' (test mode) or 'tly_live_' (live mode).\",\n status: 0,\n });\n }\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? \"https://app.tallyforagents.com\").replace(/\\/$/, \"\");\n this.#fetch = opts.fetch ?? globalThis.fetch;\n if (typeof this.#fetch !== \"function\") {\n throw new TallyError({\n type: \"internal\",\n message: \"fetch is not available in this runtime. Provide one via `fetch` option.\",\n status: 0,\n });\n }\n }\n\n async request<T>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const res = await this.#fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n\n // Surface rotation-grace warning on every response (success or\n // error) where the server attached the header. Server sets it on\n // post-auth responses; absent header = no rotation in progress.\n const graceUntil = res.headers.get(\"tally-rotation-grace-until\");\n if (graceUntil) warnRotationOnce(this.apiKey, graceUntil);\n\n if (!res.ok) {\n let payload: { error?: ApiErrorPayload } = {};\n try {\n payload = await res.json();\n } catch {\n // Non-JSON error body — fall back to a generic message.\n }\n const err = payload.error ?? {\n type: \"internal\",\n message: `Request failed with status ${res.status}.`,\n };\n throw makeError(err, res.status);\n }\n\n // 204 No Content (e.g., future delete endpoints)\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n","import type { TallyClient } from \"../client\";\n\nexport type AgentWallet = {\n /** Wallet address (lowercased EVM hex) the agent can spend from. */\n address: string;\n /** Friendly name the wallet was given in the dashboard. */\n display_name: string;\n /** Optional role label (e.g., \"main\", \"treasury\"); null if unset. */\n role_label: string | null;\n /** Max per-tx spend in USDC as a decimal string. */\n max_per_tx_usdc: string;\n /** Daily cap in USDC as a decimal string, null if uncapped. */\n daily_cap_usdc: string | null;\n};\n\nexport type Agent = {\n /** Stable user-provided identifier (e.g., \"research-bot\"). */\n id: string;\n /** \"active\" — at least one activated (non-revoked) signer is attached.\n * \"no_permissions\" — no activated signer (may still have pending\n * grants — see pending_signers). */\n status: \"no_permissions\" | \"active\";\n mode: \"test\" | \"live\";\n /** ISO 8601 timestamp. */\n created_at: string;\n /** The account slug this agent belongs to. Surfaced so callers can\n * build dashboard deep-links (e.g., when telling the user to grant\n * a permission). */\n account_slug: string;\n /** Count of non-revoked, activated signers. */\n active_signers: number;\n /** Count of non-revoked, not-yet-activated signers. */\n pending_signers: number;\n /** Wallets this agent has active permission to spend from, with the\n * per-wallet caps from the permission. Empty array if no active\n * grants. Pick one to pass as `wallet` to tally.payments.create(). */\n wallets: AgentWallet[];\n};\n\nexport type AgentUpsertInput = {\n /** User-provided stable string identifier (e.g., \"research-bot\"). */\n id: string;\n};\n\n// agents.upsert / list / get — Phase 2's full surface.\n// Future phases will add: agents.delete, agents.permissions.*, etc.\n\nexport class AgentsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Creates the agent if it doesn't exist; no-op if it does.\n *\n * Scope: the active API key's account + mode. Same id can exist\n * independently in test and live mode for the same account.\n */\n async upsert(input: AgentUpsertInput): Promise<Agent> {\n const { agent } = await this.client.request<{ agent: Agent }>(\n \"POST\",\n \"/v1/agents\",\n input,\n );\n return agent;\n }\n\n async list(): Promise<Agent[]> {\n const { agents } = await this.client.request<{ agents: Agent[] }>(\n \"GET\",\n \"/v1/agents\",\n );\n return agents;\n }\n\n async get(id: string): Promise<Agent> {\n const { agent } = await this.client.request<{ agent: Agent }>(\n \"GET\",\n `/v1/agents/${encodeURIComponent(id)}`,\n );\n return agent;\n }\n\n /**\n * Soft-deletes an agent. The row stays in the DB so historical\n * transactions keep their attribution; future list/get responses\n * hide it.\n *\n * Throws `ConflictError` (HTTP 409, `code: \"has_active_grants\"`) if\n * the agent has any active permissions — revoke them first.\n *\n * Re-creating an agent with the same `id` via `upsert()` is the\n * supported way to bring a deleted agent back.\n */\n async delete(id: string): Promise<void> {\n await this.client.request<{ deleted: boolean; id: string }>(\n \"DELETE\",\n `/v1/agents/${encodeURIComponent(id)}`,\n );\n }\n}\n","// Stripe-style auto-paginating list result. Implements `AsyncIterable`\n// so callers can `for await (const item of list) { ... }` and the SDK\n// transparently fetches subsequent pages as iteration consumes items.\n//\n// Server contract: each fetch returns `{ data: T[], next_cursor: string | null }`.\n// When `next_cursor` is null, the iterator stops.\n//\n// Used by:\n// - `tally.payments.list()`\n// - `tally.permissions.list()` (Phase 2)\n// - any future v1 list endpoint that follows the same shape\n\nexport interface PageFetcher<T> {\n (cursor: string | null): Promise<{ data: T[]; next_cursor: string | null }>;\n}\n\nexport class AsyncResourcePage<T> implements AsyncIterable<T> {\n constructor(private readonly fetchPage: PageFetcher<T>) {}\n\n /**\n * Async-iterates every item across all pages. Stops when the server\n * returns `next_cursor: null`.\n *\n * ```ts\n * for await (const p of tally.payments.list({ status: \"confirmed\" })) {\n * console.log(p.id);\n * }\n * ```\n */\n async *[Symbol.asyncIterator](): AsyncGenerator<T> {\n let cursor: string | null = null;\n while (true) {\n const page = await this.fetchPage(cursor);\n for (const item of page.data) yield item;\n if (!page.next_cursor) break;\n cursor = page.next_cursor;\n }\n }\n\n /**\n * Collects items into an array, optionally bounded. `toArray()` with\n * no argument pulls every page; `toArray(20)` stops after the first\n * 20 items (across whatever page boundaries that crosses).\n *\n * ```ts\n * const recent = await tally.payments.list().toArray(20);\n * ```\n */\n async toArray(maxItems?: number): Promise<T[]> {\n const out: T[] = [];\n for await (const item of this) {\n out.push(item);\n if (maxItems !== undefined && out.length >= maxItems) break;\n }\n return out;\n }\n\n /**\n * Returns just the first page (no auto-pagination). Use when the\n * cursor itself matters — e.g., persisting it across runs to resume\n * iteration later.\n *\n * ```ts\n * const { data, next_cursor } = await tally.payments.list().firstPage();\n * // … store next_cursor; next run: tally.payments.list().pageAfter(saved_cursor)\n * ```\n */\n async firstPage(): Promise<{ data: T[]; next_cursor: string | null }> {\n return this.fetchPage(null);\n }\n\n /**\n * Returns the page that follows the given cursor. Useful for resuming\n * iteration from a previously-persisted cursor, or for manual paging\n * when the auto-iterator's eager fetching isn't a fit.\n */\n async pageAfter(\n cursor: string,\n ): Promise<{ data: T[]; next_cursor: string | null }> {\n return this.fetchPage(cursor);\n }\n}\n","import type { TallyClient } from \"../client\";\nimport { AsyncResourcePage } from \"../pagination\";\n\nexport type Payment = {\n id: string;\n /** \"pending\" until the on-chain tx confirms; updated by a follow-up\n * GET or webhook. */\n status: \"pending\" | \"confirmed\" | \"failed\";\n /** Transaction hash on the underlying chain. Set as soon as Privy\n * accepts the signed RPC; the SDK does not wait for receipt. */\n tx_hash: string | null;\n amount_usdc: string;\n /** Destination address. For outbound, this is the external recipient.\n * For inbound, this is one of your wallets. */\n to: string;\n /** Source address. For outbound, this is your wallet. For inbound,\n * this is the external sender. */\n from: string;\n memo: string | null;\n idempotency_key: string | null;\n created_at: string;\n /** \"inbound\" or \"outbound\". Populated on list responses; may be\n * undefined on responses from `create()` or `get()` (which always\n * describe outbound payments). */\n direction?: \"inbound\" | \"outbound\";\n /** Your wallet's address — always one of YOUR wallets regardless of\n * direction. Same as `from` for outbound, `to` for inbound. */\n wallet_address?: string;\n /** Friendly name of `wallet_address`. */\n wallet_display_name?: string;\n /** The agent's externalId for outbound payments; null for inbound. */\n agent_id?: string | null;\n /** Block timestamp from the chain, set after the tx confirms. */\n block_timestamp?: string | null;\n /** Human-readable reason for `status: \"failed\"` rows. */\n error_reason?: string | null;\n};\n\nexport type PaymentListFilters = {\n /** Filter by payment status. */\n status?: \"pending\" | \"confirmed\" | \"failed\";\n /** Filter by direction. */\n direction?: \"inbound\" | \"outbound\";\n /** Filter by agent (external id, the user-provided string). */\n agent_id?: string;\n /** Filter by wallet address (case-insensitive). */\n wallet?: string;\n /** Free-text search over tx hash, addresses, memo. */\n q?: string;\n /** Max items per page. Default 50, max 100. The auto-iterator uses\n * this for each page fetch. */\n limit?: number;\n};\n\nexport type PaymentCreateInput = {\n /** Agent's user-provided id (the externalId), e.g. \"research-bot\". */\n agent_id: string;\n /** Sender wallet address. Must be in this API key's account+mode and\n * must have an active permission grant for the agent. */\n wallet: string;\n /** Recipient EVM address. */\n to: string;\n /** Decimal USDC amount as a string, e.g. \"10\" or \"2.50\". */\n amount_usdc: string;\n /** Optional memo (max 200 chars), stored alongside the transaction. */\n memo?: string;\n /** Optional idempotency key (max 64 chars). Scoped to (account, mode);\n * retries with the same key return the original Payment without\n * resubmitting on-chain. */\n idempotency_key?: string;\n};\n\n// payments.create — single endpoint for Phase 4.\n// Future phases will add: list, get (with chain status refresh), retry.\n\nexport class PaymentsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Submits a USDC payment from one of the agent's granted wallets.\n *\n * Enforcement happens in two layers:\n * 1. Tally checks policy (per-tx max, recipient/contract allowlist,\n * expiry, daily cap) and rejects with a structured error before\n * any Privy call.\n * 2. Privy's secure enclave independently checks the per-tx max and\n * recipient/contract conditions encoded in the signer's policy.\n *\n * Returns immediately with `status: \"pending\"` and the on-chain\n * `tx_hash` once Privy accepts the signed RPC. The SDK does not wait\n * for block confirmation; the Transaction row is updated by a\n * separate confirmation flow (forthcoming).\n */\n async create(input: PaymentCreateInput): Promise<Payment> {\n const { payment } = await this.client.request<{ payment: Payment }>(\n \"POST\",\n \"/v1/payments\",\n input,\n );\n return payment;\n }\n\n /**\n * Fetches the current state of a payment by id. If still pending on\n * Tally's side, this call lazily refreshes from the chain — so polling\n * this is the canonical way to wait for `confirmed` / `failed`.\n */\n async get(id: string): Promise<Payment> {\n const { payment } = await this.client.request<{ payment: Payment }>(\n \"GET\",\n `/v1/payments/${encodeURIComponent(id)}`,\n );\n return payment;\n }\n\n /**\n * Lists payments in the API key's account + mode, auto-paginated.\n * Returns an `AsyncResourcePage` you can `for await` over to iterate\n * every payment, or call `.toArray(n)` for a bounded read.\n *\n * Pending outbound rows are lazily refreshed from the chain on read,\n * matching the dashboard's behavior — polling `list({ status: \"pending\" })`\n * is a valid way to wait for confirmation.\n *\n * ```ts\n * for await (const p of tally.payments.list({ status: \"confirmed\" })) {\n * console.log(p.id, p.amount_usdc, p.to);\n * }\n *\n * // Or bounded:\n * const last20 = await tally.payments.list({ direction: \"outbound\" }).toArray(20);\n * ```\n */\n list(filters: PaymentListFilters = {}): AsyncResourcePage<Payment> {\n const { limit, status, direction, agent_id, wallet, q } = filters;\n return new AsyncResourcePage<Payment>(async (cursor) => {\n const qs = new URLSearchParams();\n if (cursor) qs.set(\"cursor\", cursor);\n if (limit !== undefined) qs.set(\"limit\", String(limit));\n if (status) qs.set(\"status\", status);\n if (direction) qs.set(\"direction\", direction);\n if (agent_id) qs.set(\"agent_id\", agent_id);\n if (wallet) qs.set(\"wallet\", wallet);\n if (q) qs.set(\"q\", q);\n const query = qs.toString();\n const path = query ? `/v1/payments?${query}` : \"/v1/payments\";\n return this.client.request<{ data: Payment[]; next_cursor: string | null }>(\n \"GET\",\n path,\n );\n });\n }\n}\n","import type { TallyClient } from \"../client\";\nimport { AsyncResourcePage } from \"../pagination\";\n\nexport type Permission = {\n /** Stable cuid for this grant. Use as the reference id if/when revoke\n * or update endpoints land. */\n id: string;\n /** Agent's user-provided externalId (e.g., \"research-bot\"). */\n agent_id: string;\n /** Wallet address this grant is on. */\n wallet_address: string;\n /** Friendly wallet name set at provisioning. */\n wallet_display_name: string;\n /** \"active\" once the wallet owner has authorized the signer on-chain;\n * \"pending\" before that. */\n status: \"active\" | \"pending\";\n max_per_tx_usdc: string;\n daily_cap_usdc: string | null;\n /** USDC already moved by this grant today (UTC). */\n used_today_usdc: string;\n /** daily_cap_usdc minus used_today_usdc, or null if uncapped. Clamped\n * to 0 when over-spent (shouldn't happen — daily-cap enforcement is\n * pre-broadcast — but defensively non-negative). */\n remaining_today_usdc: string | null;\n /** Whitelisted recipient addresses. Empty = unrestricted. */\n recipient_allowlist: string[];\n /** Whitelisted contract addresses. Defaults to the mode's USDC contract. */\n contract_allowlist: string[];\n /** ISO 8601 timestamp; null if no expiry. */\n expires_at: string | null;\n created_at: string;\n activated_at: string | null;\n};\n\nexport type PermissionListFilters = {\n /** Filter by agent (external id). */\n agent_id?: string;\n /** Max items per page. Default 50, max 100. */\n limit?: number;\n};\n\nexport class PermissionsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Lists active grants in the API key's account + mode, auto-paginated.\n * Returns an `AsyncResourcePage` you can `for await` over to iterate\n * every permission, or call `.toArray(n)` for a bounded read.\n *\n * Each row includes the granted caps, today's usage, and the rolling\n * remaining-daily-allowance, so agent code can preflight a payment\n * without round-tripping the policy bounds.\n *\n * ```ts\n * for await (const p of tally.permissions.list({ agent_id: \"research-bot\" })) {\n * console.log(`${p.wallet_display_name}: $${p.remaining_today_usdc} left`);\n * }\n * ```\n */\n list(filters: PermissionListFilters = {}): AsyncResourcePage<Permission> {\n const { limit, agent_id } = filters;\n return new AsyncResourcePage<Permission>(async (cursor) => {\n const qs = new URLSearchParams();\n if (cursor) qs.set(\"cursor\", cursor);\n if (limit !== undefined) qs.set(\"limit\", String(limit));\n if (agent_id) qs.set(\"agent_id\", agent_id);\n const query = qs.toString();\n const path = query ? `/v1/permissions?${query}` : \"/v1/permissions\";\n return this.client.request<{\n data: Permission[];\n next_cursor: string | null;\n }>(\"GET\", path);\n });\n }\n}\n","import type { TallyClient } from \"../client\";\n\nexport type Wallet = {\n /** Stable Tally cuid for this wallet. Pass as `wallet_id` to permission\n * routes (grant / edit / revoke). */\n id: string;\n /** EVM address. Use as `wallet` in `tally.payments.create({ wallet })`. */\n address: string;\n /** Friendly name set when the wallet was created. */\n display_name: string;\n /** Optional role label (e.g., \"treasury\", \"ops\"); null if unset. */\n role_label: string | null;\n mode: \"test\" | \"live\";\n /** ISO 8601 timestamp. */\n created_at: string;\n};\n\nexport type WalletCreateInput = {\n /** Human-friendly name. 1–60 chars after trimming. */\n display_name: string;\n /** Optional role label (1–40 chars after trimming). */\n role_label?: string;\n};\n\nexport class WalletsResource {\n constructor(private readonly client: TallyClient) {}\n\n /**\n * Lists every wallet in the API key's account + mode. Wallets are\n * returned oldest-first (so the \"Main Wallet\" auto-provisioned at\n * sign-in shows up first).\n */\n async list(): Promise<Wallet[]> {\n const { wallets } = await this.client.request<{ wallets: Wallet[] }>(\n \"GET\",\n \"/v1/wallets\",\n );\n return wallets;\n }\n\n /**\n * Provisions a new Privy server wallet in the API key's account + mode.\n * The wallet is owned (in Privy) by the oldest `owner`-role member of\n * the account, so SDK-created wallets behave identically to dashboard-\n * created ones: the same passkey approves any future signer changes.\n */\n async create(input: WalletCreateInput): Promise<Wallet> {\n const { wallet } = await this.client.request<{ wallet: Wallet }>(\n \"POST\",\n \"/v1/wallets\",\n input,\n );\n return wallet;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { TallyClient } from \"../client\";\n\n// Webhook helpers for SDK consumers. Tally signs every delivery with\n// HMAC-SHA256 over `${timestamp}.${body}` and sends the signature in\n// the `tally-signature` header:\n//\n// tally-signature: t=<unix_seconds>,v1=<hex_lowercase>\n//\n// Receivers MUST verify before trusting any payload — otherwise a\n// known URL is forge-able. Pass the RAW request body (not the\n// JSON-parsed object) so the bytes match what Tally signed.\n//\n// The verifier is intentionally duplicated from the server-side\n// implementation (src/lib/webhook-sign.ts) to keep the SDK\n// self-contained — external consumers shouldn't depend on Tally's\n// server code.\n\nconst SIGNATURE_VERSION = \"v1\";\nexport const DEFAULT_TOLERANCE_SECONDS = 300; // 5 minutes\n\nexport type WebhookVerifyResult =\n | { ok: true }\n | {\n ok: false;\n reason:\n | \"missing_header\"\n | \"malformed_header\"\n | \"no_v1_signature\"\n | \"timestamp_out_of_tolerance\"\n | \"signature_mismatch\";\n };\n\nexport type WebhookVerifyInput = {\n /** Raw request body the receiver got — string, exactly the bytes\n * Tally signed. Don't pass a JSON-parsed object. */\n body: string;\n /** Value of the `tally-signature` header on the incoming request. */\n header: string | null | undefined;\n /** The plaintext signing secret you saved at webhook creation\n * (`whsec_<mode>_<base64url>`). */\n secret: string;\n /** Unix seconds. Defaults to now. Pin for tests. */\n now?: number;\n /** How far the header timestamp may drift from `now`. Defaults to\n * 300s (5 min). Tighten or loosen to taste; the wider the window,\n * the longer a stolen signature stays replayable. */\n toleranceSeconds?: number;\n};\n\nexport type WebhookEventType =\n | \"payment.created\"\n | \"payment.confirmed\"\n | \"payment.failed\"\n | \"inbound.received\"\n | \"permission.granted\"\n | \"permission.updated\"\n | \"permission.revoked\";\n\nexport type Webhook = {\n /** Stable cuid for this endpoint. Pass to `revoke()`. */\n id: string;\n mode: \"test\" | \"live\";\n /** Receiver URL Tally POSTs to. */\n url: string;\n /** Event types this endpoint subscribes to. */\n events: string[];\n /** First few characters of the secret (e.g., `whsec_test_abc…`).\n * Useful for identifying the secret in dashboards without\n * exposing the plaintext. */\n secret_prefix: string;\n created_at: string;\n revoked_at: string | null;\n /** ISO timestamp of the last delivery attempt. null until first send. */\n last_delivery_at: string | null;\n};\n\nexport type CreatedWebhook = Webhook & {\n /** Plaintext signing secret. Returned exactly once at creation.\n * Store it now — it's NOT recoverable later. */\n secret: string;\n};\n\nexport type WebhookCreateInput = {\n /** Receiver URL. Must be https:// (or http://localhost for dev). */\n url: string;\n /** Event types to subscribe to. */\n events: WebhookEventType[];\n};\n\nexport class WebhooksResource {\n /**\n * The TallyClient is optional so legacy zero-arg construction\n * (`new WebhooksResource()`) still works for non-class consumers who\n * only use `verifySignature`. List / create / revoke require a\n * client; calling them on a clientless instance throws.\n */\n constructor(private readonly client?: TallyClient) {}\n\n /**\n * Verify a `tally-signature` header against the request body. Use in\n * your webhook handler before processing the payload.\n *\n * @example\n * ```ts\n * const body = await req.text(); // raw, not JSON-parsed\n * const result = tally.webhooks.verifySignature({\n * body,\n * header: req.headers.get(\"tally-signature\"),\n * secret: process.env.TALLY_WEBHOOK_SECRET!,\n * });\n * if (!result.ok) return new Response(\"invalid signature\", { status: 400 });\n * const event = JSON.parse(body);\n * // ... handle event\n * ```\n */\n verifySignature(input: WebhookVerifyInput): WebhookVerifyResult {\n return verifySignature(input);\n }\n\n private requireClient(): TallyClient {\n if (!this.client) {\n throw new Error(\n \"WebhooksResource was constructed without a TallyClient. Use `new Tally({ apiKey })` to enable list/create/revoke.\",\n );\n }\n return this.client;\n }\n\n /**\n * Lists every webhook endpoint in the API key's account + mode.\n * Revoked endpoints are included (with `revoked_at` set) for audit.\n *\n * ```ts\n * for (const w of await tally.webhooks.list()) {\n * console.log(`${w.url} → ${w.events.join(\",\")}`);\n * }\n * ```\n */\n async list(): Promise<Webhook[]> {\n const { webhooks } = await this.requireClient().request<{\n webhooks: Webhook[];\n }>(\"GET\", \"/v1/webhooks\");\n return webhooks;\n }\n\n /**\n * Creates a new webhook endpoint. The signing secret is returned in\n * `webhook.secret` **exactly once** — store it now; it's not\n * recoverable later. If you lose it, revoke and recreate.\n *\n * ```ts\n * const webhook = await tally.webhooks.create({\n * url: \"https://example.com/tally/events\",\n * events: [\"payment.confirmed\", \"payment.failed\"],\n * });\n * console.log(webhook.secret); // shown once\n * ```\n */\n async create(input: WebhookCreateInput): Promise<CreatedWebhook> {\n const { webhook } = await this.requireClient().request<{\n webhook: CreatedWebhook;\n }>(\"POST\", \"/v1/webhooks\", input);\n return webhook;\n }\n\n /**\n * Revokes a webhook endpoint by id. No further deliveries will be\n * enqueued; deliveries already in-flight are not cancelled.\n * Idempotent: revoking an already-revoked endpoint is a no-op.\n *\n * ```ts\n * await tally.webhooks.revoke(\"whk_01HXYZ...\");\n * ```\n */\n async revoke(id: string): Promise<Webhook> {\n const { webhook } = await this.requireClient().request<{\n webhook: Webhook;\n }>(\"POST\", `/v1/webhooks/${encodeURIComponent(id)}/revoke`);\n return webhook;\n }\n}\n\nexport function verifySignature(input: WebhookVerifyInput): WebhookVerifyResult {\n const { body, header, secret } = input;\n const now = input.now ?? Math.floor(Date.now() / 1000);\n const tolerance = input.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n\n if (!header) return { ok: false, reason: \"missing_header\" };\n\n let timestamp: number | null = null;\n let v1: string | null = null;\n for (const part of header.split(\",\")) {\n const [k, v] = part.split(\"=\", 2);\n if (k === \"t\") {\n const n = Number(v);\n if (Number.isFinite(n)) timestamp = n;\n } else if (k === SIGNATURE_VERSION) {\n v1 = v;\n }\n }\n\n if (timestamp === null) return { ok: false, reason: \"malformed_header\" };\n if (!v1) return { ok: false, reason: \"no_v1_signature\" };\n\n if (Math.abs(now - timestamp) > tolerance) {\n return { ok: false, reason: \"timestamp_out_of_tolerance\" };\n }\n\n const expected = createHmac(\"sha256\", secret)\n .update(`${timestamp}.${body}`)\n .digest(\"hex\");\n\n if (expected.length !== v1.length) {\n return { ok: false, reason: \"signature_mismatch\" };\n }\n const a = Buffer.from(expected, \"utf8\");\n const b = Buffer.from(v1, \"utf8\");\n if (!timingSafeEqual(a, b)) {\n return { ok: false, reason: \"signature_mismatch\" };\n }\n return { ok: true };\n}\n","import type { TallyClient } from \"../client\";\nimport { TallyError } from \"../errors\";\nimport { PaymentsResource, type Payment } from \"./payments\";\n\n// x402 client — pay any HTTP service that follows the x402 protocol:\n//\n// 1. Caller makes a normal request.\n// 2. If the service returns 200, you're done — return it.\n// 3. If the service returns 402 Payment Required with an x402-shaped\n// body, parse the accepts[] terms, pay one of them via Tally,\n// and retry with the tx hash in the `X-Payment` header.\n//\n// `tally.x402.fetch(url, opts)` does all of that for you. The agent\n// just sees a single async call that returns the response (and the\n// payment receipt, if a payment was needed).\n\nconst X402_HEADER = \"x-payment\";\n\n/** Supported networks for x402 payments. Mirrors the chains Tally\n * itself supports (test=base-sepolia, live=base). If the server's\n * 402 response lists a network outside this set, the SDK throws\n * before attempting payment. */\nconst SUPPORTED_NETWORKS = new Set([\"base-sepolia\", \"base\"]);\n\n/** Shape of a single offer inside an x402 402 response's `accepts[]`. */\nexport type X402PaymentTerms = {\n scheme: string;\n network: string;\n /** Atomic USDC amount (micro-units, 6 decimals). String to preserve\n * precision over JSON. */\n maxAmountRequired: string;\n resource: string;\n description?: string;\n payTo: string;\n asset: string;\n /** Optional metadata the server may attach. */\n extra?: Record<string, unknown>;\n};\n\n/** Shape of an x402 402 response body. */\nexport type X402Response = {\n x402Version: number;\n error?: string;\n accepts?: X402PaymentTerms[];\n};\n\nexport type X402FetchInput = {\n /** Agent's externalId. The agent must have an active permission\n * grant on `wallet` with enough headroom to cover the x402 charge. */\n agent_id: string;\n /** Sender wallet address. Typically `agent.wallets[0].address` from\n * the response to `tally.agents.upsert()`. */\n wallet: string;\n /** HTTP method for the request. Defaults to \"GET\". */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n /** Extra request headers. The SDK overrides `x-payment` on the retry\n * but everything else passes through. */\n headers?: Record<string, string>;\n /** Request body. Passed through to fetch on both the initial call\n * and the retry; the SDK does not modify it. */\n body?: BodyInit | null;\n /** Client-side cap on what the SDK will spend on this call. If the\n * 402 asks for more than this, the SDK throws before paying. The\n * agent's policy caps remain authoritative server-side; this is a\n * per-call belt to the policy's suspenders. Decimal USDC, e.g. \"1.00\". */\n max_amount_usdc?: string;\n /** Memo stored on the Tally Payment row. Defaults to\n * `x402:${host}${pathname}`. */\n memo?: string;\n /** Idempotency key for the underlying `payments.create` call. If you\n * may retry the same logical x402 call, set this to a stable string\n * so a retry returns the original payment instead of double-spending.\n * Defaults to a fresh per-call key. */\n idempotency_key?: string;\n /** Per-call timeout in ms for the underlying fetches. Default: no\n * timeout (the runtime's default applies). */\n timeout_ms?: number;\n};\n\nexport type X402PaymentReceipt = {\n /** Tally Payment id (e.g. `pay_…`). */\n id: string;\n /** On-chain transaction hash. */\n tx_hash: string;\n /** Decimal USDC amount paid, e.g. \"0.05\". */\n amount_usdc: string;\n /** Recipient address from the 402 terms. */\n to: string;\n /** Network the payment landed on. */\n network: string;\n /** Memo stored on the Tally Payment row. */\n memo: string | null;\n};\n\nexport type X402FetchResult = {\n /** The final HTTP response. If the first call returned 200, this is\n * that response. Otherwise it's the post-payment retry response.\n * Check `response.ok` / `response.status` as you would with any\n * fetch — the SDK does not throw for non-200s after a successful\n * payment, because some x402 services return 4xx/5xx legitimately. */\n response: Response;\n /** Receipt for the payment the SDK made on your behalf. Null when\n * the first call returned 200 (no payment was needed). */\n payment: X402PaymentReceipt | null;\n};\n\nexport class X402Resource {\n readonly #payments: PaymentsResource;\n\n constructor(client: TallyClient) {\n this.#payments = new PaymentsResource(client);\n }\n\n /**\n * Fetch a URL that may be paywalled by the x402 protocol. If the\n * service returns 402, the SDK pays via Tally and retries\n * automatically. The agent code sees one call.\n *\n * ```ts\n * const { response, payment } = await tally.x402.fetch(\n * \"https://api.example.com/weather?city=Tokyo\",\n * { agent_id: \"hermes\", wallet: agent.wallets[0].address }\n * );\n *\n * if (response.ok) {\n * const data = await response.json();\n * if (payment) console.log(`paid ${payment.amount_usdc} USDC — ${payment.tx_hash}`);\n * }\n * ```\n *\n * Throws `TallyError` for SDK-side problems (network unreachable,\n * malformed 402 body, unsupported network, payment refused by\n * Tally, etc.). Lets non-200 retry responses pass through as-is.\n */\n async fetch(url: string, input: X402FetchInput): Promise<X402FetchResult> {\n const initial = await this.#doFetch(url, input, /*paymentTxHash*/ null);\n\n // Happy path: service didn't paywall this call. No payment needed.\n if (initial.status !== 402) {\n return { response: initial, payment: null };\n }\n\n // 402 — parse terms.\n let parsed: X402Response;\n try {\n parsed = (await initial.json()) as X402Response;\n } catch {\n throw new TallyError({\n type: \"x402_protocol\",\n message: \"Service returned 402 with a non-JSON body.\",\n status: 0,\n });\n }\n\n const terms = parsed.accepts?.[0];\n if (!terms) {\n throw new TallyError({\n type: \"x402_protocol\",\n message: \"402 response had no `accepts[]` payment terms.\",\n status: 0,\n details: { x402Version: parsed.x402Version, error: parsed.error },\n });\n }\n\n if (!SUPPORTED_NETWORKS.has(terms.network)) {\n throw new TallyError({\n type: \"x402_protocol\",\n message: `x402 service requested unsupported network: ${terms.network}. Tally supports base-sepolia (test) and base (live).`,\n status: 0,\n details: { network: terms.network },\n });\n }\n\n const atomicAmount = (() => {\n try {\n return BigInt(terms.maxAmountRequired);\n } catch {\n throw new TallyError({\n type: \"x402_protocol\",\n message: `x402 service quoted an unparseable amount: ${terms.maxAmountRequired}`,\n status: 0,\n });\n }\n })();\n const decimalAmount = formatAtomicUSDC(atomicAmount);\n\n // Client-side safety cap (the Tally policy still bounds this\n // server-side; this is a per-call additional gate).\n if (input.max_amount_usdc !== undefined) {\n const capAtomic = parseDecimalUSDC(input.max_amount_usdc);\n if (atomicAmount > capAtomic) {\n throw new TallyError({\n type: \"x402_amount_exceeds_cap\",\n message: `x402 service requested ${decimalAmount} USDC, which exceeds the caller-supplied max_amount_usdc of ${input.max_amount_usdc}.`,\n status: 0,\n details: { requested_usdc: decimalAmount, max_usdc: input.max_amount_usdc },\n });\n }\n }\n\n // Pay via Tally.\n const memo = input.memo ?? defaultMemo(url);\n const idempotencyKey = input.idempotency_key ?? defaultIdempotencyKey(url);\n let payment: Payment;\n try {\n payment = await this.#payments.create({\n agent_id: input.agent_id,\n wallet: input.wallet,\n to: terms.payTo,\n amount_usdc: decimalAmount,\n memo,\n idempotency_key: idempotencyKey,\n });\n } catch (e) {\n // Re-throw without modification — the TallyError already carries\n // the right type (PolicyDeniedError-shape, validation, etc.).\n throw e;\n }\n\n if (!payment.tx_hash) {\n throw new TallyError({\n type: \"x402_payment_missing_tx_hash\",\n message: \"Tally accepted the payment but returned no tx_hash.\",\n status: 0,\n details: { payment_id: payment.id },\n });\n }\n\n // Retry with the tx hash. Many x402 servers wait for on-chain\n // confirmation before returning; expect this to take several\n // seconds on Base Sepolia.\n const retry = await this.#doFetch(url, input, payment.tx_hash);\n\n return {\n response: retry,\n payment: {\n id: payment.id,\n tx_hash: payment.tx_hash,\n amount_usdc: decimalAmount,\n to: terms.payTo,\n network: terms.network,\n memo: payment.memo,\n },\n };\n }\n\n async #doFetch(\n url: string,\n input: X402FetchInput,\n paymentTxHash: string | null,\n ): Promise<Response> {\n const headers: Record<string, string> = { ...(input.headers ?? {}) };\n if (paymentTxHash) headers[X402_HEADER] = paymentTxHash;\n\n const init: RequestInit = {\n method: input.method ?? \"GET\",\n headers,\n body: input.body ?? undefined,\n };\n\n if (input.timeout_ms !== undefined) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), input.timeout_ms);\n init.signal = controller.signal;\n try {\n return await fetch(url, init);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n return await fetch(url, init);\n }\n}\n\nfunction defaultMemo(url: string): string {\n try {\n const u = new URL(url);\n return `x402:${u.host}${u.pathname}`.slice(0, 200);\n } catch {\n return \"x402\";\n }\n}\n\nfunction defaultIdempotencyKey(url: string): string {\n // Fresh per-call key. Callers who want idempotent retries on the\n // same logical x402 fetch should pass their own key.\n try {\n const u = new URL(url);\n return `x402:${u.host}${u.pathname}:${Date.now()}`.slice(0, 64);\n } catch {\n return `x402:${Date.now()}`;\n }\n}\n\n/** Atomic micro-USDC → decimal string with no trailing zeros.\n * e.g. 50000n → \"0.05\", 1000000n → \"1\". */\nfunction formatAtomicUSDC(atomic: bigint): string {\n const whole = atomic / 1_000_000n;\n const frac = atomic % 1_000_000n;\n const fracStr = frac.toString().padStart(6, \"0\").replace(/0+$/, \"\");\n return fracStr ? `${whole}.${fracStr}` : `${whole}`;\n}\n\n/** Decimal USDC string → atomic micro-USDC. Throws on malformed input.\n * Used to compare a caller-supplied cap against a 402-quoted atomic\n * amount without losing precision. */\nfunction parseDecimalUSDC(decimal: string): bigint {\n if (!/^\\d+(\\.\\d{1,6})?$/.test(decimal.trim())) {\n throw new TallyError({\n type: \"validation_failed\",\n message: `Invalid decimal USDC amount: \"${decimal}\". Expected up to 6 fractional digits.`,\n status: 0,\n });\n }\n const [whole, frac = \"\"] = decimal.trim().split(\".\");\n const fracPadded = (frac + \"000000\").slice(0, 6);\n return BigInt(whole) * 1_000_000n + BigInt(fracPadded);\n}\n","// @tallyforagents/sdk — the financial OS for AI agents.\n//\n// Usage:\n// import { Tally } from \"@tallyforagents/sdk\";\n//\n// const tally = new Tally({ apiKey: process.env.TALLY_API_KEY! });\n// await tally.agents.upsert({ id: \"research-bot\", display_name: \"Research Bot\" });\n\nimport { TallyClient, type ClientOptions } from \"./client\";\nimport { AgentsResource } from \"./resources/agents\";\nimport { PaymentsResource } from \"./resources/payments\";\nimport { PermissionsResource } from \"./resources/permissions\";\nimport { WalletsResource } from \"./resources/wallets\";\nimport { WebhooksResource } from \"./resources/webhooks\";\nimport { X402Resource } from \"./resources/x402\";\n\nexport class Tally {\n readonly agents: AgentsResource;\n readonly payments: PaymentsResource;\n readonly permissions: PermissionsResource;\n readonly wallets: WalletsResource;\n readonly webhooks: WebhooksResource;\n readonly x402: X402Resource;\n\n // Expose the underlying client for advanced use (custom retries, etc.).\n // Internal callers go through the resource classes instead.\n private readonly client: TallyClient;\n\n constructor(opts: ClientOptions) {\n this.client = new TallyClient(opts);\n this.agents = new AgentsResource(this.client);\n this.payments = new PaymentsResource(this.client);\n this.permissions = new PermissionsResource(this.client);\n this.wallets = new WalletsResource(this.client);\n this.webhooks = new WebhooksResource(this.client);\n this.x402 = new X402Resource(this.client);\n }\n}\n\nexport type { ClientOptions } from \"./client\";\nexport type { Agent, AgentUpsertInput, AgentWallet } from \"./resources/agents\";\nexport type {\n Payment,\n PaymentCreateInput,\n PaymentListFilters,\n} from \"./resources/payments\";\nexport { AsyncResourcePage } from \"./pagination\";\nexport type { Wallet, WalletCreateInput } from \"./resources/wallets\";\nexport type {\n Permission,\n PermissionListFilters,\n} from \"./resources/permissions\";\nexport type {\n Webhook,\n CreatedWebhook,\n WebhookCreateInput,\n WebhookEventType,\n WebhookVerifyInput,\n WebhookVerifyResult,\n} from \"./resources/webhooks\";\nexport { verifySignature } from \"./resources/webhooks\";\nexport type {\n X402FetchInput,\n X402FetchResult,\n X402PaymentReceipt,\n X402PaymentTerms,\n X402Response,\n} from \"./resources/x402\";\nexport {\n TallyError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n ConflictError,\n} from \"./errors\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyforagents/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Tally TypeScript SDK — give AI agents USDC wallets and scoped programmable spending on Base.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tally",
|
|
@@ -50,12 +50,14 @@
|
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"prepare": "pnpm run build",
|
|
57
|
+
"prepublishOnly": "pnpm run build"
|
|
58
|
+
},
|
|
53
59
|
"devDependencies": {
|
|
54
60
|
"tsup": "^8.3.5",
|
|
55
61
|
"typescript": "^5"
|
|
56
|
-
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"build": "tsup",
|
|
59
|
-
"typecheck": "tsc --noEmit"
|
|
60
62
|
}
|
|
61
|
-
}
|
|
63
|
+
}
|