# Searching Parlel as an agent

Parlel is a professional network with three public, searchable collections:
**people**, **companies** and **jobs**. Everything on this page is anonymous,
free, and returns JSON. No key, no sign-up, no rate-limit headers to negotiate.

This is the prose version. The machine version is
<https://api.parlel.com/api/public/index>, which is generated from the routes
that actually exist and lists every parameter below; if the two disagree, the
index is right and this page is late.

## If your client speaks MCP

Add this URL as a remote MCP server — Claude Desktop, Cursor, ChatGPT,
Windsurf, or anything else that takes one:

```
https://api.parlel.com/mcp
```

Streamable HTTP, stateless, no auth. It exposes `search_jobs`, `get_job`,
`search_companies`, `get_company`, `search_people`, `get_person`,
`search_agents` and `get_agent` as typed tools with the same parameters as the
JSON below, plus this guide as a resource. Everything else on this page is for
when you would rather call HTTP yourself.

## The one-paragraph version

Each collection has a JSON list at `https://api.parlel.com/api/public/…` and a
human page at `https://parlel.com/…`. **They take the same query parameters
under the same names**, so a JSON URL becomes the page a person would see by
changing the host and path and nothing else:

| Collection | JSON list                                   | Human page                    |
| ---------- | ------------------------------------------- | ----------------------------- |
| People     | `api.parlel.com/api/public/profiles`        | `parlel.com/people`           |
| Companies  | `api.parlel.com/api/public/companies`       | `parlel.com/companies`        |
| Jobs       | `api.parlel.com/api/public/roles`           | `parlel.com/jobs`             |
| Agents     | `api.parlel.com/api/public/agents`          | `parlel.com/explore`          |

Every list returns `{"items": [...], "next_cursor": "..." | null}`. Pass
`next_cursor` back as `?cursor=` for the next page; `null` is the end. Filters
are AND-ed. Text matching is a case-insensitive substring; there is no ranking,
no fuzziness and no stemming, so search for the word you expect to appear.

## Jobs

```
GET https://api.parlel.com/api/public/roles
```

Every **open** role at every company with a published page, newest first.

| Parameter   | Values                                                          | Matches                                                                                  |
| ----------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `q`         | text, ≤120 chars                                                | The **title only**. Not the description, not the skills, not the company name.          |
| `remote`    | `onsite` · `hybrid` · `remote`                                  | Working arrangement.                                                                     |
| `seniority` | `intern` · `junior` · `mid` · `senior` · `staff` · `principal` · `exec` | Level.                                                                            |
| `comp_min`  | integer                                                         | Roles whose published range reaches this. Roles with **no published pay are excluded** when set. |
| `limit`     | 1–60, default 12                                                |                                                                                          |
| `cursor`    | opaque                                                          | From `next_cursor`.                                                                      |

```sh
# Remote senior roles, sixty at a time
curl 'https://api.parlel.com/api/public/roles?remote=remote&seniority=senior&limit=60'

# Titles containing "backend"
curl 'https://api.parlel.com/api/public/roles?q=backend'
```

Each item is the role as a structured record — `title`, `location`, `remote`,
`employment_type`, `seniority`, `comp_min`, `comp_max`, `comp_currency`,
`comp_period`, `skills`, `published_at`, `role_url` — plus a `company` object
with `handle`, `name` and `company_url`.

One role: `GET /api/public/roles/{role_id}`, or `role_url` with `.json`
appended. **A closed role keeps its URL** (agent findings cite them, and a
citation that 404s looks fabricated) but is not in the list, not in any sitemap,
and its HTML page carries no `JobPosting` block. Read `status`.

Because `q` matches the title only, a description-level search is a two-step
job: list with the structural filters, then fetch each `role_url` + `.json` and
read `description` and `skills` yourself.

## Companies

```
GET https://api.parlel.com/api/public/companies
```

| Parameter  | Values                                                                  | Matches                                          |
| ---------- | ----------------------------------------------------------------------- | ------------------------------------------------ |
| `q`        | text, ≤120 chars                                                        | `name`, `tagline` or `industry`.                 |
| `industry` | text, ≤80 chars                                                         | **Exact**, case-insensitive.                     |
| `size`     | `1-10` · `11-50` · `51-200` · `201-500` · `501-1000` · `1001-5000` · `5000+` | Headcount band.                             |
| `location` | text, ≤100 chars                                                        | Substring.                                       |
| `hiring`   | `true`                                                                  | Only companies with at least one open role.      |
| `limit`    | 1–60, default 12                                                        |                                                  |
| `cursor`   | opaque                                                                  |                                                  |

```sh
# Small fintechs in London that are hiring
curl 'https://api.parlel.com/api/public/companies?industry=Fintech&size=11-50&location=London&hiring=true'
```

Each item carries `handle`, `name`, `tagline`, `location`, `size`, `industry`,
`founded_year`, `website_url` and `open_role_count`. One company, with its open
roles inline: `GET /api/public/companies/{handle}`, or
`https://parlel.com/c/{handle}.json`.

`q=fin` and `industry=Fintech` are different questions. The first is
exploration; the second is a segment. Use the second when you know the label.

## People

```
GET https://api.parlel.com/api/public/profiles
```

Everyone with a published profile. Contact details are **never** in this list —
the field is absent from the response, not empty — so do not look for them
here.

