Get started

Quickstart

Make your first search, build a JobQuery from lookups, and read the results.

The API lives at https://trawle.com/v1. It speaks JSON, needs no key for now, and allows calls from any origin, so you can try it from a terminal or a browser.

POST /v1/jobs/search takes a JobQuery and returns a page of open jobs, newest first. Free text is the quickest start:

curl -X POST "https://trawle.com/v1/jobs/search" \
  -H "Content-Type: application/json" \
  -d '{ "query": { "q": "react" }, "limit": 5 }'

The request body, for reference:

JSON
{ "query": { "q": "react" }, "limit": 5 }

2. Build a query from lookups

Free text matches titles, departments and company names. For precise results, filter by ids instead. Each filter has a lookup endpoint that turns words into ids:

FilterLookupUse
placesGET /v1/places?q=items[].id (GeoNames id)
rolesGET /v1/roles?q=items[].slug
companiesGET /v1/companies?q=items[].slug
familiesGET /v1/familiesitems[].slug

Look up Copenhagen:

Terminal
curl "https://trawle.com/v1/places?q=copenhagen"
JSON
{
  "items": [
    {
      "id": 2618425,
      "name": "Copenhagen",
      "country": "DK",
      "kind": "city",
      "context": "Capital Region, Denmark"
    }
  ]
}

Then the role, with GET /v1/roles?q=frontend, which returns frontend-engineer. Put both into the query, and narrow it to hybrid and remote jobs:

JSON
{
  "query": {
    "roles": ["frontend-engineer"],
    "places": [2618425],
    "workplace": ["hybrid", "remote"]
  },
  "limit": 25
}

Values inside one filter are OR, filters are AND: frontend jobs, in or open to people in Copenhagen, that are hybrid or remote. Building a JobQuery explains every filter.

3. Read the results

JSON
{
  "jobs": [
    {
      "id": "4419023",
      "title": "Senior Frontend Engineer",
      "company": { "slug": "lumen-labs", "name": "Lumen Labs", "domain": "lumenlabs.example" },
      "role": { "slug": "frontend-engineer", "name": "Frontend Engineer" },
      "family": { "slug": "software-engineering", "name": "Software Engineering" },
      "locations": [{ "id": 2618425, "name": "Copenhagen", "country": "DK" }],
      "workplace": "hybrid",
      "remoteScope": null,
      "seniority": "senior",
      "employmentType": "full_time",
      "salary": { "min": 720000, "max": 900000, "currency": "DKK", "period": "year" },
      "firstSeenAt": "2026-10-30T06:12:00.000Z",
      "lastSeenAt": "2026-10-31T06:12:00.000Z",
      "postedAt": "2026-10-29T00:00:00.000Z",
      "openSince": "2026-09-14T06:10:00.000Z",
      "repostCount": 1,
      "closedAt": null,
      "applyUrl": "https://job-boards.greenhouse.io/lumenlabs/jobs/7712001",
      "url": "https://trawle.com/jobs/4419023"
    }
  ],
  "total": 38,
  "totalCapped": false,
  "nextCursor": "MjAyNi0xMC0zMFQwNjoxMjowMC4wMDBafDQ0MTkwMjM",
  "labels": { "roles:frontend-engineer": "Frontend Engineer", "places:2618425": "Copenhagen" },
  "dataDate": "2026-10-31T06:12:00.000Z",
  "nextSince": "2026-10-31T09:30:00.000Z"
}

A few fields worth knowing:

  • applyUrl is the employer's own posting. Send people there to read the full description and apply.
  • url is the job on Trawle.
  • openSince and repostCount tell you how long the job has really been open. This one was first posted in September and reposted once; see Freshness and reposts.
  • labels names the ids in your query. An id that is missing from labels matched nothing.
  • nextCursor fetches the next page (Pagination); nextSince gets only new jobs on your next run (Daily new-jobs check).

4. Show attribution

When you display Trawle results, show "Data by Trawle" with a link to https://trawle.com (or to each job's url), and link each job to its applyUrl. See Attribution and data policy.

Typed clients

The OpenAPI spec is complete enough to generate a client. For TypeScript, openapi-typescript plus openapi-fetch gives typed requests and responses:

Terminal
npx openapi-typescript https://developers.trawle.com/openapi.json -o trawle.d.ts
npm install openapi-fetch
TypeScript
import createClient from "openapi-fetch";

import type { paths } from "./trawle";

const trawle = createClient<paths>({ baseUrl: "https://trawle.com" });
const { data, error } = await trawle.POST("/v1/jobs/search", {
  body: { query: { roles: ["frontend-engineer"], places: [2618425] } },
});

Every page in the API reference has samples for cURL, TypeScript and Python.