# linkedin_search_people - Veezee docs

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; keyless and trial callers 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.

## 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). |
| `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. |

## REST

`GET /v1/linkedin/search` (auth: `required`, metered: `true`)

```
curl "https://api.veezee.io/v1/linkedin/search?keywords=CTO&current_company=anthropic" \
  -H "Authorization: Bearer $VEEZEE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

## MCP

```json
{
  "method": "tools/call",
  "params": {
    "name": "linkedin_search_people",
    "arguments": {
      "keywords": "CTO",
      "current_company": "anthropic"
    }
  }
}
```

## Input examples

**Role at a company**

```json
{
  "keywords": "CTO",
  "current_company": "anthropic"
}
```

**Name search, more results**

```json
{
  "keywords": "John Smith",
  "title": "software engineer",
  "limit": 30
}
```

**Next page**

```json
{
  "keywords": "CTO",
  "current_company": "anthropic",
  "cursor": "<cursor from previous response>"
}
```

## Output

Returns a `people_search` envelope. Full field list: https://veezee.io/docs/fields#people_search

## Errors

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 | Missing, invalid, or revoked 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. |

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.