| Parameter      | Values                                                          | Matches                                                                                                   |
| -------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `q`            | text, ≤120 chars                                                | `display_name`, `headline`, `company`, `role`, and work/education history (organisation, title, field). **Not bio, not skills.** |
| `skill`        | repeatable, ≤40 chars each, ≤20                                 | Exact tag, folded to lowercase, **AND-ed**. `?skill=rust&skill=go` means both.                            |
| `based_in`     | text, ≤100 chars                                                | Where the person **is**.                                                                                  |
| `location`     | text, ≤100 chars                                                | Where they are **or** where they would move to. A hiring question; prefer `based_in` for "who is here".    |
| `open_to_work` | `true`                                                          | Only people looking.                                                                                      |
| `seniority`    | `intern` … `exec` (as above)                                    | The level they **seek**, not the one they hold.                                                           |
| `remote`       | `onsite` · `hybrid` · `remote`                                  | The arrangement they **seek**.                                                                            |
| `comp_max`     | integer                                                         | People whose asking floor is at or below this.                                                            |
| `limit`        | 1–60, default 12                                                |                                                                                                           |
| `cursor`       | opaque                                                          |                                                                                                           |

```sh
# Rust and Go engineers in Berlin
curl 'https://api.parlel.com/api/public/profiles?skill=rust&skill=go&based_in=Berlin'

# Everyone who has worked at, or studied at, somewhere matching "atlassian"
curl 'https://api.parlel.com/api/public/profiles?q=atlassian'
```

Skills are their own parameter because `q` does not read them: a person whose
only mention of Python is in their skills list is found by `skill=python` and
missed by `q=python`.

One person: `GET /api/public/profiles/{handle}`, or
`https://parlel.com/u/{handle}.json`. Their posts:
`/api/public/profiles/{handle}/posts`.

## Agents

```
GET https://api.parlel.com/api/public/agents
```

Published watch agents — standing searches that people run against the open
web, with what they found. Parameters: `sort` (`recent` | `popular`), `limit`
(1–24), `cursor`. **There is no `q`.** With a few hundred agents, walk the list.
One agent with its findings: `/api/public/agents/{slug}`, or
`https://parlel.com/a/{slug}.json`.

## Paging, correctly

Cursors are keyset, ordered on `(created_at DESC, id DESC)`. A page boundary
cannot drop or repeat a row while new rows arrive, so it is safe to walk a whole
collection while people are publishing into it. Cursors are opaque, are not
portable between different filter sets, and a malformed one is a `400`.

```sh
url='https://api.parlel.com/api/public/roles?limit=60'
while [ -n "$url" ]; do
  page=$(curl -s "$url")
  echo "$page" | jq -c '.items[]'
  cursor=$(echo "$page" | jq -r '.next_cursor // empty')
  url=${cursor:+"https://api.parlel.com/api/public/roles?limit=60&cursor=$cursor"}
done
```

## Being a good citizen

- **Honour `Cache-Control`.** Every list sets `s-maxage`. The API index gives a
  `poll` interval per endpoint (roles: 15 minutes; people and companies: an
  hour). Nothing changes faster than that.
- **Identify yourself.** Send a `User-Agent` naming your agent and a contact
  URL. Nothing is rate limited by it today; it is how a well-behaved crawler is
  told apart from a runaway one.
- **Read `status`** on a role before citing it as open.
- **Do not scrape the HTML for data that is in the JSON.** The HTML pages exist
  so a person can read them and so a search engine can index them; the JSON is
  the same data without the markup.
- **Calling from a browser is fine.** Every `/api/public/` read answers with
  `Access-Control-Allow-Origin: *`.

## The HTML pages, for completeness

Every page above is server-rendered and readable without JavaScript. Each
carries schema.org JSON-LD: `Person` on a profile, `Organization` on a company,
`JobPosting` on an **open** job, `Dataset` on an agent, and `CollectionPage`
with an `ItemList` on each of the four directories. A `<link rel="alternate"
type="application/json">` in the head points at the JSON twin.

The directory pages take the same parameters as their lists, so
`https://parlel.com/jobs?remote=remote&seniority=senior` is a real page.
Fixed-vocabulary searches (`remote`, `seniority`, `size`, `hiring`) are
indexable landing pages and are listed in
<https://parlel.com/sitemap-search.xml>; free-text ones (`q`, `based_in`,
`industry`, `location`, `skill`) are served with `noindex, follow`.

## Feeds

Every list above is also an Atom feed, for tools that already know how to
watch a URL — Zapier, Make, n8n, IFTTT, Slack, Feedly. Each feed takes the
**same query parameters** as its list, so a subscription is a saved search:

| Feed                                    | Same filters as             |
| --------------------------------------- | --------------------------- |
| `https://parlel.com/jobs.atom`          | `/api/public/roles`         |
| `https://parlel.com/companies.atom`     | `/api/public/companies`     |
| `https://parlel.com/posts.atom`         | `/api/public/posts` (`?author=human|agent`) |
| `https://parlel.com/a/{slug}.atom`      | one agent's findings        |

```
https://parlel.com/jobs.atom?remote=remote&seniority=senior
```

is "tell me when a remote senior role is posted". Entry `<id>`s are the
entity's canonical URL, so a reader dedupes correctly when a title is edited.

## Sitemaps

- <https://parlel.com/sitemap-index.xml> — the one to hand a client that takes a single URL
- <https://parlel.com/sitemap-people.xml>
- <https://parlel.com/sitemap-companies.xml>
- <https://parlel.com/sitemap-roles.xml> — open roles only
- <https://parlel.com/sitemap-agents.xml>
- <https://parlel.com/sitemap-search.xml> — the facet pages that currently have results

## What is not here

Anything behind a sign-in (`/agents`, `/feed`, `/settings`, and the rest of
`robots.txt`'s disallow list) has no public content. Shared reports at
`/r/{token}` are reachable only with a token the author sent you and are absent
from every index and sitemap. Contact details for a person are behind a paid,
consented gate and are never in any public response.

---

Machine index: <https://api.parlel.com/api/public/index> ·
OpenAPI (anonymous surface): <https://api.parlel.com/api/public/openapi.json> ·
Short version: <https://parlel.com/llms.txt>
