export declare const TOOL_NAMES: readonly ["linkedin_resolve_url", "linkedin_get_profile", "linkedin_search_people", "linkedin_get_company", "linkedin_get_posts", "reddit_search", "reddit_get_subreddit", "reddit_get_subreddit_posts", "reddit_get_user", "reddit_get_post", "reddit_resolve_url", "x_search", "x_get_profile", "x_get_tweets", "x_get_tweet", "x_resolve_url", "get_usage"]; export type ToolName = (typeof TOOL_NAMES)[number]; export declare const ERROR_CODES: readonly ["INVALID_INPUT", "NOT_FOUND", "UNAUTHORIZED", "KEY_REQUIRED", "AUTH_REQUIRED", "NOT_ENTITLED", "INSUFFICIENT_CREDITS", "QUOTE_EXCEEDS_MAX_CREDITS", "IDEMPOTENCY_KEY_REQUIRED", "IDEMPOTENCY_KEY_REUSED", "CONCURRENCY_LIMIT", "RATE_LIMITED", "TRIAL_CAP_EXCEEDED", "BUDGET_EXHAUSTED", "UPSTREAM_UNAVAILABLE", "PAYLOAD_TOO_LARGE", "INTERNAL"]; export type ErrorCode = (typeof ERROR_CODES)[number]; /** RFC 9457 problem+json body, as returned by the API on any non-2xx response. */ export interface VeezeeErrorShape { code: ErrorCode; /** Written as a corrective next-turn instruction, not a log line. */ message: string; param?: string; doc_url: string; is_retriable: boolean; retry_after_seconds?: number; valid_values?: string[]; claim_url?: string; /** Present on code KEY_REQUIRED: no key was resolvable for this call. POST here (no auth, no * body) to mint a free trial key, or run `vz init`. */ mint_url?: string; /** Present when a payment can fix this error; give this link to your human. */ upgrade_url?: string; /** Credits the failed call needs; set when a reserve fails on balance. */ credits_required?: number; /** Machine-readable purchase offer; travels with upgrade_url. */ offer?: OfferV1; } /** Machine-readable purchase offer attached to payment-fixable errors. */ export interface OfferV1 { offer_version: 1; reason: ErrorCode; currency: "usd"; /** Which pack to lead with. */ recommended?: "flex" | "production"; packs: Array<{ pack: "flex" | "production"; mode: "payment" | "subscription"; price_usd_cents: number; credits?: number; credits_per_month?: number; /** Short label for when this pack fits. */ when?: string; }>; rails: Array<"stripe_checkout">; /** Same account-bound capability as upgrade_url. */ checkout_url: string; /** How to resume the failed call after paying; truthful per code. */ resume: string; refund_policy: string; } export type Freshness = "recent" | "realtime"; export type ProfileSection = "about" | "experience" | "education" | "skills"; export interface ResolveUrlArgs { /** A LinkedIn URL, e.g. https://www.linkedin.com/in/williamhgates or .../company/microsoft. */ url: string; } export interface GetProfileArgs { /** Profile URL, slug (after /in/), or urn:li:fsd_profile URN. */ identifier: string; /** Extra profile sections. First 2 are included in the base price. Max 4. */ sections?: ProfileSection[]; freshness?: Freshness; /** Spend ceiling for this one call; rejected (uncharged) if the quote exceeds it. */ max_credits?: number; } export interface SearchPeopleArgs { /** Free-text query: a name, a title, or both. */ keywords?: string; first_name?: string; last_name?: string; /** Current job title filter. */ title?: string; school?: string; /** Company name, slug, numeric id, or urn:li:fsd_company URN. */ current_company?: string; /** Same accepted forms as current_company. */ past_company?: string; /** How many results to return. 1-30 (trial keys max 10). Default 10. */ limit?: number; /** Cursor from a previous page. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface GetCompanyArgs { /** Company URL, slug (after /company/), or website domain (e.g. 'microsoft.com'). */ identifier: string; freshness?: Freshness; max_credits?: number; } export interface GetPostsArgs { /** Person or company URL, slug, URN, or company website domain. */ identifier: string; /** Cursor from a previous page for older posts. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export type RedditSearchType = "posts" | "comments" | "subreddits" | "users"; export type RedditSearchSort = "relevance" | "top" | "new" | "hot" | "comment_count"; export type RedditRange = "past_hour" | "today" | "past_week" | "past_month" | "past_year" | "all_time"; export type RedditSubredditSort = "best" | "hot" | "new" | "top" | "controversial" | "rising"; export type RedditUserSection = "comments" | "posts" | "subreddits"; export type RedditPostDetail = "concise" | "full"; export type RedditThreadSort = "best" | "new" | "top" | "controversial" | "old" | "qa"; export interface RedditSearchArgs { /** Free-text keywords, e.g. 'self hosted photo backup'. Not a URL; use reddit.resolveUrl for URLs. */ query: string; /** What to search. 'comments' finds mentions inside discussions; 'subreddits' finds communities. Default 'posts'. */ type?: RedditSearchType; /** posts: any value; comments: relevance|top|new; invalid for subreddits and users. */ sort?: RedditSearchSort; /** Time window. posts only. */ range?: RedditRange; /** Cursor from a previous page. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface RedditGetSubredditArgs { /** Subreddit name without the r/ prefix, e.g. 'selfhosted'. Full URLs are accepted and cleaned. */ subreddit_name: string; /** Also return rules and moderators for +2 credits. Default false. */ include_settings?: boolean; freshness?: Freshness; max_credits?: number; } export interface RedditGetSubredditPostsArgs { /** Subreddit name without the r/ prefix, e.g. 'selfhosted'. */ subreddit_name: string; /** Defaults to the subreddit's front-page order. */ sort?: RedditSubredditSort; /** Time window for sort=top or controversial. */ range?: RedditRange; /** Keep the promoted ads Reddit splices into the feed (marked is_promoted). Default drops them. */ include_promoted?: boolean; /** Cursor from a previous page for older posts. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface RedditGetUserArgs { /** Reddit username without the u/ prefix, e.g. 'spez'. Full profile URLs are accepted and cleaned. */ username: string; /** Extra activity sections, 2 credits each (max 2 per call). */ sections?: RedditUserSection[]; freshness?: Freshness; max_credits?: number; } export interface RedditGetPostArgs { /** 1 to 100 post ids with the t3_ prefix, e.g. ["t3_1tbups6"]. */ post_ids: string[]; /** 'full' adds the discussion tree; only valid with exactly one id, +4 credits. Default 'concise'. */ detail?: RedditPostDetail; /** A t1_ comment id to fetch in context; only valid with exactly one post id. */ comment_id?: string; /** Discussion-tree order; only with detail 'full'. */ sort?: RedditThreadSort; /** comments_cursor from a previous detail='full' page. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface RedditResolveUrlArgs { /** A Reddit URL, e.g. https://www.reddit.com/r/selfhosted/comments/1tbups6/... or https://redd.it/1tbups6. */ url: string; } export type XSearchType = "recent" | "popular" | "people"; export type XIdentifierBy = "screen_name" | "id"; export type XTimelineMode = "posts" | "posts_and_replies" | "highlights"; export interface XSearchArgs { /** Free-text keywords; X advanced operators work, e.g. 'claude code from:AnthropicAI since:2026-06-01'. */ query: string; /** recent = chronological deep sweep; popular = top engagement; people = account search (single page). Default 'recent'. */ type?: XSearchType; /** Cursor from a previous page. Not valid with type 'people'. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface XGetProfileArgs { /** Screen name without the @ (e.g. 'nasa'), profile URL, or numeric account id. */ identifier: string; /** Force how identifier is interpreted; auto-detected when omitted. */ by?: XIdentifierBy; freshness?: Freshness; max_credits?: number; } export interface XGetTweetsArgs { /** Screen name without the @, profile URL, or numeric account id. */ identifier: string; /** Which timeline view to read. Default 'posts'. */ mode?: XTimelineMode; /** Set false to drop retweets from the page. Default true. */ include_retweets?: boolean; /** Cursor from a previous page for older tweets. */ cursor?: string; freshness?: Freshness; max_credits?: number; } export interface XGetTweetArgs { /** Numeric tweet id, e.g. '2054497961162478079', or a full tweet URL. */ tweet_id: string; freshness?: Freshness; max_credits?: number; } export interface XResolveUrlArgs { /** An X URL, e.g. https://x.com/nasa/status/2054497961162478079 or https://twitter.com/nasa. */ url: string; } export interface CheckoutArgs { pack: "flex" | "production"; } export interface FreshnessBlock { /** When the data was fetched from the source. ISO 8601. */ source_retrieved_at: string | null; served_at: string; cache_age_seconds: number | null; /** True when these bytes came from cache rather than a fetch made for this call. */ served_from_cache: boolean; freshness_requested: Freshness; freshness_served: Freshness | "stale"; } export interface UsageBlock { receipt_id: string | null; credits_quoted: number; credits_charged: number; balance_remaining: number | null; /** Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. */ free_tier_hint?: string; } export interface Location { /** Human-readable place, e.g. 'Seattle, Washington'. */ name: string | null; /** ISO 3166-1 alpha-2 when known. */ country_code: string | null; } interface EnvelopeBase { entity: Entity; /** The platform that produced this payload; null on account-level responses (get_usage). */ platform: string | null; canonical_url: string | null; data_as_of: string | null; schema_version: "2"; common: Common; platform_fields: PlatformFields; freshness: FreshnessBlock | null; usage: UsageBlock; } export interface MonthYear { month: number | null; year: number | null; } export interface CurrentPosition { company_name: string | null; /** LinkedIn company slug. */ company_handle: string | null; company_url: string | null; company_urn: string | null; start_year: number | null; } export interface ExperienceEntry { company: { name: string | null; handle: string | null; url: string | null; }; positions: Array<{ role: string | null; location: string | null; is_current: boolean | null; start_date: MonthYear | null; end_date: MonthYear | null; }>; } export interface EducationEntry { institution: string | null; institution_url: string | null; degree: string | null; start_year: number | null; end_year: number | null; } export interface Skill { name: string; endorsement_count: number | null; } export interface PersonCommon { full_name: string; first_name: string | null; last_name: string | null; headline: string | null; location: Location | null; /** Only present when the 'about' section was requested. */ about: string | null; current_position: CurrentPosition | null; /** Only present when the 'experience' section was requested. */ experience: ExperienceEntry[] | null; /** Only present when the 'education' section was requested. */ education: EducationEntry[] | null; /** Only present when the 'skills' section was requested. */ skills: Skill[] | null; followers: number | null; connections: number | null; is_verified: boolean | null; image_url: string | null; /** Canonical LinkedIn profile URL. */ url: string; } export interface PersonPlatformFields { /** Stable LinkedIn URN (urn:li:fsd_profile:...). Use this for repeat lookups. */ urn: string; /** Profile slug after /in/. */ public_identifier: string | null; is_influencer: boolean | null; is_creator: boolean | null; is_hiring: boolean | null; has_premium: boolean | null; open_to_messages: boolean | null; pronoun: string | null; } export type PersonEnvelope = EnvelopeBase<"person", PersonCommon, PersonPlatformFields>; export interface PersonSummary { name: string; position: string | null; location: string | null; followers: number | null; is_verified: boolean | null; image_url: string | null; url: string | null; urn: string; public_identifier: string | null; /** True when the profile is private: it exists but linkedin_get_profile cannot dereference it. Do not retry. */ is_anonymous: boolean; } export interface PeopleSearchCommon { results: PersonSummary[]; /** Pass back to fetch the next page. Null when exhausted. */ cursor: string | null; /** Ready-to-GET REST URL for the next page. */ next_url: string | null; total_matches: number | null; returned_count: number; /** Present when total_matches far exceeds returned results; says which filter to add. */ truncation_hint: string | null; } export type PeopleSearchEnvelope = EnvelopeBase<"people_search", PeopleSearchCommon, Record>; export interface CompanyCommon { name: string; description: string | null; website_url: string | null; industry: string[]; employee_count: number | null; employee_count_range: string | null; followers: number | null; founded_year: number | null; specialities: string[]; headquarters: Location | null; logo_url: string | null; /** Canonical LinkedIn company URL. */ url: string; } export interface CompanyPlatformFields { /** Stable LinkedIn URN (urn:li:fsd_company:...). */ urn: string; /** Numeric company id; accepted by search filters. */ linkedin_id: number | null; public_identifier: string | null; organization_type: string | null; stock_symbol: string | null; is_verified: boolean | null; } export type CompanyEnvelope = EnvelopeBase<"company", CompanyCommon, CompanyPlatformFields>; export interface Post { urn: string; url: string | null; text: string | null; /** ISO 8601. */ created_at: string | null; author: { name: string | null; url: string | null; urn: string | null; } | null; likes: number | null; comments_count: number | null; shares: number | null; is_repost: boolean | null; } export interface PostsCommon { results: Post[]; cursor: string | null; next_url: string | null; returned_count: number; /** What kind of entity the posts belong to. */ author_type: "person" | "company"; } export type PostsEnvelope = EnvelopeBase<"posts", PostsCommon, Record>; export interface UrlResolutionCommon { input_url: string; /** What the URL points at, in the platform's own vocabulary. */ type: "person" | "company" | "post" | "subreddit" | "user" | "comment" | "profile" | "tweet"; /** Stable platform id (URN, t3_/t1_ id, or numeric id) when resolvable. */ id: string | null; /** Human-readable slug or handle when present in the URL. */ handle: string | null; canonical_url: string | null; } export type UrlResolutionEnvelope = EnvelopeBase<"url_resolution", UrlResolutionCommon, Record>; export interface SubredditRef { /** Subreddit name without the r/ prefix, e.g. 'selfhosted'. */ name: string; subscribers: number | null; } export interface RedditPost { /** Post id with the t3_ prefix. Pass to reddit.getPost. */ id: string; title: string | null; /** Username without the u/ prefix. */ author: string | null; subreddit: SubredditRef | null; /** ISO 8601. */ created_at: string | null; upvotes: number | null; upvote_ratio: number | null; comment_count: number | null; /** Canonical reddit.com URL. */ permalink: string | null; /** The linked page for link posts; null for self posts. */ external_url: string | null; /** Start of the post body; the full body comes from reddit.getPost. */ preview_text: string | null; flair: string | null; media_type: string | null; } export interface RedditComment { /** Comment id with the t1_ prefix. */ id: string; author: string | null; /** Comment text (markdown as written). */ content: string | null; created_at: string | null; upvotes: number | null; permalink: string | null; /** t1_ id of the parent comment, or t3_ id when top-level. */ parent_id: string | null; /** 0 = top-level. Only set inside a discussion tree. */ depth: number | null; /** The post this comment belongs to. Only set outside a discussion tree (search, user history). */ post: { id: string | null; title: string | null; subreddit: SubredditRef | null; } | null; } export interface RedditUserSummary { username: string; created_at: string | null; karma: number | null; profile_url: string | null; } export interface SubredditCommon { name: string; title: string | null; description: string | null; subscribers: number | null; active_users: number | null; created_at: string | null; is_nsfw: boolean | null; topics: string[]; /** Canonical reddit.com URL for the subreddit. */ url: string; /** Only present when include_settings was requested. */ rules: Array<{ name: string | null; description: string | null; }> | null; /** Only present when include_settings was requested. */ moderators: string[] | null; } export type SubredditEnvelope = EnvelopeBase<"subreddit", SubredditCommon, Record>; export interface RedditUserCommon { username: string; created_at: string | null; karma: number | null; followers: number | null; is_verified: boolean | null; description: string | null; account_type: string | null; /** Canonical reddit.com URL for the user. */ url: string; /** Only present when the 'comments' section was requested (most recent first). */ comments: RedditComment[] | null; /** Only present when the 'posts' section was requested. */ posts: RedditPost[] | null; /** Only present when the 'subreddits' section was requested: where this user is active. */ subreddits: SubredditRef[] | null; } export type RedditUserEnvelope = EnvelopeBase<"reddit_user", RedditUserCommon, Record>; export interface RedditPostsCommon { results: RedditPost[]; /** Pass back to fetch the next page. Null when exhausted. */ cursor: string | null; /** Ready-to-GET REST URL for the next page. */ next_url: string | null; returned_count: number; } export type RedditPostsEnvelope = EnvelopeBase<"reddit_posts", RedditPostsCommon, Record>; export interface RedditThreadPost extends RedditPost { /** Full post body (markdown). Null for link posts. */ content: string | null; } export interface RedditThreadCommon { posts: RedditThreadPost[]; /** The discussion tree, flattened in tree order with depth set. Only present with detail: 'full' or comment_id. */ comments: RedditComment[] | null; /** Pass back as cursor to continue the discussion tree. */ comments_cursor: string | null; returned_count: number; } export type RedditThreadEnvelope = EnvelopeBase<"reddit_thread", RedditThreadCommon, Record>; export interface RedditSearchSubredditHit { name: string; description: string | null; subscribers: number | null; } export interface RedditSearchCommon { /** Which result array is populated. */ type: RedditSearchType; posts: RedditPost[] | null; comments: RedditComment[] | null; subreddits: RedditSearchSubredditHit[] | null; users: RedditUserSummary[] | null; /** Pass back to fetch the next page. Null when exhausted. */ cursor: string | null; next_url: string | null; returned_count: number; /** Present when results were cut off; says how to narrow or continue. */ truncation_hint: string | null; } export type RedditSearchEnvelope = EnvelopeBase<"reddit_search", RedditSearchCommon, Record>; export interface XAuthor { /** Handle without the @, e.g. 'nasa'. */ screen_name: string | null; name: string | null; /** Numeric account id as a string; stable across handle changes. */ id: string | null; followers: number | null; /** Blue-check state. */ is_verified: boolean | null; } export interface XTweet { /** Numeric tweet id as a string. Pass to x.getTweet. */ id: string; text: string | null; author: XAuthor | null; /** ISO 8601. */ created_at: string | null; /** Canonical x.com URL. */ url: string | null; views: number | null; likes: number | null; retweets: number | null; replies: number | null; quotes: number | null; bookmarks: number | null; lang: string | null; is_reply: boolean | null; is_retweet: boolean | null; is_quote: boolean | null; in_reply_to_screen_name: string | null; /** Thread root tweet id; equal to id for thread starters. */ conversation_id: string | null; possibly_sensitive: boolean | null; } export interface XProfileCommon { screen_name: string; name: string | null; description: string | null; location: string | null; /** The link in the profile bio, not the x.com URL. */ website_url: string | null; created_at: string | null; followers: number | null; following: number | null; tweets_count: number | null; media_count: number | null; /** Blue-check state. */ is_verified: boolean | null; /** e.g. 'Business' or 'Government' when applicable. */ verified_type: string | null; /** True when tweets are visible to approved followers only. */ is_protected: boolean | null; image_url: string | null; banner_url: string | null; /** Canonical x.com profile URL. */ url: string; } export interface XProfilePlatformFields { /** Numeric account id as a string; stable across handle changes. Use for repeat lookups. */ id: string; pinned_tweet_ids: string[] | null; is_business_account: boolean | null; } export type XProfileEnvelope = EnvelopeBase<"x_profile", XProfileCommon, XProfilePlatformFields>; export interface XTweetsCommon { results: XTweet[]; /** Pass back to fetch the next page. Null when exhausted. */ cursor: string | null; /** Ready-to-GET REST URL for the next page. */ next_url: string | null; returned_count: number; } export type XTweetsEnvelope = EnvelopeBase<"x_tweets", XTweetsCommon, Record>; export interface XTweetDetail extends XTweet { /** The tweet this one quotes, when is_quote. */ quoted_tweet: XTweet | null; } export type XTweetEnvelope = EnvelopeBase<"x_tweet", XTweetDetail, Record>; export interface XPersonHit extends XAuthor { description: string | null; location: string | null; } export interface XSearchCommon { /** Which result array is populated. */ type: XSearchType; tweets: XTweet[] | null; people: XPersonHit[] | null; /** Pass back to fetch the next page. Null when exhausted or for type 'people' (single page). */ cursor: string | null; next_url: string | null; returned_count: number; /** Present when results were cut off; says how to narrow or continue. */ truncation_hint: string | null; } export type XSearchEnvelope = EnvelopeBase<"x_search", XSearchCommon, Record>; export interface ReceiptSummary { receipt_id: string; tool: string; credits_charged: number; created_at: string; } export interface UsageCommon { plan: "trial" | "payg" | "flex" | "production"; /** Platforms this account's key may call. Grants are explicit; write to hello@veezee.io to enable more. */ platforms: string[]; balance_remaining: number; realtime_ops_used: number; /** Null means unlimited (paid plans). */ realtime_ops_limit: number | null; concurrent_limit: number; /** Up to the last 10 charges. */ recent_receipts: ReceiptSummary[]; /** Present on trial accounts: open to attach an email so the account can be recovered if the key is lost. */ claim_url: string | null; /** Give this link to your human to add credits or upgrade; purchases credit THIS account with no login. */ upgrade_url: string; /** Give this link to your human to change or cancel a paid plan in the Stripe billing portal. Valid at least 24 hours; call get_usage again for a fresh one. */ manage_url: string; } export type UsageEnvelope = EnvelopeBase<"usage", UsageCommon, Record>; export interface CheckoutResult { checkout_url: string; } export interface MintKeyFreeTier { credits_per_ip_day: number; freshness: Freshness; /** True when list/search endpoints return only their first page on this key. */ first_page_only: boolean; } export interface MintKeySetup { /** Shell line to export the key as VEEZEE_API_KEY. */ env: string; rest: string; mcp: { url: string; headers: Record; }; } /** POST /v1/keys/mint response body. Mints a free zero-allowance trial key with no auth and * no body; see client.mintKey() and client.mint(). */ export interface MintKeyResult { key: string; /** Masked display form, e.g. "vz_trial_...ab12". Safe to print or log; the raw key is not. */ key_hint: string; account_id: string; plan: "trial"; free_tier: MintKeyFreeTier; upgrade_url: string; setup: MintKeySetup; note: string; docs: string; } /** Result of client.mint(): ensures the client has a usable key without ever exposing the * raw key to the caller beyond what request() needs internally for the Authorization header. */ export interface MintResult { key_hint: string; account_id?: string; upgrade_url?: string; /** True only when this call minted a fresh key; false when an existing key was reused. */ created: boolean; source: "explicit" | "env" | "config" | "minted"; /** Set when ~/.veezee/config could not be written (non-Node runtime, or a write error): the * minted key lives only in this client instance's memory and is lost when it is discarded. */ warning?: string; } export interface KeySummary { id: string; scope: string; label: string | null; /** Masked display form, e.g. "vz_live_...ab12". The raw secret is never returned here. */ key_hint: string | null; created_at: number; } /** GET /v1/keys response body. */ export interface KeysListResult { account_id: string; keys: KeySummary[]; } /** POST /v1/keys response body. api_key is shown once here; store it immediately. */ export interface CreateKeyResult { account_id: string; key_id: string; label: string | null; api_key: string; } /** POST /v1/keys/revoke response body. */ export interface RevokeKeyResult { account_id: string; key_id: string; revoked: true; } /** POST /v1/keys/rotate response body. api_key is shown once here; store it immediately. */ export interface RotateKeyResult { account_id: string; key_id: string; api_key: string; } /** POST /v1/alert response body. */ export interface SetBalanceAlertResult { account_id: string; alert_threshold: number | null; } /** POST /v1/device/code response body. */ export interface DeviceCodeResult { device_code: string; user_code: string; verification_uri: string; /** Seconds until device_code expires. */ expires_in: number; /** Minimum seconds to wait between poll attempts. */ interval: number; } /** POST /v1/device/token response body: "pending" until the human finishes verification in a * browser, then "complete" with the management token. */ export type DeviceTokenResult = { status: "pending"; interval: number; } | { status: "complete"; token: string; expires_at: number; email: string; }; export {};