# Veezee full docs LinkedIn, Reddit, and X (formerly Twitter) data for AI agents. No signup: your agent mints its own free key in one call (POST https://api.veezee.io/v1/keys/mint, no body), then the first data call returns data. An un-keyed call returns a machine-readable KEY_REQUIRED error carrying that same recipe. Paying is the only human step in the product. --- ## Error reference Every tool below returns this same set of error codes. REST returns `application/problem+json`; MCP returns the same content as an error result. `message` is written as the next-turn instruction. | Code | HTTP status | Retriable | Meaning | | --- | --- | --- | --- | | `INVALID_INPUT` | 400 | no | A parameter failed validation. Check param and message for what to fix. | | `NOT_FOUND` | 404 | no | Nothing matches the given identifier or URL. | | `UNAUTHORIZED` | 401 | no | Invalid, revoked, or unusable API key. | | `NOT_ENTITLED` | 403 | no | This account is not enabled for the platform you called. | | `INSUFFICIENT_CREDITS` | 402 | no | Your balance can't cover this call's quote. Check get_usage or add credits. | | `QUOTE_EXCEEDS_MAX_CREDITS` | 402 | no | The call's quote is higher than the max_credits you set. Nothing was charged. | | `IDEMPOTENCY_KEY_REQUIRED` | 400 | no | This is a metered call; send an Idempotency-Key header. | | `IDEMPOTENCY_KEY_REUSED` | 409 | no | That Idempotency-Key was already used with different arguments. Use a new key for a new call. | | `CONCURRENCY_LIMIT` | 429 | yes | Too many calls in flight for this key's plan. Wait for one to finish. | | `RATE_LIMITED` | 429 | yes | Too many calls per minute for this key's plan. Back off and retry. | | `TRIAL_CAP_EXCEEDED` | 403 | no | A trial-only limit was hit (concurrency, rate, search size, or realtime fetches). | | `BUDGET_EXHAUSTED` | 503 | no | A configured spend budget has been used up. | | `UPSTREAM_UNAVAILABLE` | 502 | yes | LinkedIn data wasn't reachable. Safe to retry. | | `PAYLOAD_TOO_LARGE` | 413 | no | The request or response exceeded the size limit. | | `INTERNAL` | 500 | yes | Something failed on our side. Safe to retry. | | `AUTH_REQUIRED` | 401 | no | | | `KEY_REQUIRED` | 401 | no | No API key was sent. Mint one free at POST /v1/keys/mint and retry. | Errors a payment can fix add fields to this shape. INSUFFICIENT_CREDITS, TRIAL_CAP_EXCEEDED, and BUDGET_EXHAUSTED carry `upgrade_url` (give it to your human) and `offer`, its machine-readable twin; RATE_LIMITED and CONCURRENCY_LIMIT carry both on trial accounts only, where a paid plan raises the limit. `offer` holds `offer_version` (1), `reason` (the error code), `currency` ("usd"), `recommended` (which pack to lead with, currently `flex`), `packs` (pack, mode, price_usd_cents, credits or credits_per_month, and `when`, a short label for when that pack fits), `rails` (currently `stripe_checkout`), `checkout_url` (the same account-bound link as `upgrade_url`), `resume`, and `refund_policy`. Follow `offer.resume` after payment: INSUFFICIENT_CREDITS retries the same call with the same Idempotency-Key; TRIAL_CAP_EXCEEDED and BUDGET_EXHAUSTED retry with a fresh key; the two limit codes clear on their own with back-off, payment only raises the limit. INSUFFICIENT_CREDITS also sets `credits_required`: the credits the failed call needed. The failed attempt charged nothing. --- ## MCP call shape Every MCP tool call takes this envelope; only `name` and `arguments` change per tool: ```json { "method": "tools/call", "params": { "name": "", "arguments": { ... } } } ``` --- # Docs - Veezee Everything to call Veezee's LinkedIn, Reddit, and X tools over MCP or REST. ## Index - Connect your client (verified install snippets per MCP host): https://veezee.io/docs/clients - Platforms: https://veezee.io/docs/linkedin, https://veezee.io/docs/reddit, https://veezee.io/docs/x - Field reference: https://veezee.io/docs/fields - Auth reference: https://veezee.io/auth.md - Error reference: https://veezee.io/docs/errors - OpenAPI: https://veezee.io/openapi.json - SDK: https://veezee.io/docs/sdk - CLI: https://veezee.io/docs/cli - Agent skills: https://veezee.io/docs/skills - Pricing: https://veezee.io/pricing - AGENTS.md: https://veezee.io/AGENTS.md ## Getting started Fastest path: fetch https://veezee.io/agent-setup/prompt.md and follow the setup instructions. The steps below are the same setup inline. ### 1. Mint a free key ``` curl -s -X POST https://api.veezee.io/v1/keys/mint ``` No signup, no card, no human: one call returns a key, shown once, plus ready-made setup snippets. The CLI does this for you (`npx @veezee/sdk init`) and stores the key in `~/.veezee/config`. ### 2. Call the API ``` curl "https://api.veezee.io/v1/linkedin/profiles?identifier=williamhgates" \ -H "Authorization: Bearer $VEEZEE_API_KEY" ``` The free key runs under a shared budget of 200 credits per IP per day, recent data only, no realtime, no `Idempotency-Key` needed. Call without a key and the response is a machine-readable `KEY_REQUIRED` error carrying this exact recipe, so any agent self-heals in one round-trip. ### 3. Or connect over MCP ``` https://mcp.veezee.io/linkedin ``` transport: streamable-http, same free budget as REST. Claude Code, claude.ai, and other clients that support the MCP authorization spec open a browser sign-in automatically (email code, no password, no card, no key to copy). Other clients: put the key from step 1 in your MCP client's connection headers. ### 4. Hit the daily cap? Buy credits The error names `upgrade_url`: https://veezee.io/upgrade. Pick a pack and pay: checkout credits the same key, nothing to reconfigure. Send it as `Authorization: Bearer ` on every REST call (plus an `Idempotency-Key` header on metered routes), or in your MCP client's connection headers. That checkout is the only human step in the product. Default path: use MCP when your host supports it, the SDK otherwise, REST as the fallback; the CLI and skills are conveniences layered on top of those. ## Platforms - [LinkedIn](https://veezee.io/docs/linkedin): Structured people and company data for outreach, recruiting, and research. - [Reddit](https://veezee.io/docs/reddit): Discussions and comment-level sentiment: what people actually say about a product, problem, or brand, straight from the comments. - [X (formerly Twitter)](https://veezee.io/docs/x): Volume and recency: a deep chronological sweep across the whole platform, not just one community. ## Tools - **linkedin_resolve_url** (2 credits): Identify a LinkedIn URL. [/docs/tools/linkedin_resolve_url](https://veezee.io/docs/tools/linkedin_resolve_url) - **linkedin_get_profile** (4 credits): Get a LinkedIn person profile. [/docs/tools/linkedin_get_profile](https://veezee.io/docs/tools/linkedin_get_profile) - **linkedin_search_people** (10 credits): Search people on LinkedIn. [/docs/tools/linkedin_search_people](https://veezee.io/docs/tools/linkedin_search_people) - **linkedin_get_company** (4 credits): Get a LinkedIn company. [/docs/tools/linkedin_get_company](https://veezee.io/docs/tools/linkedin_get_company) - **linkedin_get_posts** (4 credits): Get recent posts by a person or company. [/docs/tools/linkedin_get_posts](https://veezee.io/docs/tools/linkedin_get_posts) - **reddit_search** (6 credits): Search Reddit posts, comments, subreddits, or users. [/docs/tools/reddit_search](https://veezee.io/docs/tools/reddit_search) - **reddit_get_subreddit** (4 credits): Get subreddit details. [/docs/tools/reddit_get_subreddit](https://veezee.io/docs/tools/reddit_get_subreddit) - **reddit_get_subreddit_posts** (4 credits): Get a subreddit's posts. [/docs/tools/reddit_get_subreddit_posts](https://veezee.io/docs/tools/reddit_get_subreddit_posts) - **reddit_get_user** (4 credits): Get a Reddit user. [/docs/tools/reddit_get_user](https://veezee.io/docs/tools/reddit_get_user) - **reddit_get_post** (4 credits): Get Reddit posts by id, with optional discussion thread. [/docs/tools/reddit_get_post](https://veezee.io/docs/tools/reddit_get_post) - **reddit_resolve_url** (2 credits): Identify a Reddit URL. [/docs/tools/reddit_resolve_url](https://veezee.io/docs/tools/reddit_resolve_url) - **x_search** (6 credits): Search X (formerly Twitter). [/docs/tools/x_search](https://veezee.io/docs/tools/x_search) - **x_get_profile** (4 credits): Get an X profile. [/docs/tools/x_get_profile](https://veezee.io/docs/tools/x_get_profile) - **x_get_tweets** (4 credits): Get an account's tweets. [/docs/tools/x_get_tweets](https://veezee.io/docs/tools/x_get_tweets) - **x_get_tweet** (4 credits): Get one tweet with full metrics. [/docs/tools/x_get_tweet](https://veezee.io/docs/tools/x_get_tweet) - **x_resolve_url** (2 credits): Identify an X URL. [/docs/tools/x_resolve_url](https://veezee.io/docs/tools/x_resolve_url) - **get_usage** (0 credits): Check credits and recent charges. [/docs/tools/get_usage](https://veezee.io/docs/tools/get_usage) ## Reference - Connect your client (verified install snippets per MCP host): https://veezee.io/docs/clients - Use cases (candidate sourcing, prospect enrichment, company research, brand monitoring, market research): https://veezee.io/use-cases/candidate-sourcing - Field reference (every field Veezee actually serves, by entity): https://veezee.io/docs/fields - Auth reference (every REST or CLI call needs a key, minted free; MCP clients that support the authorization spec sign in over the browser instead): https://veezee.io/auth.md - Error reference (every error code, when it happens, and how to recover): https://veezee.io/docs/errors - OpenAPI (the machine-readable REST contract): https://veezee.io/openapi.json - SDK (npm install @veezee/sdk, typed TypeScript client): https://veezee.io/docs/sdk - CLI (the veezee command, every tool as a subcommand): https://veezee.io/docs/cli - Agent skills (installable SKILL.md packs for recurring jobs): https://veezee.io/docs/skills - Pricing + cost examples: https://veezee.io/pricing - AGENTS.md (non-obvious rules for agents calling Veezee): https://veezee.io/AGENTS.md --- # LinkedIn - Veezee docs Structured people and company data for outreach, recruiting, and research. ## Tools - **linkedin_resolve_url** (2 credits): Identify a LinkedIn URL. [/docs/tools/linkedin_resolve_url](https://veezee.io/docs/tools/linkedin_resolve_url) - **linkedin_get_profile** (4 credits): Get a LinkedIn person profile. [/docs/tools/linkedin_get_profile](https://veezee.io/docs/tools/linkedin_get_profile) - **linkedin_search_people** (10 credits): Search people on LinkedIn. [/docs/tools/linkedin_search_people](https://veezee.io/docs/tools/linkedin_search_people) - **linkedin_get_company** (4 credits): Get a LinkedIn company. [/docs/tools/linkedin_get_company](https://veezee.io/docs/tools/linkedin_get_company) - **linkedin_get_posts** (4 credits): Get recent posts by a person or company. [/docs/tools/linkedin_get_posts](https://veezee.io/docs/tools/linkedin_get_posts) `get_usage` checks balance and works the same way across every platform: free, 0 credits. https://veezee.io/docs/tools/get_usage ## Quickstart ### 1. Mint a free key ``` curl -s -X POST https://api.veezee.io/v1/keys/mint ``` No signup, no card, no human: one call returns a key, shown once, plus ready-made setup snippets. The CLI does this for you (`npx @veezee/sdk init`) and stores the key in `~/.veezee/config`. ### 2. Call the API ``` curl "https://api.veezee.io/v1/linkedin/profiles?identifier=williamhgates" \ -H "Authorization: Bearer $VEEZEE_API_KEY" ``` The free key runs under a shared budget of 200 credits per IP per day, recent data only, no realtime, no `Idempotency-Key` needed. Call without a key and the response is a machine-readable `KEY_REQUIRED` error carrying this exact recipe, so any agent self-heals in one round-trip. ### 3. Or connect over MCP ``` https://mcp.veezee.io/linkedin ``` transport: streamable-http, same free budget as REST. Claude Code, claude.ai, and other clients that support the MCP authorization spec open a browser sign-in automatically (email code, no password, no card, no key to copy). Other clients: put the key from step 1 in your MCP client's connection headers. ### 4. Hit the daily cap? Buy credits The error names `upgrade_url`: https://veezee.io/upgrade. Pick a pack and pay: checkout credits the same key, nothing to reconfigure. Send it as `Authorization: Bearer ` on every REST call (plus an `Idempotency-Key` header on metered routes), or in your MCP client's connection headers. That checkout is the only human step in the product. ## What comes back [url_resolution](https://veezee.io/docs/fields#url_resolution), [person](https://veezee.io/docs/fields#person), [people_search](https://veezee.io/docs/fields#people_search), [company](https://veezee.io/docs/fields#company), [posts](https://veezee.io/docs/fields#posts). Full field lists: https://veezee.io/docs/fields ## Limits - Every tool is read-only: no posting, commenting, or messaging. - No contact details: no email addresses or phone numbers. - No company search by name: linkedin_get_company takes a URL, slug, or domain; resolve a name with linkedin_search_people's current_company filter instead. - No keyword search across LinkedIn posts: linkedin_get_posts returns one entity's recent posts, not a search. Other platforms: [Reddit](https://veezee.io/docs/reddit), [X (formerly Twitter)](https://veezee.io/docs/x). LinkedIn API for AI agents: https://veezee.io/linkedin-api-for-ai-agents Full tool reference: https://veezee.io/docs --- # Reddit - Veezee docs Discussions and comment-level sentiment: what people actually say about a product, problem, or brand, straight from the comments. ## Tools - **reddit_search** (6 credits): Search Reddit posts, comments, subreddits, or users. [/docs/tools/reddit_search](https://veezee.io/docs/tools/reddit_search) - **reddit_get_subreddit** (4 credits): Get subreddit details. [/docs/tools/reddit_get_subreddit](https://veezee.io/docs/tools/reddit_get_subreddit) - **reddit_get_subreddit_posts** (4 credits): Get a subreddit's posts. [/docs/tools/reddit_get_subreddit_posts](https://veezee.io/docs/tools/reddit_get_subreddit_posts) - **reddit_get_user** (4 credits): Get a Reddit user. [/docs/tools/reddit_get_user](https://veezee.io/docs/tools/reddit_get_user) - **reddit_get_post** (4 credits): Get Reddit posts by id, with optional discussion thread. [/docs/tools/reddit_get_post](https://veezee.io/docs/tools/reddit_get_post) - **reddit_resolve_url** (2 credits): Identify a Reddit URL. [/docs/tools/reddit_resolve_url](https://veezee.io/docs/tools/reddit_resolve_url) `get_usage` checks balance and works the same way across every platform: free, 0 credits. https://veezee.io/docs/tools/get_usage ## Quickstart ### 1. Mint a free key ``` curl -s -X POST https://api.veezee.io/v1/keys/mint ``` No signup, no card, no human: one call returns a key, shown once, plus ready-made setup snippets. The CLI does this for you (`npx @veezee/sdk init`) and stores the key in `~/.veezee/config`. ### 2. Call the API ``` curl "https://api.veezee.io/v1/reddit/subreddits?subreddit_name=selfhosted" \ -H "Authorization: Bearer $VEEZEE_API_KEY" ``` The free key runs under a shared budget of 200 credits per IP per day, recent data only, no realtime, no `Idempotency-Key` needed. Call without a key and the response is a machine-readable `KEY_REQUIRED` error carrying this exact recipe, so any agent self-heals in one round-trip. ### 3. Or connect over MCP ``` https://mcp.veezee.io/reddit ``` transport: streamable-http, same free budget as REST. Claude Code, claude.ai, and other clients that support the MCP authorization spec open a browser sign-in automatically (email code, no password, no card, no key to copy). Other clients: put the key from step 1 in your MCP client's connection headers. ### 4. Hit the daily cap? Buy credits The error names `upgrade_url`: https://veezee.io/upgrade. Pick a pack and pay: checkout credits the same key, nothing to reconfigure. Send it as `Authorization: Bearer ` on every REST call (plus an `Idempotency-Key` header on metered routes), or in your MCP client's connection headers. That checkout is the only human step in the product. ## What comes back [reddit_search](https://veezee.io/docs/fields#reddit_search), [subreddit](https://veezee.io/docs/fields#subreddit), [reddit_posts](https://veezee.io/docs/fields#reddit_posts), [reddit_user](https://veezee.io/docs/fields#reddit_user), [reddit_thread](https://veezee.io/docs/fields#reddit_thread), [url_resolution](https://veezee.io/docs/fields#url_resolution). Full field lists: https://veezee.io/docs/fields ## Limits - No server-side time window on comment search: filter results on created_at yourself, and poll with sort=new for monitoring. - Discover result depth caps around a few hundred results per query; decompose a broad topic into several narrower queries instead of one wide one. - Cached search results refresh on a 20-minute cycle: polling faster than that just replays the same page. Other platforms: [LinkedIn](https://veezee.io/docs/linkedin), [X (formerly Twitter)](https://veezee.io/docs/x). Reddit API for AI agents: https://veezee.io/reddit-api-for-ai-agents Full tool reference: https://veezee.io/docs --- # X (formerly Twitter) - Veezee docs Volume and recency: a deep chronological sweep across the whole platform, not just one community. ## Tools - **x_search** (6 credits): Search X (formerly Twitter). [/docs/tools/x_search](https://veezee.io/docs/tools/x_search) - **x_get_profile** (4 credits): Get an X profile. [/docs/tools/x_get_profile](https://veezee.io/docs/tools/x_get_profile) - **x_get_tweets** (4 credits): Get an account's tweets. [/docs/tools/x_get_tweets](https://veezee.io/docs/tools/x_get_tweets) - **x_get_tweet** (4 credits): Get one tweet with full metrics. [/docs/tools/x_get_tweet](https://veezee.io/docs/tools/x_get_tweet) - **x_resolve_url** (2 credits): Identify an X URL. [/docs/tools/x_resolve_url](https://veezee.io/docs/tools/x_resolve_url) `get_usage` checks balance and works the same way across every platform: free, 0 credits. https://veezee.io/docs/tools/get_usage ## Quickstart ### 1. Mint a free key ``` curl -s -X POST https://api.veezee.io/v1/keys/mint ``` No signup, no card, no human: one call returns a key, shown once, plus ready-made setup snippets. The CLI does this for you (`npx @veezee/sdk init`) and stores the key in `~/.veezee/config`. ### 2. Call the API ``` curl "https://api.veezee.io/v1/x/profiles?identifier=nasa" \ -H "Authorization: Bearer $VEEZEE_API_KEY" ``` The free key runs under a shared budget of 200 credits per IP per day, recent data only, no realtime, no `Idempotency-Key` needed. Call without a key and the response is a machine-readable `KEY_REQUIRED` error carrying this exact recipe, so any agent self-heals in one round-trip. ### 3. Or connect over MCP ``` https://mcp.veezee.io/x ``` transport: streamable-http, same free budget as REST. Claude Code, claude.ai, and other clients that support the MCP authorization spec open a browser sign-in automatically (email code, no password, no card, no key to copy). Other clients: put the key from step 1 in your MCP client's connection headers. ### 4. Hit the daily cap? Buy credits The error names `upgrade_url`: https://veezee.io/upgrade. Pick a pack and pay: checkout credits the same key, nothing to reconfigure. Send it as `Authorization: Bearer ` on every REST call (plus an `Idempotency-Key` header on metered routes), or in your MCP client's connection headers. That checkout is the only human step in the product. ## What comes back [x_search](https://veezee.io/docs/fields#x_search), [x_profile](https://veezee.io/docs/fields#x_profile), [x_tweets](https://veezee.io/docs/fields#x_tweets), [x_tweet](https://veezee.io/docs/fields#x_tweet), [url_resolution](https://veezee.io/docs/fields#url_resolution). Full field lists: https://veezee.io/docs/fields ## Limits - No batch tweet lookup: x_get_tweet fetches one tweet at a time. - t.co links cannot be resolved offline: x_resolve_url returns INVALID_INPUT for them; expand them in a browser step first. - People search returns a single page: x_search type=people has no cursor. Other platforms: [LinkedIn](https://veezee.io/docs/linkedin), [Reddit](https://veezee.io/docs/reddit). X (formerly Twitter) API for AI agents: https://veezee.io/x-api-for-ai-agents Full tool reference: https://veezee.io/docs --- ## linkedin_resolve_url Identify what a LinkedIn URL points at before fetching it. Give any LinkedIn profile, company, or post URL (utm params, www/m subdomains, trailing slashes are fine); get back {type: person|company|post, id, handle, canonical_url}. For profile URLs, id is the stable person URN; for company URLs, id is the stable company URN; for post URLs, id is the activity URN extracted from the URL. For people, use the returned handle or id with linkedin_get_profile or linkedin_get_posts. For companies, use the returned HANDLE with linkedin_get_company or linkedin_get_posts; the company URN/id is a linkedin_search_people filter input, not a fetch identifier. Costs 2 credits. Skip this tool when you already have a slug, URN, or clean URL: linkedin_get_profile and linkedin_get_company accept those directly, so resolving first would waste 2 credits. Not for non-LinkedIn URLs; it returns INVALID_INPUT for those. Credits: 2. REST: `GET /v1/linkedin/resolve-url` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `url` | yes | `string` | A LinkedIn URL, e.g. https://www.linkedin.com/in/williamhgates or .../company/microsoft. | ### Example ```json { "url": "https://www.linkedin.com/in/williamhgates?utm_source=share" } ``` Output: returns a `url_resolution` envelope. Full field list: https://veezee.io/docs/fields#url_resolution --- ## linkedin_get_profile Fetch one person's LinkedIn profile. identifier accepts a profile URL, the slug after /in/ (e.g. 'williamhgates'), or a urn:li:fsd_profile URN; URLs are cleaned automatically. Always returns the overview (name, headline, location, current position, follower counts) plus up to 2 requested sections from about|experience|education|skills at no extra cost; each section beyond 2 adds 2 credits (max 4 sections). Costs 4 credits base. If you only have a name, use linkedin_search_people first; this tool does not search. Results from linkedin_search_people with is_anonymous=true cannot be fetched here; treat them as 'someone matching this exists' and stop. Companies belong to linkedin_get_company. Credits: 4. REST: `GET /v1/linkedin/profiles` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `identifier` | yes | `string` | Profile URL, slug (after /in/), or urn:li:fsd_profile URN. | | `sections` | no | `array` | Extra profile sections. First 2 are included in the base price. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "identifier": "williamhgates" } ``` Output: returns a `person` envelope. Full field list: https://veezee.io/docs/fields#person --- ## linkedin_search_people Find people on LinkedIn by keywords and filters. The right tool when you have a name, role, or 'who is the X at Y' question without a profile URL. Pass keywords (free text: name, title, or both) and any of first_name, last_name, title, school, current_company, past_company. If keywords is omitted it is derived from the name or title filters; school or company filters alone are rejected with INVALID_INPUT, so include keywords with those. Company filters accept a company name, slug, numeric id, or URN; names are resolved for you. Costs 10 credits including the first 10 results; each further 10 results add 1 credit (limit max 30; trial keys max 10). A cursor page is a NEW call priced the same way by its own limit, so one limit=30 call is much cheaper than three limit=10 pages; prefer a larger limit over paginating. Do NOT combine a company NAME filter with limit=30: name resolution spends one of the call's three internal fetches, so that combination is rejected. With a company name keep limit<=20; for limit=30 pass the company's numeric id or URN (linkedin_get_company returns both). Returns name, position, location, urn, public_identifier per result, a cursor for the next page, and total_matches. Results with is_anonymous=true are private profiles; do not pass them to linkedin_get_profile. For one known person with a URL/slug, call linkedin_get_profile directly instead. Credits: 10. REST: `GET /v1/linkedin/search` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `keywords` | no | `string` | Free-text query: a name, a title, or both. | | `first_name` | no | `string` | First-name filter, exact match. | | `last_name` | no | `string` | Last-name filter, exact match. | | `title` | no | `string` | Current job title filter. | | `school` | no | `string` | School or university name filter. | | `current_company` | no | `string` | Company name, slug, numeric id, or urn:li:fsd_company URN. | | `past_company` | no | `string` | Same accepted forms as current_company. | | `limit` | no | `integer` | How many results to return. | | `cursor` | no | `string` | Cursor from a previous page. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "keywords": "CTO", "current_company": "anthropic" } ``` Output: returns a `people_search` envelope. Full field list: https://veezee.io/docs/fields#people_search --- ## linkedin_get_company Fetch one company's LinkedIn page: name, description, industry, employee count, headquarters, website, founding year, specialities, and the URN/numeric id you need for linkedin_search_people company filters. identifier accepts a company URL, the slug after /company/ (e.g. 'microsoft'), or a website domain like 'microsoft.com'; numeric ids and URNs are search-filter inputs, not fetch identifiers. Domains are resolved to a company and verified against that company's website: a domain identifier always QUOTES base+4 credits (set max_credits accordingly), and the 4-credit resolution surcharge is refunded at settlement when the domain was resolved before, so known domains settle at the base price. A domain that cannot be verified to a company returns INVALID_INPUT with the closest matches instead of a guessed company. Costs 4 credits base. Do not guess a slug from a brand name: slugs are vanity strings and a famous name can belong to an unrelated company's page (linkedin.com/company/anthropic is a small investment fund, not the AI lab). When you only know the company's name, pass its website domain instead -- the verified form -- and sanity-check the returned industry and description against what you expected. This tool does not search by name: if you only have an approximate company name, use linkedin_search_people's current_company filter with keywords (the filter resolves names) or give the exact slug. For the company's posts, use linkedin_get_posts with the same identifier (URL, slug, or website domain all work there too). Credits: 4. REST: `GET /v1/linkedin/companies` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `identifier` | yes | `string` | Company URL, slug (after /company/), or website domain (e.g. 'microsoft.com'). Numeric ids/URNs are not fetchable; use them only in linkedin_search_people company filters. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "identifier": "microsoft" } ``` Output: returns a `company` envelope. Full field list: https://veezee.io/docs/fields#company --- ## linkedin_get_posts Fetch the recent LinkedIn posts of one person or one company. identifier accepts a profile or company URL, a slug, a person URN, or a company website domain like 'microsoft.com'; the entity type is detected automatically. A domain resolves to its verified company first, exactly like linkedin_get_company: it QUOTES base+4 credits (set max_credits accordingly) and the surcharge is refunded at settlement for already-known domains, so they settle at the base price. Company URNs and numeric company ids are search-filter inputs, not fetch identifiers: use the company slug, URL, or domain here. Returns one page of posts (text, created_at, author, likes, comments_count, shares, is_repost, url) with a cursor for older posts. Costs 4 credits per page. Use this for 'what has X been posting', voice-of-company research, or activity checks before outreach. Not for reading one specific post you already have a URL for, and not for keyword search across LinkedIn; neither is supported in v1. Credits: 4. REST: `GET /v1/linkedin/posts` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `identifier` | yes | `string` | Person or company URL, slug, URN, or company website domain. | | `cursor` | no | `string` | Cursor from a previous page for older posts. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "identifier": "https://www.linkedin.com/company/microsoft/" } ``` Output: returns a `posts` envelope. Full field list: https://veezee.io/docs/fields#posts --- ## reddit_search Search all of Reddit by keywords. type picks the target: posts (default), comments (what people actually say about a product, problem, or brand -- unique to Reddit search), subreddits (find communities), users. Pass query as free text up to 256 characters; decompose broad topics into several narrower queries, since result depth per query is capped upstream around a few hundred results. sort applies to posts (relevance|top|new|hot|comment_count) and comments (relevance|top|new); range (past_hour..all_time) applies to posts only; both are rejected with INVALID_INPUT elsewhere. Costs 6 credits per page; a cursor page is a NEW call priced the same way. Returns one page of summaries (author, title or comment text, upvotes, comment_count, created_at, permalink, id) with a cursor; there is no server-side time window on comment search, so for monitoring filter on created_at yourself and poll with sort=new. Fetch full post bodies and discussion threads with reddit_get_post; read one community's feed with reddit_get_subreddit_posts. For high-volume recency sweeps across X instead, use x_search. Credits: 6. REST: `GET /v1/reddit/search` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `query` | yes | `string` | Free-text keywords, e.g. 'self hosted photo backup'. Not a URL; use reddit_resolve_url for URLs. | | `type` | no | `string` | What to search. 'comments' finds mentions inside discussions; 'subreddits' finds communities. | | `sort` | no | `string` | posts: any value; comments: relevance|top|new; invalid for subreddits and users. | | `range` | no | `string` | Time window. posts only. | | `cursor` | no | `string` | Cursor from a previous page. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "query": "notion alternative", "type": "comments" } ``` Output: returns a `reddit_search` envelope. Full field list: https://veezee.io/docs/fields#reddit_search --- ## reddit_get_subreddit Fetch one subreddit's profile: title, description, subscriber and active-user counts, age, NSFW flag, and topics. subreddit_name is the name without the r/ prefix, e.g. 'selfhosted'; a full reddit.com URL also works. Set include_settings to also get the community rules and moderator list for +2 credits (useful before posting or judging moderation culture). Costs 4 credits base. Subscriber counts here are the standard sizing signal for market research. This tool does not return posts: read the feed with reddit_get_subreddit_posts, and discover subreddits you don't know by name with reddit_search type=subreddits. Credits: 4. REST: `GET /v1/reddit/subreddits` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `subreddit_name` | yes | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. Full URLs are accepted and cleaned. | | `include_settings` | no | `boolean` | Also return rules and moderators for +2 credits. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "subreddit_name": "selfhosted" } ``` Output: returns a `subreddit` envelope. Full field list: https://veezee.io/docs/fields#subreddit --- ## reddit_get_subreddit_posts Fetch one page of posts from a single subreddit, the community-monitoring primitive. subreddit_name is the name without the r/ prefix. sort defaults to the subreddit's own front-page order (best); use sort=new for monitoring. sort=top and controversial need a range, but the window is currently not applied upstream on this feed: top returns the subreddit's all-time top posts whatever range says (time-windowed tops are a known gap here; reddit_search's range DOES work for keyword queries). Costs 4 credits per page; a cursor page is a NEW call priced the same way. Reddit splices about one promoted ad into every feed page; these are dropped by default, so set include_promoted=true only when ads ARE the data you want (ad intelligence, who targets this community) -- kept ads carry is_promoted=true. Returns post summaries (title, author, upvotes, comment_count, created_at, permalink, id) with a cursor for older posts; bodies and discussions come from reddit_get_post with the returned ids. For keyword search across all of Reddit use reddit_search; this tool takes no query. Credits: 4. REST: `GET /v1/reddit/subreddit-posts` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `subreddit_name` | yes | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `sort` | no | `string` | Defaults to the subreddit's front-page order. | | `range` | no | `string` | Required with sort=top or controversial, but currently not applied upstream on this feed (results are all-time). | | `include_promoted` | no | `boolean` | Keep the promoted ads Reddit splices into the feed (marked is_promoted). Default drops them. | | `cursor` | no | `string` | Cursor from a previous page for older posts. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "subreddit_name": "selfhosted", "sort": "new" } ``` Output: returns a `reddit_posts` envelope. Full field list: https://veezee.io/docs/fields#reddit_posts --- ## reddit_get_user Fetch one Reddit user's public profile: username, account age, karma, follower count, and description. username is the name without the u/ prefix, e.g. 'spez'; a full profile URL also works. Add up to 2 sections from comments|posts|subreddits at 2 credits each: comments and posts return that user's recent activity (first page), subreddits returns where they are active. Costs 4 credits base. Use this to profile loud voices found via reddit_search before quoting or engaging them. To find users by topic, use reddit_search type=users; this tool needs an exact username. Credits: 4. REST: `GET /v1/reddit/users` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `username` | yes | `string` | Reddit username without the u/ prefix, e.g. 'spez'. Full profile URLs are accepted and cleaned. | | `sections` | no | `array` | Extra activity sections, 2 credits each (max 2 per call). | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "username": "spez" } ``` Output: returns a `reddit_user` envelope. Full field list: https://veezee.io/docs/fields#reddit_user --- ## reddit_get_post Fetch full post content for up to 100 Reddit posts by their t3_ ids in one call -- the follow-up loop after reddit_search or reddit_get_subreddit_posts. Costs 4 credits for up to 10 ids, +1 credit per further 10 ids; every post comes back with its full body text. With exactly ONE id you may set detail to 'full' for +4 credits to also get the discussion tree (comments flattened in tree order with depth, about 200 per page, with a comments_cursor to continue), or pass comment_id (a t1_ id, also +4 credits) to fetch one specific comment in its post context. Post ids come from the other Reddit tools or from reddit_resolve_url on a post URL. Not for discovering posts; search first, then batch-fetch here. Credits: 4. REST: `GET /v1/reddit/posts` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `post_ids` | yes | `array` | 1 to 100 post ids with the t3_ prefix, e.g. ["t3_1tbups6"]. | | `detail` | no | `string` | 'full' adds the discussion tree; only valid with exactly one id, +4 credits. | | `comment_id` | no | `string` | A t1_ comment id to fetch in context; only valid with exactly one post id, +4 credits like detail 'full'. | | `sort` | no | `string` | Discussion-tree order; only with detail 'full'. | | `cursor` | no | `string` | comments_cursor from a previous detail='full' page. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "post_ids": [ "t3_1tbups6", "t3_1tbuneg" ] } ``` Output: returns a `reddit_thread` envelope. Full field list: https://veezee.io/docs/fields#reddit_thread --- ## reddit_resolve_url Identify what a Reddit URL points at before fetching it. Give any reddit.com or redd.it URL (share links, old.reddit.com, trailing params are fine); get back {type: subreddit|user|post|comment, id, handle, canonical_url}. Post URLs yield the t3_ id for reddit_get_post; comment permalinks yield the t1_ id; subreddit and user URLs yield the name for reddit_get_subreddit or reddit_get_user. Costs 2 credits and parses offline without fetching the page. Skip this tool when you already have a t3_/t1_ id, subreddit name, or username: the other Reddit tools accept those directly. Not for non-Reddit URLs; it returns INVALID_INPUT for those. Credits: 2. REST: `GET /v1/reddit/resolve-url` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `url` | yes | `string` | A Reddit URL, e.g. https://www.reddit.com/r/selfhosted/comments/1tbups6/... or https://redd.it/1tbups6. | ### Example ```json { "url": "https://redd.it/1tbups6" } ``` Output: returns a `url_resolution` envelope. Full field list: https://veezee.io/docs/fields#url_resolution --- ## x_search Search X by keywords. type picks the mode: recent (default) is the deep chronological sweep and keeps paginating as far as you follow the cursor; popular returns the highest-engagement tweets for the query; people finds accounts and returns a single page (no cursor). Advanced query operators pass through verbatim, e.g. "from:nasa", "min_faves:100", exact phrases in quotes -- there is no separate date parameter, so use since:/until: operators for time windows. Costs 6 credits per page; a cursor page is a NEW call priced the same way, so a deep sweep costs linearly in pages. Returns tweet summaries (text, author with follower count, views, likes, retweets, replies, created_at, url, id) with a cursor. Fetch one tweet's full detail with x_get_tweet and an account's timeline with x_get_tweets. For comment-level sentiment inside topic communities, reddit_search type=comments is usually the sharper instrument. Credits: 6. REST: `GET /v1/x/search` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `query` | yes | `string` | Free-text keywords; X advanced operators work, e.g. 'claude code from:AnthropicAI since:2026-06-01'. | | `type` | no | `string` | recent = chronological deep sweep; popular = top engagement; people = account search (single page). | | `cursor` | no | `string` | Cursor from a previous page. Not valid with type 'people'. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "query": "veezee api" } ``` Output: returns a `x_search` envelope. Full field list: https://veezee.io/docs/fields#x_search --- ## x_get_profile Fetch one X account's profile: name, bio, location, website, follower/following counts, tweet and media counts, verification state, and join date. identifier accepts a screen name without the @ (e.g. 'nasa'), a full x.com or twitter.com profile URL, or the numeric account id; numeric strings are treated as ids, and the rare all-digit handle can be forced with by='screen_name'. Costs 4 credits. The returned platform_fields.id is stable across handle changes; store it for repeat lookups. To find accounts by topic use x_search type=people, and to read what an account posts use x_get_tweets; this tool returns no tweets. Credits: 4. REST: `GET /v1/x/profiles` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `identifier` | yes | `string` | Screen name without the @ (e.g. 'nasa'), profile URL, or numeric account id. | | `by` | no | `string` | Force how identifier is interpreted; auto-detected when omitted. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "identifier": "nasa" } ``` Output: returns a `x_profile` envelope. Full field list: https://veezee.io/docs/fields#x_profile --- ## x_get_tweets Fetch one page of an X account's timeline. identifier is a screen name, profile URL, or numeric id (auto-detected). mode picks the view: posts (default) is the account's own tweets, posts_and_replies includes their replies, highlights is the account's pinned highlights tab. include_retweets (default true) filters retweets out when false. Costs 4 credits per page; a cursor page is a NEW call priced the same way. Returns tweet summaries with engagement counts and a cursor for older tweets. Use this for 'what has X been posting', voice checks before outreach, or drafting replies in an account's register. For keyword search across all of X use x_search; for one specific tweet you already have, x_get_tweet. Credits: 4. REST: `GET /v1/x/tweets` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `identifier` | yes | `string` | Screen name without the @, profile URL, or numeric account id. | | `mode` | no | `string` | Which timeline view to read. | | `include_retweets` | no | `boolean` | Set false to drop retweets from the page. | | `cursor` | no | `string` | Cursor from a previous page for older tweets. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "identifier": "nasa" } ``` Output: returns a `x_tweets` envelope. Full field list: https://veezee.io/docs/fields#x_tweets --- ## x_get_tweet Fetch one tweet by id with full engagement metrics: views, likes, retweets, quotes, replies, bookmarks, language, and the quoted tweet inline when there is one. tweet_id is the numeric id from a tweet URL (the digits after /status/) or from any other X tool's results; full tweet URLs are accepted too. Costs 4 credits. Use this to verify engagement before citing a tweet or to read a quoted thread hop by hop. It returns a single tweet, not the conversation around it: for the author's other tweets use x_get_tweets, and to find tweets by topic use x_search. Credits: 4. REST: `GET /v1/x/tweet` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `tweet_id` | yes | `string` | Numeric tweet id, e.g. '2054497961162478079', or a full tweet URL. | | `freshness` | no | `string` | recent (default) serves cached data from the last few hours when available; realtime forces a live fetch for +2 credits (refunded if we fall back to cached data). Trial keys are cached-only and reject realtime with TRIAL_CAP_EXCEEDED; paying upgrades this same key to unlock it. | | `max_credits` | no | `integer` | Spend ceiling for this one call. The call is rejected (nothing charged) if its quote exceeds this. Only the quote is ever reserved, never this ceiling. | ### Example ```json { "tweet_id": "2054497961162478079" } ``` Output: returns a `x_tweet` envelope. Full field list: https://veezee.io/docs/fields#x_tweet --- ## x_resolve_url Identify what an X (formerly Twitter) URL points at before fetching it. Give any x.com or twitter.com URL (mobile links, query params, /i/web/status forms are fine); get back {type: profile|tweet, id, handle, canonical_url}. Tweet URLs yield the numeric id for x_get_tweet; profile URLs yield the handle for x_get_profile or x_get_tweets. Costs 2 credits and parses offline without fetching the page. t.co short links cannot be expanded offline and return INVALID_INPUT telling you so; expand them in your own browser step first. Skip this tool when you already have a handle or tweet id: the other X tools accept those directly. Credits: 2. REST: `GET /v1/x/resolve-url` (auth: `required`, metered: `true`). ### Parameters | Param | Required | Type | Description | | --- | --- | --- | --- | | `url` | yes | `string` | An X URL, e.g. https://x.com/nasa/status/2054497961162478079 or https://twitter.com/nasa. | ### Example ```json { "url": "https://x.com/nasa/status/2054497961162478079" } ``` Output: returns a `url_resolution` envelope. Full field list: https://veezee.io/docs/fields#url_resolution --- ## get_usage Check your balance, plan, limits, and the last 10 charges (receipt ids included). Costs 0 credits and is exempt from the per-minute rate limit, so call it first to check your budget before running data tools, and any time after. Works the same on a trial key or a paid key. The response includes upgrade_url (give it to your human when credits or plan limits block you; purchases credit this account directly with no login) and manage_url (give it to your human to change or cancel a paid plan in the Stripe billing portal). Trial accounts also get a claim_url that attaches an email so the account can be recovered if the key is lost. Like every tool on this server, this one needs an API key; if this session doesn't have one yet, call mint_key first (when offered) or POST /v1/keys/mint. Not for fetching platform data. Credits: 0. REST: `GET /v1/usage` (auth: `required`, metered: `false`). ### Parameters No parameters. ### Example ```json {} ``` Output: returns a `usage` envelope. Full field list: https://veezee.io/docs/fields#usage --- # Connect your client - Veezee docs One MCP server, many hosts. Endpoint: `https://mcp.veezee.io/linkedin` (streamable-http). Clients that support the MCP authorization spec (Claude Code, claude.ai, ChatGPT developer-mode connectors) open a Veezee sign-in in your browser on connect: email code, no password, no card, zero keys to copy. Other clients: mint a free key with `POST https://api.veezee.io/v1/keys/mint` and every host below connects under a shared per-IP daily budget; buy a key at https://veezee.io/upgrade for more. Snippets verified against each client's official docs on 2026-07-11; "tested" marks what was actually exercised against production. ## Claude Code ``` claude mcp add --transport http veezee https://mcp.veezee.io/linkedin ``` Terminal; persists to ~/.claude.json (or project .mcp.json with --scope). Opens a Veezee sign-in in your browser (email code, no password, no card); approving it connects the account, zero keys involved. Headless or CI: mint a free key over REST instead and put it in the client's connection headers.. Status: tested end to end (real binary, 2026-07-11: linkedin_get_company at 4 credits, zero errors). Official docs: https://code.claude.com/docs/en/mcp ## claude.ai (web) ``` Settings > Connectors > Add custom connector > https://mcp.veezee.io/linkedin ``` claude.ai settings UI, no config file. Team/Enterprise: Organization settings > Connectors. Enable per-chat from the + menu. Leave the optional client id/secret fields blank. Connecting opens a Veezee sign-in (email code, no password, no card); approving it connects the account, zero keys involved.. Status: config path verified against official docs; not app-tested. Official docs: https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp ## Cursor ``` { "mcpServers": { "veezee": { "url": "https://mcp.veezee.io/linkedin" } } } ``` .cursor/mcp.json (project) or ~/.cursor/mcp.json (global). Status: config verified against official docs; desktop flow pending a human run (BLOCKERS.md). Official docs: https://cursor.com/docs/context/mcp ## Windsurf ``` { "mcpServers": { "veezee": { "serverUrl": "https://mcp.veezee.io/linkedin" } } } ``` ~/.codeium/windsurf/mcp_config.json (note the serverUrl key, not url). Status: config verified against official docs; not app-tested. Official docs: https://docs.devin.ai/desktop/cascade/mcp ## VS Code (Copilot agent mode) ``` { "servers": { "veezee": { "type": "http", "url": "https://mcp.veezee.io/linkedin" } } } ``` .vscode/mcp.json (top-level key is "servers", and "type": "http" is required). Status: config verified against official docs; not app-tested. Official docs: https://code.visualstudio.com/docs/copilot/chat/mcp-servers ## Codex CLI ``` codex mcp add veezee --url https://mcp.veezee.io/linkedin # or in ~/.codex/config.toml: [mcp_servers.veezee] url = "https://mcp.veezee.io/linkedin" ``` ~/.codex/config.toml. Status: tested end to end (real binary, headless codex exec, 2026-07-11: linkedin_get_company, error-recovery flow). Official docs: https://developers.openai.com/codex/mcp ## Cline ``` { "mcpServers": { "veezee": { "type": "streamableHttp", "url": "https://mcp.veezee.io/linkedin" } } } ``` Cline panel > MCP Servers > Remote Servers, or cline_mcp_settings.json. Set "type": "streamableHttp" explicitly.. Status: config verified against official docs; not app-tested. Official docs: https://docs.cline.bot/mcp/configuring-mcp-servers ## Zed ``` { "context_servers": { "veezee": { "url": "https://mcp.veezee.io/linkedin" } } } ``` Zed settings.json under "context_servers", or Settings > AI > MCP Servers > Add Remote Server. Status: config verified against official docs; not app-tested. Official docs: https://zed.dev/docs/ai/mcp ## Plain REST (curl) ``` curl -s -X POST https://api.veezee.io/v1/keys/mint | jq -r .key > ~/.veezee/key curl "https://api.veezee.io/v1/linkedin/companies?identifier=microsoft" \ -H "Authorization: Bearer $(cat ~/.veezee/key)" # hit the daily cap? buy a key at https://veezee.io/upgrade, then: curl "https://api.veezee.io/v1/linkedin/companies?identifier=microsoft" \ -H "Authorization: Bearer $VEEZEE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" ``` Any HTTP client. Contract: https://veezee.io/openapi.json. Metered calls need an Idempotency-Key header, even on GET (free-tier calls do not).. Status: tested end to end (the e2e suite runs this against production on every deploy). Official docs: https://veezee.io/openapi.json ## SDK `npm install @veezee/sdk` (Node 20+): typed client for every tool, retries and Idempotency-Keys built in. `npm install -g @veezee/sdk` also gives the `veezee` CLI. Docs: https://veezee.io/docs/sdk and https://veezee.io/docs/cli. All three servers are listed in the official MCP Registry: MCP Registry: io.veezee servers (https://registry.modelcontextprotocol.io/v0/servers?search=io.veezee). --- # Field reference - Veezee docs Every field Veezee serves, generated from https://veezee.io/openapi.json. Only served fields appear here; nothing upstream-only. ## url_resolution | Field | Type | Description | | --- | --- | --- | | `entity` | `"url_resolution"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.input_url` | `string` | | | `common.type` | `person | company | post | subreddit | user | comment | profile | tweet` | What the URL points at, in the platform's own vocabulary. | | `common.id` | `string | null` | | | `common.handle` | `string | null` | | | `common.canonical_url` | `string | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## person | Field | Type | Description | | --- | --- | --- | | `entity` | `"person"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.full_name` | `string` | | | `common.first_name` | `string | null` | | | `common.last_name` | `string | null` | | | `common.headline` | `string | null` | | | `common.location.name` | `string | null` | | | `common.location.country_code` | `string | null` | | | `common.about` | `string | null` | | | `common.current_position.company_name` | `string | null` | | | `common.current_position.company_handle` | `string | null` | | | `common.current_position.company_url` | `string | null` | | | `common.current_position.company_urn` | `string | null` | | | `common.current_position.start_year` | `integer | null` | | | `common.experience[].company.name` | `string | null` | | | `common.experience[].company.handle` | `string | null` | | | `common.experience[].company.url` | `string | null` | | | `common.experience[].positions[].role` | `string | null` | | | `common.experience[].positions[].location` | `string | null` | | | `common.experience[].positions[].is_current` | `boolean | null` | | | `common.experience[].positions[].start_date.month` | `integer | null` | | | `common.experience[].positions[].start_date.year` | `integer | null` | | | `common.experience[].positions[].end_date.month` | `integer | null` | | | `common.experience[].positions[].end_date.year` | `integer | null` | | | `common.education[].institution` | `string | null` | | | `common.education[].institution_url` | `string | null` | | | `common.education[].degree` | `string | null` | | | `common.education[].start_year` | `integer | null` | | | `common.education[].end_year` | `integer | null` | | | `common.skills[].name` | `string` | | | `common.skills[].endorsement_count` | `integer | null` | | | `common.followers` | `integer | null` | | | `common.connections` | `integer | null` | | | `common.is_verified` | `boolean | null` | | | `common.image_url` | `string | null` | | | `common.url` | `string` | Canonical LinkedIn profile URL. | | `platform_fields.urn` | `string` | Stable LinkedIn URN (urn:li:fsd_profile:...). Use this for repeat lookups. | | `platform_fields.public_identifier` | `string | null` | | | `platform_fields.is_influencer` | `boolean | null` | | | `platform_fields.is_creator` | `boolean | null` | | | `platform_fields.is_hiring` | `boolean | null` | | | `platform_fields.has_premium` | `boolean | null` | | | `platform_fields.open_to_messages` | `boolean | null` | | | `platform_fields.pronoun` | `string | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## people_search | Field | Type | Description | | --- | --- | --- | | `entity` | `"people_search"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.results[].name` | `string` | | | `common.results[].position` | `string | null` | | | `common.results[].location` | `string | null` | | | `common.results[].followers` | `integer | null` | | | `common.results[].is_verified` | `boolean | null` | | | `common.results[].image_url` | `string | null` | | | `common.results[].url` | `string | null` | | | `common.results[].urn` | `string` | | | `common.results[].public_identifier` | `string | null` | | | `common.results[].is_anonymous` | `boolean` | True when the profile is private: it exists but linkedin_get_profile cannot dereference it. Do not retry. | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.total_matches` | `integer | null` | | | `common.returned_count` | `integer` | | | `common.truncation_hint` | `string | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## company | Field | Type | Description | | --- | --- | --- | | `entity` | `"company"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.name` | `string` | | | `common.description` | `string | null` | | | `common.website_url` | `string | null` | | | `common.industry` | `array` | | | `common.employee_count` | `integer | null` | | | `common.employee_count_range` | `string | null` | | | `common.followers` | `integer | null` | | | `common.founded_year` | `integer | null` | | | `common.specialities` | `array` | | | `common.headquarters.name` | `string | null` | | | `common.headquarters.country_code` | `string | null` | | | `common.logo_url` | `string | null` | | | `common.url` | `string` | Canonical LinkedIn company URL. | | `platform_fields.urn` | `string` | Stable LinkedIn URN (urn:li:fsd_company:...). | | `platform_fields.linkedin_id` | `integer | null` | | | `platform_fields.public_identifier` | `string | null` | | | `platform_fields.organization_type` | `string | null` | | | `platform_fields.stock_symbol` | `string | null` | | | `platform_fields.is_verified` | `boolean | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## posts | Field | Type | Description | | --- | --- | --- | | `entity` | `"posts"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.results[].urn` | `string` | | | `common.results[].url` | `string | null` | | | `common.results[].text` | `string | null` | | | `common.results[].created_at` | `string | null` | | | `common.results[].author.name` | `string | null` | | | `common.results[].author.url` | `string | null` | | | `common.results[].author.urn` | `string | null` | | | `common.results[].likes` | `integer | null` | | | `common.results[].comments_count` | `integer | null` | | | `common.results[].shares` | `integer | null` | | | `common.results[].is_repost` | `boolean | null` | | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.returned_count` | `integer` | | | `common.author_type` | `person | company` | What kind of entity the posts belong to. | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## reddit_search | Field | Type | Description | | --- | --- | --- | | `entity` | `"reddit_search"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.type` | `posts | comments | subreddits | users` | Which result array is populated. | | `common.posts[].id` | `string` | Post id with the t3_ prefix. Pass to reddit_get_post. | | `common.posts[].title` | `string | null` | | | `common.posts[].author` | `string | null` | | | `common.posts[].subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.posts[].subreddit.subscribers` | `integer | null` | | | `common.posts[].created_at` | `string | null` | | | `common.posts[].upvotes` | `integer | null` | | | `common.posts[].upvote_ratio` | `number | null` | | | `common.posts[].comment_count` | `integer | null` | | | `common.posts[].permalink` | `string | null` | | | `common.posts[].external_url` | `string | null` | | | `common.posts[].preview_text` | `string | null` | | | `common.posts[].flair` | `string | null` | | | `common.posts[].media_type` | `string | null` | | | `common.posts[].is_promoted` | `boolean` | True for promoted ads, which subreddit feeds include only when include_promoted=true. Organic posts are false. | | `common.comments[].id` | `string` | Comment id with the t1_ prefix. | | `common.comments[].author` | `string | null` | | | `common.comments[].content` | `string | null` | | | `common.comments[].created_at` | `string | null` | | | `common.comments[].upvotes` | `integer | null` | | | `common.comments[].permalink` | `string | null` | | | `common.comments[].parent_id` | `string | null` | | | `common.comments[].depth` | `integer | null` | | | `common.comments[].post.id` | `string | null` | | | `common.comments[].post.title` | `string | null` | | | `common.comments[].post.subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.comments[].post.subreddit.subscribers` | `integer | null` | | | `common.subreddits[].name` | `string` | | | `common.subreddits[].description` | `string | null` | | | `common.subreddits[].subscribers` | `integer | null` | | | `common.users[].username` | `string` | | | `common.users[].created_at` | `string | null` | | | `common.users[].karma` | `integer | null` | | | `common.users[].profile_url` | `string | null` | | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.returned_count` | `integer` | | | `common.truncation_hint` | `string | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## subreddit | Field | Type | Description | | --- | --- | --- | | `entity` | `"subreddit"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.name` | `string` | | | `common.title` | `string | null` | | | `common.description` | `string | null` | | | `common.subscribers` | `integer | null` | | | `common.active_users` | `integer | null` | | | `common.created_at` | `string | null` | | | `common.is_nsfw` | `boolean | null` | | | `common.topics` | `array` | | | `common.url` | `string` | Canonical reddit.com URL for the subreddit. | | `common.rules[].name` | `string | null` | | | `common.rules[].description` | `string | null` | | | `common.moderators` | `array | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## reddit_posts | Field | Type | Description | | --- | --- | --- | | `entity` | `"reddit_posts"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.results[].id` | `string` | Post id with the t3_ prefix. Pass to reddit_get_post. | | `common.results[].title` | `string | null` | | | `common.results[].author` | `string | null` | | | `common.results[].subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.results[].subreddit.subscribers` | `integer | null` | | | `common.results[].created_at` | `string | null` | | | `common.results[].upvotes` | `integer | null` | | | `common.results[].upvote_ratio` | `number | null` | | | `common.results[].comment_count` | `integer | null` | | | `common.results[].permalink` | `string | null` | | | `common.results[].external_url` | `string | null` | | | `common.results[].preview_text` | `string | null` | | | `common.results[].flair` | `string | null` | | | `common.results[].media_type` | `string | null` | | | `common.results[].is_promoted` | `boolean` | True for promoted ads, which subreddit feeds include only when include_promoted=true. Organic posts are false. | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.returned_count` | `integer` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## reddit_user | Field | Type | Description | | --- | --- | --- | | `entity` | `"reddit_user"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.username` | `string` | | | `common.created_at` | `string | null` | | | `common.karma` | `integer | null` | | | `common.followers` | `integer | null` | | | `common.is_verified` | `boolean | null` | | | `common.description` | `string | null` | | | `common.account_type` | `string | null` | | | `common.url` | `string` | Canonical reddit.com URL for the user. | | `common.comments[].id` | `string` | Comment id with the t1_ prefix. | | `common.comments[].author` | `string | null` | | | `common.comments[].content` | `string | null` | | | `common.comments[].created_at` | `string | null` | | | `common.comments[].upvotes` | `integer | null` | | | `common.comments[].permalink` | `string | null` | | | `common.comments[].parent_id` | `string | null` | | | `common.comments[].depth` | `integer | null` | | | `common.comments[].post.id` | `string | null` | | | `common.comments[].post.title` | `string | null` | | | `common.comments[].post.subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.comments[].post.subreddit.subscribers` | `integer | null` | | | `common.posts[].id` | `string` | Post id with the t3_ prefix. Pass to reddit_get_post. | | `common.posts[].title` | `string | null` | | | `common.posts[].author` | `string | null` | | | `common.posts[].subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.posts[].subreddit.subscribers` | `integer | null` | | | `common.posts[].created_at` | `string | null` | | | `common.posts[].upvotes` | `integer | null` | | | `common.posts[].upvote_ratio` | `number | null` | | | `common.posts[].comment_count` | `integer | null` | | | `common.posts[].permalink` | `string | null` | | | `common.posts[].external_url` | `string | null` | | | `common.posts[].preview_text` | `string | null` | | | `common.posts[].flair` | `string | null` | | | `common.posts[].media_type` | `string | null` | | | `common.posts[].is_promoted` | `boolean` | True for promoted ads, which subreddit feeds include only when include_promoted=true. Organic posts are false. | | `common.subreddits[].name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.subreddits[].subscribers` | `integer | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## reddit_thread | Field | Type | Description | | --- | --- | --- | | `entity` | `"reddit_thread"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.posts[].id` | `string` | Post id with the t3_ prefix. Pass to reddit_get_post. | | `common.posts[].title` | `string | null` | | | `common.posts[].author` | `string | null` | | | `common.posts[].subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.posts[].subreddit.subscribers` | `integer | null` | | | `common.posts[].created_at` | `string | null` | | | `common.posts[].upvotes` | `integer | null` | | | `common.posts[].upvote_ratio` | `number | null` | | | `common.posts[].comment_count` | `integer | null` | | | `common.posts[].permalink` | `string | null` | | | `common.posts[].external_url` | `string | null` | | | `common.posts[].preview_text` | `string | null` | | | `common.posts[].flair` | `string | null` | | | `common.posts[].media_type` | `string | null` | | | `common.posts[].is_promoted` | `boolean` | True for promoted ads, which subreddit feeds include only when include_promoted=true. Organic posts are false. | | `common.posts[].content` | `string | null` | | | `common.comments[].id` | `string` | Comment id with the t1_ prefix. | | `common.comments[].author` | `string | null` | | | `common.comments[].content` | `string | null` | | | `common.comments[].created_at` | `string | null` | | | `common.comments[].upvotes` | `integer | null` | | | `common.comments[].permalink` | `string | null` | | | `common.comments[].parent_id` | `string | null` | | | `common.comments[].depth` | `integer | null` | | | `common.comments[].post.id` | `string | null` | | | `common.comments[].post.title` | `string | null` | | | `common.comments[].post.subreddit.name` | `string` | Subreddit name without the r/ prefix, e.g. 'selfhosted'. | | `common.comments[].post.subreddit.subscribers` | `integer | null` | | | `common.comments_cursor` | `string | null` | | | `common.returned_count` | `integer` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## x_search | Field | Type | Description | | --- | --- | --- | | `entity` | `"x_search"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.type` | `recent | popular | people` | Which result array is populated. | | `common.tweets[].id` | `string` | Numeric tweet id as a string. Pass to x_get_tweet. | | `common.tweets[].text` | `string | null` | | | `common.tweets[].author.screen_name` | `string | null` | | | `common.tweets[].author.name` | `string | null` | | | `common.tweets[].author.id` | `string | null` | | | `common.tweets[].author.followers` | `integer | null` | | | `common.tweets[].author.is_verified` | `boolean | null` | | | `common.tweets[].created_at` | `string | null` | | | `common.tweets[].url` | `string | null` | | | `common.tweets[].views` | `integer | null` | | | `common.tweets[].likes` | `integer | null` | | | `common.tweets[].retweets` | `integer | null` | | | `common.tweets[].replies` | `integer | null` | | | `common.tweets[].quotes` | `integer | null` | | | `common.tweets[].bookmarks` | `integer | null` | | | `common.tweets[].lang` | `string | null` | | | `common.tweets[].is_reply` | `boolean | null` | | | `common.tweets[].is_retweet` | `boolean | null` | | | `common.tweets[].is_quote` | `boolean | null` | | | `common.tweets[].in_reply_to_screen_name` | `string | null` | | | `common.tweets[].conversation_id` | `string | null` | | | `common.tweets[].possibly_sensitive` | `boolean | null` | | | `common.people[].screen_name` | `string | null` | | | `common.people[].name` | `string | null` | | | `common.people[].id` | `string | null` | | | `common.people[].followers` | `integer | null` | | | `common.people[].is_verified` | `boolean | null` | | | `common.people[].description` | `string | null` | | | `common.people[].location` | `string | null` | | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.returned_count` | `integer` | | | `common.truncation_hint` | `string | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## x_profile | Field | Type | Description | | --- | --- | --- | | `entity` | `"x_profile"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.screen_name` | `string` | | | `common.name` | `string | null` | | | `common.description` | `string | null` | | | `common.location` | `string | null` | | | `common.website_url` | `string | null` | | | `common.created_at` | `string | null` | | | `common.followers` | `integer | null` | | | `common.following` | `integer | null` | | | `common.tweets_count` | `integer | null` | | | `common.media_count` | `integer | null` | | | `common.is_verified` | `boolean | null` | | | `common.verified_type` | `string | null` | | | `common.is_protected` | `boolean | null` | | | `common.image_url` | `string | null` | | | `common.banner_url` | `string | null` | | | `common.url` | `string` | Canonical x.com profile URL. | | `platform_fields.id` | `string` | Numeric account id as a string; stable across handle changes. Use for repeat lookups. | | `platform_fields.pinned_tweet_ids` | `array | null` | | | `platform_fields.is_business_account` | `boolean | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## x_tweets | Field | Type | Description | | --- | --- | --- | | `entity` | `"x_tweets"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.results[].id` | `string` | Numeric tweet id as a string. Pass to x_get_tweet. | | `common.results[].text` | `string | null` | | | `common.results[].author.screen_name` | `string | null` | | | `common.results[].author.name` | `string | null` | | | `common.results[].author.id` | `string | null` | | | `common.results[].author.followers` | `integer | null` | | | `common.results[].author.is_verified` | `boolean | null` | | | `common.results[].created_at` | `string | null` | | | `common.results[].url` | `string | null` | | | `common.results[].views` | `integer | null` | | | `common.results[].likes` | `integer | null` | | | `common.results[].retweets` | `integer | null` | | | `common.results[].replies` | `integer | null` | | | `common.results[].quotes` | `integer | null` | | | `common.results[].bookmarks` | `integer | null` | | | `common.results[].lang` | `string | null` | | | `common.results[].is_reply` | `boolean | null` | | | `common.results[].is_retweet` | `boolean | null` | | | `common.results[].is_quote` | `boolean | null` | | | `common.results[].in_reply_to_screen_name` | `string | null` | | | `common.results[].conversation_id` | `string | null` | | | `common.results[].possibly_sensitive` | `boolean | null` | | | `common.cursor` | `string | null` | | | `common.next_url` | `string | null` | | | `common.returned_count` | `integer` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## x_tweet | Field | Type | Description | | --- | --- | --- | | `entity` | `"x_tweet"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.id` | `string` | Numeric tweet id as a string. Pass to x_get_tweet. | | `common.text` | `string | null` | | | `common.author.screen_name` | `string | null` | | | `common.author.name` | `string | null` | | | `common.author.id` | `string | null` | | | `common.author.followers` | `integer | null` | | | `common.author.is_verified` | `boolean | null` | | | `common.created_at` | `string | null` | | | `common.url` | `string | null` | | | `common.views` | `integer | null` | | | `common.likes` | `integer | null` | | | `common.retweets` | `integer | null` | | | `common.replies` | `integer | null` | | | `common.quotes` | `integer | null` | | | `common.bookmarks` | `integer | null` | | | `common.lang` | `string | null` | | | `common.is_reply` | `boolean | null` | | | `common.is_retweet` | `boolean | null` | | | `common.is_quote` | `boolean | null` | | | `common.in_reply_to_screen_name` | `string | null` | | | `common.conversation_id` | `string | null` | | | `common.possibly_sensitive` | `boolean | null` | | | `common.quoted_tweet.id` | `string` | Numeric tweet id as a string. Pass to x_get_tweet. | | `common.quoted_tweet.text` | `string | null` | | | `common.quoted_tweet.author.screen_name` | `string | null` | | | `common.quoted_tweet.author.name` | `string | null` | | | `common.quoted_tweet.author.id` | `string | null` | | | `common.quoted_tweet.author.followers` | `integer | null` | | | `common.quoted_tweet.author.is_verified` | `boolean | null` | | | `common.quoted_tweet.created_at` | `string | null` | | | `common.quoted_tweet.url` | `string | null` | | | `common.quoted_tweet.views` | `integer | null` | | | `common.quoted_tweet.likes` | `integer | null` | | | `common.quoted_tweet.retweets` | `integer | null` | | | `common.quoted_tweet.replies` | `integer | null` | | | `common.quoted_tweet.quotes` | `integer | null` | | | `common.quoted_tweet.bookmarks` | `integer | null` | | | `common.quoted_tweet.lang` | `string | null` | | | `common.quoted_tweet.is_reply` | `boolean | null` | | | `common.quoted_tweet.is_retweet` | `boolean | null` | | | `common.quoted_tweet.is_quote` | `boolean | null` | | | `common.quoted_tweet.in_reply_to_screen_name` | `string | null` | | | `common.quoted_tweet.conversation_id` | `string | null` | | | `common.quoted_tweet.possibly_sensitive` | `boolean | null` | | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | ## usage | Field | Type | Description | | --- | --- | --- | | `entity` | `"usage"` | | | `platform` | `linkedin | reddit | x | null` | | | `canonical_url` | `string | null` | | | `data_as_of` | `string | null` | | | `schema_version` | `"2"` | | | `common.plan` | `trial | payg | flex | production` | | | `common.platforms` | `array` | Platforms this account's key may call. Grants are explicit; write to hello@veezee.io to enable more. | | `common.balance_remaining` | `integer` | | | `common.free_tier.credits_per_ip_day` | `integer` | | | `common.free_tier.used_today` | `integer` | | | `common.free_tier.remaining_today` | `integer` | | | `common.free_tier.resets` | `string` | UTC midnight when the day budget resets. ISO 8601. | | `common.realtime_ops_used` | `integer` | | | `common.realtime_ops_limit` | `integer | null` | | | `common.concurrent_limit` | `integer` | | | `common.recent_receipts[].receipt_id` | `string` | | | `common.recent_receipts[].tool` | `string` | | | `common.recent_receipts[].credits_charged` | `integer` | | | `common.recent_receipts[].created_at` | `string` | | | `common.claim_url` | `string | null` | | | `common.upgrade_url` | `string` | Give this link to your human to add credits or upgrade; purchases credit THIS account with no login. | | `common.manage_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. | | `freshness.source_retrieved_at` | `string | null` | | | `freshness.served_at` | `string` | | | `freshness.cache_age_seconds` | `integer | null` | | | `freshness.served_from_cache` | `boolean` | True when these bytes were served from cache rather than fetched for this call. source_retrieved_at says how old they are. | | `freshness.freshness_requested` | `recent | realtime` | | | `freshness.freshness_served` | `recent | realtime | stale` | | | `usage.receipt_id` | `string | null` | | | `usage.credits_quoted` | `integer` | | | `usage.credits_charged` | `integer` | | | `usage.balance_remaining` | `integer | null` | | | `usage.free_tier_hint` | `string` | Present on free-tier trial-key calls: what budget the call drew from and that paying upgrades this same key. | --- # Pricing - Veezee Start free: your agent creates its own key in one call, no account or card, and gets 200 credits per IP per day (about 6,000 a month). Need more? Pay as you go at $2.00 per 1,000 credits ($20.00 minimum), or $99.00/mo with 80,000 credits included. Payment credits the key you already have, so nothing needs reconfiguring. Every tool's cost is fixed and shown on every response. Only calls that return data spend credits: failed calls refund automatically, and unused purchased credits are refunded on request within 14 days. What agents pay elsewhere: the leading LinkedIn MCP vendor charges $1.50 per 1,000 results pay-as-you-go and $1,999/month on its volume plan; the official X API bills $0.005 per post read and $0.010 per user lookup on prepaid credits and requires an approved developer account (docs.x.com/x-api/getting-started/pricing, checked 2026-07-17), covering neither LinkedIn nor Reddit. Veezee starts at $0 with one prepaid meter across all three platforms. Named, dated sources: https://veezee.io/alternatives ## Packs | Pack | Credits | Price | Notes | | --- | --- | --- | --- | | Free key | 200 credits/day | $0.00 | shared per IP; the agent mints the key free, no signup, no card, recent data only | | Pay-as-you-go | per 1,000 credits | $2.00 | unit rate; $20.00 minimum purchase | | Flex pack | 10,000 credits | $20.00 | prepaid, does not expire while the account is open | | Production | 80,000 credits/mo | $99.00/mo | 5 concurrent, higher rate limits (120 req/min, search up to 30 results/call) | ## How to buy Humans buy on https://veezee.io/pricing (each plan card checks out directly) or on https://veezee.io/upgrade; a new key is shown once on the confirmation page. Already have a key (agents mint one free at `POST /v1/keys/mint`)? Use the personalized upgrade_url that get_usage or a payment-fixable error returns: payment credits that same key, nothing to reconfigure. Payment runs through Stripe Checkout. ## Tool costs | Tool | Credits | Notes | | --- | --- | --- | | linkedin_resolve_url | 2 | | | linkedin_get_profile | 4 | first 2 sections included; +2/section after, up to 4 total | | linkedin_search_people | 10 | first 10 results included; +1/10 more, up to 30 (10 on trial) | | linkedin_get_company | 4 | | | linkedin_get_posts | 4 | | | reddit_search | 6 | | | reddit_get_subreddit | 4 | | | reddit_get_subreddit_posts | 4 | | | reddit_get_user | 4 | | | reddit_get_post | 4 | | | reddit_resolve_url | 2 | | | x_search | 6 | | | x_get_profile | 4 | | | x_get_tweets | 4 | | | x_get_tweet | 4 | | | x_resolve_url | 2 | | | get_usage | 0 | | Realtime freshness (`freshness: "realtime"`) adds 2 credits to any tool that accepts it; refunded automatically if the live fetch falls back to cached data. Realtime needs a paid key: a free key always serves cached (`recent`) data. ## Free-key and trial-key limits Free-key calls draw from the per-IP daily budget above (the Free plan). A `vz_trial_` key, issued through account recovery, carries its own caps: 500 credits, 1 concurrent call, 20 calls/minute, search capped at 10 results/call, 5 realtime fetches total. Claim any trial key with an email and confirm it by signing in at https://veezee.io/login: that adds a one-time 10,000-credit grant (once per email, once per key), spent under the same trial limits, after the free daily budget. ## Example costs | Call | Credits | PAYG cost | | --- | --- | --- | | linkedin_resolve_url, one URL | 2 | $0.00 | | linkedin_get_profile, up to 2 sections | 4 | $0.01 | | linkedin_get_profile, all 4 sections | 8 | $0.02 | | linkedin_search_people, limit=10 | 10 | $0.02 | | linkedin_search_people, limit=30 | 12 | $0.02 | | linkedin_get_company, one company | 4 | $0.01 | | linkedin_get_posts, one page | 4 | $0.01 | | realtime surcharge, any tool | 2 | $0.00 | --- # Trust - Veezee What Veezee stores, how it's protected, and how to leave. ## What we store We keep request and response bodies to support idempotent replay: if you retry a call with the same `Idempotency-Key`, you get back the exact stored result instead of a second charge. Bodies are kept for up to 30 days and are size-capped. Ledger events (the record of what was charged and when) are kept indefinitely, since they're your billing record. ## Telemetry Operational telemetry uses opaque, hashed identifiers, never raw account or request data. We don't put personal information in telemetry. ## Keys API keys are shown to you exactly once, at creation. We store only a hash of the key, not the key itself. ## Authentication REST and the CLI use API keys only, no OAuth. MCP clients that support the MCP authorization spec (Claude Code, claude.ai, ChatGPT developer-mode connectors, and others) connect via a real OAuth flow instead: an unauthenticated request gets a 401 with OAuth discovery, and a compliant client opens a Veezee sign-in with no key involved. Full reference: https://veezee.io/auth.md ## Billing and cancellation Paid plans are self-serve through Stripe. To change or cancel: ask your agent for its manage link (the free get_usage tool returns `manage_url`), or paste your API key at https://veezee.io/manage. Either opens the Stripe billing portal for your account. Flex packs are one-time purchases; nothing recurs, so there is nothing to cancel. ## Contact hello@veezee.io --- # Agent readiness - Veezee Agent readiness is the set of conventions that make a site legible to AI agents: stable URLs, markdown twins, structured data, robots controls, and machine-readable discovery files. This page walks the [Website Spec agent-readiness checklist](https://specification.website/spec/agent-readiness/) item by item and shows where veezee.io stands. Every Live row links to the artifact itself, on this domain, fetchable right now. Current score: the one required item, 8 of 9 recommended items, and 6 of 10 optional items are live. The rows below say exactly what is not live and why. ## Required | Item | Status | Proof | | --- | --- | --- | | [Stable URLs](https://specification.website/spec/agent-readiness/stable-urls/) | Live | URLs are public contracts. Renamed pages keep serving as redirects ([/twitter-api-for-ai-agents](/twitter-api-for-ai-agents)), and every published path is listed in [/sitemap.xml](/sitemap.xml). | ## Recommended | Item | Status | Proof | | --- | --- | --- | | [Agent readiness overview](https://specification.website/spec/agent-readiness/agent-readiness-overview/) | Live | This page. | | [/llms.txt](https://specification.website/spec/agent-readiness/llms-txt/) | Live | [/llms.txt](/llms.txt): a curated index of the whole corpus. | | [Per-page Markdown](https://specification.website/spec/agent-readiness/markdown-source-endpoints/) | Live | Append index.md to any docs URL, or send `Accept: text/markdown`. Try [/docs/index.md](/docs/index.md). | | [robots.txt for AI crawlers](https://specification.website/spec/agent-readiness/robots-for-ai-crawlers/) | Live | [/robots.txt](/robots.txt) names GPTBot, ClaudeBot, CCBot, Google-Extended, PerplexityBot, and more, each with an explicit allow. | | [Structured data](https://specification.website/spec/agent-readiness/structured-data-for-agents/) | Live | JSON-LD (SoftwareApplication, Organization, Offer, BreadcrumbList) ships inline in every page. View source on [/](/) or [/pricing](/pricing). | | [Machine-readable formats](https://specification.website/spec/agent-readiness/machine-readable-formats/) | Live | [/product.json](/product.json), [/recipes.json](/recipes.json), [/openapi.json](/openapi.json), [/proof-feed.json](/proof-feed.json). | | [HTTP Link headers](https://specification.website/spec/agent-readiness/link-headers/) | Live | Every page response carries a Link header naming [/openapi.json](/openapi.json) as service-desc; the home page adds alternate links to [/llms.txt](/llms.txt) and [/index.md](/index.md). Check with `curl -sI https://veezee.io/`. | | [Agent Skills discovery](https://specification.website/spec/agent-readiness/agent-skills-discovery/) | Live | [/.well-known/agent-skills/index.json](/.well-known/agent-skills/index.json), backed by the packs at [/docs/skills](/docs/skills). | | [DNS-AID](https://specification.website/spec/agent-readiness/dns-aid/) | Not yet | The `_index._agents` and `_mcp._agents` HTTPS records are drafted; DNS changes ship through a manual approval gate. Every artifact on this page is discoverable over HTTP today. | ## Optional | Item | Status | Proof | | --- | --- | --- | | [/llms-full.txt](https://specification.website/spec/agent-readiness/llms-full-txt/) | Live | [/llms-full.txt](/llms-full.txt): the whole docs corpus in one fetch. | | [Content Signals](https://specification.website/spec/agent-readiness/content-signals/) | Live | `Content-Signal: search=yes, ai-input=yes, ai-train=yes` in [/robots.txt](/robots.txt). | | [Web Bot Auth](https://specification.website/spec/agent-readiness/web-bot-auth/) | Not applicable | It defines how bot operators sign their requests. A content site has nothing to publish, and we serve signed and unsigned bots the same content. | | [MCP and tool discovery](https://specification.website/spec/agent-readiness/mcp-and-tool-discovery/) | Live | [/.well-known/mcp.json](/.well-known/mcp.json) and [/.well-known/mcp-server-card.json](/.well-known/mcp-server-card.json), pointing at the live servers on mcp.veezee.io. | | [A2A agent card](https://specification.website/spec/agent-readiness/a2a-agent-cards/) | Live | [/.well-known/agent-card.json](/.well-known/agent-card.json). Veezee does not run an A2A server; the card points A2A-aware crawlers at the MCP surface. | | [Agentic Resource Discovery](https://specification.website/spec/agent-readiness/agentic-resource-discovery/) | Live | [/.well-known/ai-catalog.json](/.well-known/ai-catalog.json), advertised by the Agentmap line in [/robots.txt](/robots.txt). | | [NLWeb](https://specification.website/spec/agent-readiness/nlweb/) | Not planned | MCP already gives agents a queryable interface with real auth and per-call pricing. An /ask endpoint would duplicate it. | | [WebMCP](https://specification.website/spec/agent-readiness/webmcp/) | Live | The forms on [/upgrade](/upgrade) and [/manage](/manage) are declared as WebMCP tools (toolname and tooldescription attributes, plus imperative registration where fields are sensitive). Nothing auto-submits. | | [OKF bundle](https://specification.website/spec/agent-readiness/okf-bundle/) | Not planned | The corpus already ships as Markdown: per-page index.md twins and [/llms-full.txt](/llms-full.txt). | | [Schemamap](https://specification.website/spec/agent-readiness/schemamap/) | Not planned | It indexes per-resource .jsonld endpoints. Our JSON-LD ships inline in every page, so there are no .jsonld endpoints to index. | ## Why this page exists Veezee sells LinkedIn, Reddit, and X data to AI agents, so the site is built agent-first: an agent should be able to discover, evaluate, connect, and pay with no human in the loop except the payment itself. The conventions above are how an agent finds its way in. If we are missing one you rely on, tell us: hello@veezee.io. --- # Terms of service - Veezee These terms cover use of veezee.io, api.veezee.io, and mcp.veezee.io ("Veezee"). Using the service means you accept them. Questions: [hello@veezee.io](mailto:hello@veezee.io). ## The service Veezee provides read-only, structured data from public LinkedIn, Reddit, and X (formerly Twitter) pages, over REST, MCP, a TypeScript SDK, and a CLI. Every tool reads; nothing is ever posted, messaged, or changed on any platform on your behalf. ## Keys and accounts API keys are created self-serve and shown once, at creation; Veezee stores only a hash. You are responsible for calls made with your keys. Attaching an email to a key adds recovery and management; the key works either way. ## Credits and payment Credits are prepaid. Only calls that return data spend credits: failed or unfulfilled calls are refunded to the balance automatically, and a retried call with the same `Idempotency-Key` is never billed twice. When credits run out, calls stop; you can never owe more than you paid. Payments run through Stripe Checkout; card details never touch Veezee. Unused purchased credits are refunded on request within 14 days ([hello@veezee.io](mailto:hello@veezee.io)). The monthly plan renews through Stripe and can be cancelled anytime at [/manage](/manage). ## Fair use The free budget is per IP per day so that anyone can evaluate the service without an account. Working around it (key farming, coordinated IP rotation) can get requests blocked. You are responsible for how you use retrieved data, including compliance with applicable law and the source platforms' terms. Don't use the service to harass or surveil individuals. ## Availability The service is provided as-is, without an uptime guarantee. To the extent permitted by law, Veezee's total liability is limited to the amount you paid in the twelve months before the claim. ## Changes We may update these terms; material changes are announced on the [changelog](/changelog). --- # Privacy - Veezee What Veezee stores, why, and what it never does. The longer operational version is on [/trust](/trust). Questions or deletion requests: [hello@veezee.io](mailto:hello@veezee.io). ## What we store - **API traffic**: request and response bodies for up to 30 days, size-capped, so a retried call with the same `Idempotency-Key` returns the stored result instead of charging twice. Charge records (the ledger) are kept indefinitely: they are your billing history. - **Keys**: only a hash. The key itself is shown once and never stored. - **Email**: only if you sign in or claim a key. Used for sign-in codes, receipts, and the balance alerts you can turn off in the dashboard. - **Free-tier metering**: per-IP daily counters that enforce the free budget. - **Payments**: handled by Stripe. Card details never touch Veezee; we receive the order status and the checkout email. ## Analytics The site uses PostHog (EU-hosted) for page analytics: no session recording, query strings stripped before sending, no advertising cookies. Signing in sets one session cookie, which is required for the dashboard to work. Operational telemetry uses opaque, hashed identifiers, never personal information. ## What we never do We don't sell personal data, we don't put personal information in telemetry, and we don't show ads. ## Your choices Revoke or rotate keys anytime in the [dashboard](/dashboard). To delete an account and its stored data, email [hello@veezee.io](mailto:hello@veezee.io). Unused purchased credits are refunded on request within 14 days. --- # Changelog - Veezee ## 2026-07-17: Skills, integration guides, solution pages, status Two new skill packs: `launch-sentiment-sweep` (one-shot Reddit and X reaction readout for a launch) and `outreach-list-builder` (ICP spec to ranked outreach list), making eight. Integration guides at https://veezee.io/integrations for Claude Code, Codex CLI, Cursor, and Gemini CLI, each ending with a copy-paste verification prompt. Four solution pages: https://veezee.io/social-listening-api, https://veezee.io/lead-generation-api, https://veezee.io/brand-monitoring-api, https://veezee.io/competitive-intelligence-api. Live service checks at https://veezee.io/status. ## 2026-07-16: MCP OAuth connector sign-in MCP clients that support the authorization spec now connect with zero keys: an unauthenticated request returns `401` with OAuth discovery, and the client opens a Veezee sign-in in the browser (one-time emailed code, no password, no card). Works with Claude Code, claude.ai, ChatGPT developer-mode connectors, and any compliant client; keyed connections work unchanged. Connected apps are listed and revocable in the dashboard. ## 2026-07-15: Free tier and a sign-in grant Every data tool now answers under a free budget of 200 credits per IP per day: no account, no card. Signing in adds a one-time grant of 10,000 credits, once per email, spent after the daily budget. ## 2026-07-14: Accounts and key management Sign in at https://veezee.io/login with a one-time emailed code (no password exists): dashboard, named keys, rotation and revocation, balance alerts, and self-serve lost-key recovery at https://veezee.io/recover. The CLI signs in with `vz login` (browser or `--device`). `vzm_` management tokens unlock the same surface over REST and MCP; spend keys stay data-only. The key spends; the identity governs. ## 2026-07-13: vz CLI alias, deeper comparisons SDK 0.3.1: the CLI answers to `vz` as well as `veezee`, and the npm package now ships all six agent skill packs including `reddit-monitoring`. The comparison pages (https://veezee.io/alternatives) now assess data access head-on (search shape, freshness disclosure, docs you can read before paying, refund behavior), with sentiment gathered under the free tier using Veezee's own `reddit_search` and `x_search`. Three new landing pages: https://veezee.io/linkedin-api-for-ai-agents, https://veezee.io/reddit-api-for-ai-agents, https://veezee.io/x-api-for-ai-agents. ## 2026-07-13: Reddit and X Reddit and X (formerly Twitter) join LinkedIn on the same contract: `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`, over the same MCP and REST pattern, priced per credit, free tier first. Per-platform docs: https://veezee.io/docs/linkedin, https://veezee.io/docs/reddit, https://veezee.io/docs/x. ## 2026-07-12: v1 launch Veezee opens with LinkedIn: six tools (`linkedin_resolve_url`, `linkedin_get_profile`, `linkedin_search_people`, `linkedin_get_company`, `linkedin_get_posts`, `get_usage`) over MCP and REST (`GET /v1/linkedin/*`), priced per credit. No signup: your agent mints its own free key in one call, then calls run under a small shared per-IP daily budget (200 credits/day). Past that, buy a key at https://veezee.io/upgrade: pay, and checkout credits the same key. --- # Social listening API - Veezee Social listening means watching what people say about a brand, product, or topic across public discussion, not just tracking official accounts. Most teams want the raw posts and comments so their own pipeline or agent can score sentiment, cluster themes, or spot a spike; a vendor's canned sentiment label just gets in the way. ## How to do it with Veezee Veezee gives an agent three tools for this. [reddit_search](https://veezee.io/docs/tools/reddit_search) with `type=comments` reaches comment-level mentions inside discussions, not just post titles. [x_search](https://veezee.io/docs/tools/x_search) sweeps X chronologically for a query, following the cursor for as many pages as the sweep needs. [reddit_get_subreddit_posts](https://veezee.io/docs/tools/reddit_get_subreddit_posts) reads one community's feed directly, useful once you know where the conversation happens (a product's own subreddit, a niche community). None of these return a sentiment score: every result carries the raw text, author, upvotes or likes, and timestamp, and your agent runs its own analysis on that. No signup: your agent mints its own free key in one call, then uses it directly. ```sh curl -s -X POST https://api.veezee.io/v1/keys/mint | jq -r .key curl "https://api.veezee.io/v1/reddit/search?query=your-brand&type=comments" -H "Authorization: Bearer $VEEZEE_API_KEY" ``` ## FAQ **Does Veezee score sentiment for me?** No. Every response carries the raw post or comment text plus upvotes, comment counts, and timestamps; your agent runs its own sentiment analysis on that text. **Can I get notified the moment someone posts about my brand?** Not automatically: there's no push mechanism. Poll reddit_search or x_search on your own schedule (`sort=new` for Reddit, `type=recent` for X) and diff against what you've already seen. **How far back does the search go?** reddit_search has no server-side time window on comment search, so filter results on `created_at` yourself; x_search takes `since:`/`until:` query operators for time windows directly. **What's a realistic setup for checking this daily?** A handful of narrow comment searches plus one subreddit poll and one X sweep, costed out step by step in the recipe below. ## Read next - Worked recipe with real credit costs: [/use-cases/brand-monitoring](https://veezee.io/use-cases/brand-monitoring) - Full docs: [/docs](https://veezee.io/docs) - Credit prices and packs: [/pricing](https://veezee.io/pricing) - Buy credits: [/upgrade](https://veezee.io/upgrade) --- # Lead generation API - Veezee Lead generation means turning a target list, a role, a company, an industry, into named people with enough context to reach out to. That means finding candidates who match, then pulling the profile detail (title, company, background) needed to personalize outreach, without a human clicking through LinkedIn by hand. ## How to do it with Veezee [linkedin_search_people](https://veezee.io/docs/tools/linkedin_search_people) finds people by keywords, title, school, or current/past company; give it a role and a company and it returns names, positions, locations, and a urn for each match. [linkedin_get_profile](https://veezee.io/docs/tools/linkedin_get_profile) takes one of those results (or a known profile URL) and returns the full profile: headline, location, current position, follower counts, plus up to two extra sections (experience, education, skills, about) at no extra cost. [linkedin_get_company](https://veezee.io/docs/tools/linkedin_get_company) resolves a company by URL, slug, or website domain, and returns the numeric id linkedin_search_people needs to filter results down to that one company. No signup: your agent mints its own free key in one call, then uses it directly. ```sh curl -s -X POST https://api.veezee.io/v1/keys/mint | jq -r .key curl "https://api.veezee.io/v1/linkedin/search?keywords=VP%20of%20Sales¤t_company=acme.com" -H "Authorization: Bearer $VEEZEE_API_KEY" ``` ## FAQ **Can I get an email address or phone number?** No. Veezee returns what LinkedIn's profile shows publicly (name, headline, position, history); it does not return contact details. **Can I search by company name directly?** For search, yes: linkedin_search_people's `current_company` filter resolves a plain company name for you. linkedin_get_company itself doesn't search by name; give it a URL, slug, or website domain instead. **How many results does one search return?** Up to 30 per call (10 on a trial key); a cursor page is a new, separately priced call, so one larger `limit` is cheaper than several small pages. **Can Veezee message or connect with these people for me?** No. Every LinkedIn tool is read-only: no posting, commenting, or messaging. ## Read next - Worked recipe with real credit costs: [/use-cases/prospect-enrichment](https://veezee.io/use-cases/prospect-enrichment) - Full docs: [/docs](https://veezee.io/docs) - Credit prices and packs: [/pricing](https://veezee.io/pricing) - Buy credits: [/upgrade](https://veezee.io/upgrade) --- # Brand monitoring API - Veezee Brand monitoring means tracking mentions of a brand, product, or executive across public discussion, and being able to drill into any one thread when something looks worth a closer look, not just counting mentions. ## How to do it with Veezee [x_search](https://veezee.io/docs/tools/x_search) sweeps X for a brand's name or handle, chronologically or by engagement. [reddit_search](https://veezee.io/docs/tools/reddit_search) with `type=comments` finds mentions inside Reddit discussions, not just post titles. When one thread is worth reading in full, [reddit_get_post](https://veezee.io/docs/tools/reddit_get_post) fetches that post's full body and, with `detail=full`, the entire comment tree in context, so an agent can follow up on a specific complaint or compliment instead of guessing from a one-line summary. No signup: your agent mints its own free key in one call, then uses it directly. ```sh curl -s -X POST https://api.veezee.io/v1/keys/mint | jq -r .key curl "https://api.veezee.io/v1/x/search?query=%22your-brand%22&type=recent" -H "Authorization: Bearer $VEEZEE_API_KEY" ``` ## FAQ **Can I set up an ongoing monitor that runs itself?** Not automatically: run the searches on your own schedule, a daily cron job, an agent loop. There's no built-in recurring job. **How do I read the full discussion under a Reddit post I found in search results?** Take the post's `t3_` id from reddit_search or reddit_get_subreddit_posts and call reddit_get_post with `detail=full`; it returns the comment tree in depth order. **Does this include a sentiment score per mention?** No. Every result is the raw post or comment text plus its engagement numbers; scoring sentiment is up to your agent. **Is there a cheaper way to check one specific community every day?** reddit_get_subreddit_posts with `sort=new` reads that community's feed directly for a flat per-page price, cheaper than a broad keyword search once you already know where the conversation happens. ## Read next - Worked recipe with real credit costs: [/use-cases/brand-monitoring](https://veezee.io/use-cases/brand-monitoring) - Full docs: [/docs](https://veezee.io/docs) - Credit prices and packs: [/pricing](https://veezee.io/pricing) - Buy credits: [/upgrade](https://veezee.io/upgrade) --- # Competitive intelligence API - Veezee Competitive intelligence means tracking what a competitor's company page says about itself, what its people are posting, and what the public is saying about it elsewhere, pulled into one picture instead of five open tabs. ## How to do it with Veezee [linkedin_get_company](https://veezee.io/docs/tools/linkedin_get_company) fetches a competitor's LinkedIn page: description, industry, employee count, headquarters, and the id needed for further LinkedIn calls. [linkedin_get_posts](https://veezee.io/docs/tools/linkedin_get_posts) reads that same company's (or one exec's) recent posts, the voice-of-company signal: what they're announcing, hiring for, or talking about. [reddit_search](https://veezee.io/docs/tools/reddit_search) and [x_search](https://veezee.io/docs/tools/x_search) then cover what's said about the competitor outside its own channels, on Reddit and X respectively. No signup: your agent mints its own free key in one call, then uses it directly. ```sh curl -s -X POST https://api.veezee.io/v1/keys/mint | jq -r .key curl "https://api.veezee.io/v1/linkedin/posts?identifier=competitor.com" -H "Authorization: Bearer $VEEZEE_API_KEY" ``` ## FAQ **Can I search LinkedIn posts by keyword across the whole platform?** No. linkedin_get_posts returns one company or person's recent posts; there's no keyword search across LinkedIn in v1. **How do I avoid guessing the wrong company page?** Pass the competitor's website domain (e.g. `acme.com`) instead of guessing a slug from the brand name. Veezee resolves and verifies the domain against the company it returns; a famous brand name can otherwise point at an unrelated page. **Does this include job listings or funding data?** No. linkedin_get_company returns the company's own profile fields (industry, headcount, HQ, specialities); it does not return job listings. **What's a reasonable cadence for this?** A weekly check on a handful of companies (a company fetch plus a recent-posts page each) is the recipe below; run it more often around a launch or news cycle. ## Read next - Worked recipes with real credit costs: [/use-cases/market-research](https://veezee.io/use-cases/market-research) and [/use-cases/company-research](https://veezee.io/use-cases/company-research) - Full docs: [/docs](https://veezee.io/docs) - Credit prices and packs: [/pricing](https://veezee.io/pricing) - Buy credits: [/upgrade](https://veezee.io/upgrade) --- # SDK - Veezee docs Typed TypeScript client for the Veezee REST API: LinkedIn, Reddit, and X (formerly Twitter) data behind one client. Zero runtime dependencies, built on Node 20's global `fetch`. Package home: [@veezee/sdk on npm](https://www.npmjs.com/package/@veezee/sdk); source: [veezeehq/veezee-sdk on GitHub](https://github.com/veezeehq/veezee-sdk). ## Install ``` npm install @veezee/sdk ``` Node 20+ required. The package also ships the [`veezee` CLI](/docs/cli) (short alias: `vz`) and the [agent skill packs](/docs/skills). ## Quickstart ```ts import { VeezeeClient } from "@veezee/sdk"; const client = new VeezeeClient(); // finds your key: constructor option, VEEZEE_API_KEY, or ~/.veezee/config const profile = await client.linkedin.getProfile({ identifier: "williamhgates" }); const chatter = await client.reddit.search({ query: "notion alternative", type: "comments" }); const tweets = await client.x.getTweets({ identifier: "nasa" }); ``` No key yet? `await client.mint()` creates a free one and saves it to `~/.veezee/config` (same store `npx @veezee/sdk init` writes). The free key includes 200 credits per IP per day. Need more? `client.checkout({ pack: "flex" })` (or [/upgrade](/upgrade) in a browser) adds credits to the same key, so nothing needs reconfiguring. Already have a key? `new VeezeeClient({ apiKey: process.env.VEEZEE_API_KEY })`. ## The methods One method per tool, same names and envelopes as the REST contract (https://veezee.io/openapi.json). Every data response carries `usage` with the receipt id, credits charged, and balance. LinkedIn, under `client.linkedin` ([platform docs](/docs/linkedin)): - `getProfile`: a person's profile with named sections (about, experience, education, skills) - `searchPeople`: people search with typed filters (title, current or past company, school, keywords) - `getCompany`: a company page by URL, slug, or website domain - `getPosts`: recent posts by a person or company Reddit, under `client.reddit` ([platform docs](/docs/reddit)): - `search`: search posts, comments, subreddits, or users - `getSubreddit`: subreddit details, optionally including settings - `getSubredditPosts`: one page of a subreddit's posts, by sort - `getUser`: a Reddit user, with optional comments, posts, and subreddits sections - `getPost`: posts by id, optionally with the full discussion thread - `resolveUrl`: identify a Reddit URL X, under `client.x` ([platform docs](/docs/x)): - `search`: search recent or popular tweets, or people - `getProfile`: a profile with follower and tweet counts - `getTweets`: an account's tweets by mode (posts, posts and replies, highlights) - `getTweet`: one tweet with full engagement metrics - `resolveUrl`: identify an X URL Top-level on the client: - `resolveUrl`: identify a LinkedIn URL (person, company, or post) - `getUsage`: credits, plan, and recent charges; free, requires a key - `checkout`: buy a key or add credits ## Retries and idempotency The client retries RATE_LIMITED, CONCURRENCY_LIMIT, UPSTREAM_UNAVAILABLE, INTERNAL, and network failures up to 3 attempts with backoff, honoring retry_after_seconds. Each metered call gets one Idempotency-Key reused across its own retries, so retries never double-charge. Terminal errors throw `VeezeeError` with the same code/message/param shape the API returns, including `offer` and `credits_required` on payment-fixable errors. --- # CLI - Veezee docs The `veezee` CLI ships inside [@veezee/sdk](https://www.npmjs.com/package/@veezee/sdk): the same tools as REST and MCP, as `vz ` subcommands across LinkedIn, Reddit, and X, with JSON output via `--json`. `vz` is the same binary, three keystrokes shorter. `vz init` creates a free key in one call (no account needed) and saves it to `~/.veezee/config`; every command then runs under the free budget of 200 credits per IP per day on all three platforms. Need more? Buy credits at [/upgrade](/upgrade): checkout credits the same key. ## Install ``` npm install -g @veezee/sdk ``` ## Commands ``` vz init mint a free key (no signup) and save it to ~/.veezee/config vz linkedin profile get fetch a person's LinkedIn profile vz linkedin search [flags] search people on LinkedIn vz linkedin company get fetch a company's LinkedIn page vz linkedin posts get fetch recent posts by a person or company vz reddit search [flags] search Reddit posts, comments, subreddits, or users vz reddit subreddit [flags] fetch subreddit details vz reddit subreddit-posts fetch a subreddit's posts vz reddit user [flags] fetch a Reddit user vz reddit post [flags] fetch Reddit posts by id, with optional discussion thread vz reddit resolve-url identify a Reddit URL vz x search [flags] search X (formerly Twitter) vz x profile [flags] fetch an X profile vz x tweets [flags] fetch an account's tweets vz x tweet fetch one tweet with full metrics vz x resolve-url identify an X URL vz resolve-url identify a LinkedIn URL (person/company/post) vz usage check credits, plan, and recent charges (requires a key) ``` ## Examples ``` vz linkedin profile get williamhgates --sections experience,education vz linkedin search --keywords "CTO" --company anthropic --limit 20 vz linkedin company get microsoft --json vz reddit search "notion alternative" --type comments vz reddit subreddit selfhosted --include-settings vz reddit post t3_1tbups6,t3_1tbuneg vz x search "claude code" vz x profile nasa vz x tweets nasa --mode posts_and_replies --no-retweets vz usage --key vz_live_... --json ``` ## Flags `--json` prints the raw response envelope. `--key ` sets the API key (else reads `VEEZEE_API_KEY`, or the key `vz init` saved to `~/.veezee/config`; omit entirely to run under the free per-IP budget). `--base-url ` overrides the API base URL. Per command: `linkedin profile get` takes `--sections a,b` and `--realtime`; `linkedin search` takes `--keywords`, `--title`, `--company`, `--past-company`, `--school`, `--first-name`, `--last-name`, `--limit`, `--cursor`, `--freshness`; `reddit search` takes `--type posts|comments|subreddits|users`, `--sort`, `--range`, `--cursor`; `reddit post` takes `--detail concise|full`, `--comment-id`; `x search` takes `--type recent|popular|people`; `x tweets` takes `--mode posts|posts_and_replies|highlights` and `--no-retweets`. Every data command takes `--max-credits ` (per-call spend cap; an over-quote call fails with nothing charged). Unknown flags are a hard usage error (exit 2), never silently ignored. `--json` applies to errors too: the machine-readable error shape prints to stdout. Run `vz --help` for the full list. Exit codes: 0 success, 1 failure, 2 usage error (bad command, unknown flag, or INVALID_INPUT from the API), 4 auth required (no key, or UNAUTHORIZED/NOT_ENTITLED from the API). --- # Candidate sourcing - Veezee Candidate sourcing finds people who match a role at a target company, then fetches full profiles for the top matches. ## Recipe 1. No signup: mint a free key (`POST /v1/keys/mint`, no body) and call every step below under a shared budget of 200 credits per IP per day. Hit the cap, or need `limit: 30`? Buy a key at [/upgrade](/upgrade); checkout credits the same key. 2. `linkedin_get_company`: resolve the target company once, by URL, slug, or numeric id. Returns the company's numeric id and URN for the search filter. Cost: 4 credits. 3. `linkedin_search_people`: filter by `title` and `current_company` (the numeric id from step 2), `limit: 30`. Returns matches, each flagged `is_anonymous` if private. Cost: 12 credits. 4. `linkedin_get_profile`: for the top 10 non-anonymous results, fetch with `sections: ["experience", "education"]`. Cost: 4 credits per call, 40 credits for 10. Skip any result with `is_anonymous: true`; `linkedin_get_profile` cannot dereference a private profile. Treat the search match itself as confirmation and move on. ## Total cost 56 credits for one company lookup, one search at limit 30, and 10 profile fetches. ## Limits worth knowing - Free-key calls and trial keys cap search at 10 results per call; the `limit: 30` step needs a paid key. - Pass the company's numeric id (from linkedin_get_company) when you want `limit: 30`; a company NAME filter with limit 30 is rejected. - One search at a higher limit costs less than several at a low limit; a cursor page is priced fresh by its own limit, so paging does not save credits. - With a paid key, call `get_usage` (free, exempt from the rate limit) before a large batch to check balance; a free key has no account balance to check, but each response reports its own cost. ## Run it Full reference: [/docs](/docs). A ready-made agent setup prompt: [/agent-setup/prompt.md](/agent-setup/prompt.md). --- # Prospect enrichment - Veezee Prospect enrichment turns a list of known profile identifiers into full profile data (role, current company, experience) for people you have already identified. ## Recipe 1. Try one lead free first: no signup, mint a key with `POST /v1/keys/mint` and call under a shared budget of 200 credits per IP per day. A batch of 100 leads needs more than that; buy a key at [/upgrade](/upgrade) before running the full batch, checkout credits the same key. 2. `linkedin_resolve_url` (optional): only for a dirty or ambiguous profile URL. A clean URL, slug, or URN goes straight to `linkedin_get_profile`. Cost: 2 credits. 3. `linkedin_get_profile`: one call per lead, with `sections: ["experience"]`. The first two sections are included in the base fetch; each section past two adds 2 credits, up to 4 sections total. Cost: 4 credits per lead. 4. `get_usage`: free, exempt from the rate limit, once you have a key. Check balance before a large batch instead of finding out mid-run. ## Total cost 400 credits for 100 leads at one section each, within the two included sections. ## Limits worth knowing - Realtime fetches need a paid key: a free key always serves cached (`recent`) data. On a paid key, `freshness: "realtime"` adds 2 credits per call, refunded automatically if the live fetch falls back to cached data. - Skip `linkedin_resolve_url` for identifiers you already trust; it spends 2 credits for nothing on a clean URL. - A profile flagged `is_anonymous: true` in a search result is private; `linkedin_get_profile` cannot dereference it. - Set `max_credits` on a call to cap its own spend; if the quote would exceed it, nothing is charged and the error carries `credits_required` (the exact quote) so you can decide with numbers, not prose. The cap survives into `next_url`, so paging stays capped. --- # Company research - Veezee Company research pulls a company's profile and its recent posts, for a single lookup or a repeating watchlist check. ## Recipe 1. A single check runs free: no signup, mint a key with `POST /v1/keys/mint` and call under a shared budget of 200 credits per IP per day. A recurring, scheduled watchlist needs more than that; buy a key at [/upgrade](/upgrade) first, checkout credits the same key. 2. `linkedin_get_company`: one call per company, by URL, slug, or numeric id. Returns name, size, industry, founding year, specialities, and the ids other tools use. Cost: 4 credits per company. 3. `linkedin_get_posts`: same identifier, one page per company. Returns recent posts with engagement counts. Cost: 4 credits per company; each further page is priced the same. 4. `get_usage`: free, exempt from the rate limit, once you have a key. Check balance before the next scheduled run. ## Total cost 40 credits for a 5-company check, one company fetch and one post page each. ## Limits worth knowing - A paid key draws down the same balance each scheduled run, so budget across runs, not just within one. - Realtime fetches need a paid key: a free key always serves cached (`recent`) data. On a paid key, `freshness: "realtime"` adds 2 credits to a call, refunded automatically on cached fallback. The default (`recent`) is free and usually a few hours old. - A second page of posts costs the same as the first; pull only what you need. - Set `max_credits` on a call to cap its own spend before it happens. --- # Brand monitoring - Veezee Brand monitoring finds the sentences where people compare, complain, and recommend, checks the brand's home community, and sweeps X for volume. ## Recipe 1. No signup: mint a free key (`POST /v1/keys/mint`, no body) and call every step below under a shared budget of 200 credits per IP per day. Running this daily needs more than that; buy a key at [/upgrade](/upgrade) first, checkout credits the same key. 2. `reddit_search` with `type: "comments"`: run a few narrow queries for the brand name and its common nicknames or misspellings. There is no server-side time window on comment search, so filter results on `created_at` yourself. Cost: 6 credits per query page. 3. `reddit_get_subreddit_posts` with `sort: "new"`: poll the brand's home community (or its category subreddit) for new posts. Cost: 4 credits per page. 4. `x_search` with `type: "recent"`: sweep X for the same brand terms, the deep chronological mode. Cost: 6 credits per page. 5. `get_usage`: free, exempt from the rate limit, once you have a key. Check balance before a scheduled run. ## Total cost A daily sweep of 3 comment searches, 1 subreddit poll, and 1 X sweep: 28 credits/day. ## Limits worth knowing - Comment search has no time-window parameter; filter on `created_at` client-side and re-poll with `sort: "new"` for fresh mentions. - Reddit's discover depth caps around a few hundred results per query; several narrow queries beat one broad one. - Cached search results refresh on a 20-minute cycle: polling faster than that replays the same page. - X search paginates as far as you follow the cursor, so a deep sweep costs linearly in pages; budget for that before running one. ## Run it Platform docs: [/docs/reddit](/docs/reddit) and [/docs/x](/docs/x). Full reference: [/docs](/docs). --- # Market research - Veezee Market research finds the communities and accounts already talking about a space, sizes them, and profiles whoever is loudest. ## Recipe 1. No signup: mint a free key (`POST /v1/keys/mint`, no body) and call every step below under a shared budget of 200 credits per IP per day. Buy a key at [/upgrade](/upgrade) once you need more; checkout credits the same key. 2. `reddit_search` with `type: "subreddits"`: find communities discussing the topic. Cost: 6 credits per page. 3. `reddit_get_subreddit`: size each candidate community by subscriber and active-user counts, the standard sizing signal. Cost: 4 credits per community. 4. `x_search` with `type: "people"`: find X accounts talking about the topic. Single page, no cursor. Cost: 6 credits. 5. `reddit_get_user` and `x_get_profile`: profile the loudest voices found above before quoting or engaging them. Cost: 4 credits per Reddit user, 4 credits per X account. ## Total cost 48 credits for one subreddit-discovery page, sizing 3 candidate communities, one X people search, and profiling 3 loud voices on each platform. ## Limits worth knowing - Reddit's discover result depth caps around a few hundred per query; decompose a broad market into several narrower queries. - `x_search` with `type: "people"` returns a single page with no cursor: it is a scan, not an exhaustive directory. - `reddit_get_user` and `x_get_profile` need an exact username or handle; use the search results' author/handle fields directly, don't guess one. ## Run it Platform docs: [/docs/reddit](/docs/reddit) and [/docs/x](/docs/x). Full reference: [/docs](/docs). --- # Agent skills - Veezee docs Skills are SKILL.md instruction packs your agent installs once and reuses: each pack teaches a recurring job (inputs, tool sequence, budget rules) on top of the Veezee tools. All packs live in [veezeehq/veezee-skills on GitHub](https://github.com/veezeehq/veezee-skills) and ship inside the [@veezee/sdk npm package](https://www.npmjs.com/package/@veezee/sdk). ## Install From GitHub: ``` npx skills add veezeehq/veezee-skills ``` Or from the npm package, after `npm install @veezee/sdk`: ``` npx skills add ./node_modules/@veezee/sdk/skills ``` Or copy the raw SKILL.md into your project's skills directory. ## Available skills - prospect-enrich: enrich known prospects with current role, company, and experience data, with per-run credit budget rules. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/prospect-enrich/SKILL.md) - candidate-sourcing: turn a role spec (title, company, school) into a ranked, enriched shortlist. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/candidate-sourcing/SKILL.md) - company-enrichment: enrich a batch of companies (URLs, slugs, or website domains) with firmographics. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/company-enrichment/SKILL.md) - account-research: one-account pre-outreach briefing: company facts, key people, recent posts. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/account-research/SKILL.md) - post-voice-research: what a person or company posts about: topics, tone, cadence. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/post-voice-research/SKILL.md) - reddit-monitoring: watch subreddits and comment chatter for a brand, product, or topic, with budget rules. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/reddit-monitoring/SKILL.md) - launch-sentiment-sweep: one-shot Reddit and X reaction readout for a launch or announcement: volume, quotes, themes, notable accounts. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/launch-sentiment-sweep/SKILL.md) - outreach-list-builder: turn an ICP spec into a ranked outbound sales list with company context and opener hooks. [SKILL.md](https://github.com/veezeehq/veezee-skills/blob/main/skills/outreach-list-builder/SKILL.md) The repo install carries all eight packs; the npm package bundles the packs at its release date (six as of SDK 0.6.1). ## Machine index Agents can enumerate the packs at https://veezee.io/.well-known/agent-skills/index.json. Truth rule: a skill only instructs what the shipped tools actually do; every pack is validated in CI (frontmatter shape, forbidden-vocabulary scan). --- # Evidence - Veezee Public results of the Veezee tool-selection eval: does a fresh-context model pick the right Veezee tool, emit a valid first call, and read a real response envelope correctly? Machine-readable twin: [/evidence/tool-selection-eval.json](/evidence/tool-selection-eval.json). ## Method Anthropic tool-eval rubric, three axes, graded by three fresh-context subagents. Picker sees ONLY the tool names + descriptions and a realistic user ask, and must name the right tool with no args. First-call-success sees names + descriptions + params and must emit the exact first call (tool + JSON args), validated against the frozen zod schemas. Response-usability sees a real production response envelope and must answer the user's question from it and name its next action. No agent saw the expected answers. All results reflect the shipped tool descriptions as of the run date. Models: picker Haiku (the smallest model the descriptions must survive), first-call Sonnet, response-usability Sonnet. Run date: 2026-07-11. ## Scope: what this does and doesn't measure This eval measures tool-selection and first-call / response-envelope usability only: whether a model picks the right tool for a realistic ask, emits a valid first call, and can read and act on a real response envelope. It does NOT measure data quality, coverage, or freshness, and it does NOT measure API availability or latency. It covers the LinkedIn toolset (five LinkedIn tools plus get_usage); the Reddit and X tools shipped after this run and have not yet been through this eval. ## Picker: 13/13 | Case | Ask | Expected | Selected | Result | | --- | --- | --- | --- | --- | | P1 | Find the LinkedIn profile of the CTO of Datadog. | linkedin_search_people | linkedin_search_people | pass | | P2 | What has Anthropic been posting on LinkedIn recently? | linkedin_get_posts | linkedin_get_posts | pass | | P3 | Pull the full work history for linkedin.com/in/satyanadella. | linkedin_get_profile | linkedin_get_profile | pass | | P4 | How many employees does Stripe have on LinkedIn? | linkedin_get_company | linkedin_get_company | pass | | P5 | A user pasted this link, what is it? https://www.linkedin.com/company/openai/?utm_source=chatgpt | linkedin_resolve_url or linkedin_get_company | linkedin_resolve_url | pass | | P7 | How many credits do I have left? | get_usage | get_usage | pass | | P8 | Find software engineers at Shopify who used to work at Amazon. | linkedin_search_people | linkedin_search_people | pass | | P9 | Get the education history of williamhgates. | linkedin_get_profile | linkedin_get_profile | pass | | P10 | I only have the website vercel.com. Get their LinkedIn company info. | linkedin_get_company | linkedin_get_company | pass | | P11 | Did Bill Gates post anything about malaria this month? | linkedin_get_posts | linkedin_get_posts | pass | | P12 | Look up the profile of the person named 'Jordan Rivera' who works at Datadog. | linkedin_search_people | linkedin_search_people | pass | | P13 | Check whether my key is still valid and what plan I'm on. | get_usage | get_usage | pass | | P14 | Read this specific post for me: https://www.linkedin.com/feed/update/urn:li:activity:7123456789/ | linkedin_resolve_url or none | none | pass | ## First-call success: 8/8 | Case | Ask | Tool | Args | Result | | --- | --- | --- | --- | --- | | F1 | Pull the work history for linkedin.com/in/satyanadella. | linkedin_get_profile | `{"identifier":"linkedin.com/in/satyanadella","sections":["experience"]}` | pass | | F2 | Find software engineers at Shopify who used to work at Amazon. | linkedin_search_people | `{"title":"Software Engineer","current_company":"Shopify","past_company":"Amazon"}` | pass | | F3 | I only have the website vercel.com. Get their LinkedIn company info. | linkedin_get_company | `{"identifier":"vercel.com"}` | pass | | F4 | What has Anthropic been posting on LinkedIn recently? | linkedin_get_posts | `{"identifier":"anthropic"}` | pass | | F5 | Get the education history of williamhgates. | linkedin_get_profile | `{"identifier":"williamhgates","sections":["education"]}` | pass | | F6 | Search up to 30 results for CTOs at Anthropic, but do not spend more than 15 credits on the call. | linkedin_search_people | `{"keywords":"CTO Anthropic","title":"CTO","limit":30,"max_credits":15}` | pass | | F7 | Get LinkedIn company info for microsoft.com with a hard 6-credit ceiling. | linkedin_get_company | `{"identifier":"microsoft.com","max_credits":6}` | pass | | F8 | (a LinkedIn company URL passed as the identifier) | linkedin_get_company | `{}` | pass | Notes on the hard cases: **F3** Website domains are first-class identifiers: the domain reaches the company in one call, zero extra turns. **F6** The hard case: a result cap plus a hard credit ceiling. The model followed the description's budget rule (quote 12 <= max_credits 15) and avoided the company-name-filter-plus-3-pages combination the planner rejects; the server's teaching error remains the safety net for agents that miss it. **F7** Correctly predicted from the published prices that domain resolution quotes 8 credits, exceeding max_credits=6, and expected the call to reject uncharged. **F8** Passed the LinkedIn URL straight through as identifier, without misrouting it through linkedin_resolve_url first. ## Response usability: 3/3 | Case | Ask | Envelope source | Result | | --- | --- | --- | --- | | U1 | How many employees does Microsoft have on LinkedIn, and what industry is it in? | production linkedin_get_company identifier=microsoft | pass | | U2 | How many credits do I have left and what did my last few calls cost? | production get_usage | pass | | U3 | Find CTOs at Anthropic; I will want their profiles next. | production linkedin_search_people keywords=CTO current_company=1035 limit=10 | pass | Note on U3: the eval's own input envelope was a Microsoft-id search mislabeled "Anthropic". The pass is the model catching that mismatch from the envelope's echoed current_company field and refusing to spend credits on wrong-company fetches; the full grading note is in the JSON twin. ## 30-day availability and latency Pending. Synthetics-derived 30-day availability and p50/p95 latency have not accumulated enough data yet. This section will be filled in once that monitoring window closes; no numbers are published here in the meantime. ## Verdict Descriptions pass the picker axis on a small fast model (Haiku) and the first-call axis on a mid-size model (Sonnet). The hardest cases (a result cap combined with a hard credit ceiling; a website domain as the only identifier) pass on the first call with the shipped descriptions.