Developer docs

Build on the ApplyLoop jobs feed.

The ApplyLoop API exposes the same catalog our own product runs on: every posting our scout discovers across 26 ATS platforms (Greenhouse, Lever, Ashby, Workday, iCIMS, and 20+ more), deduplicated, freshness-validated (stale postings are pruned), and filtered to US locations.

It's built for job boards that want a fresh source, researchers studying the hiring market, and anyone wiring jobs into a personal tool or agent. One endpoint, bearer-token auth, keyset pagination.

GreenhouseLeverAshbyWorkdayiCIMSSmartRecruitersWorkable+19 more

Get an API key

  1. Create a free ApplyLoop account. No card required.
  2. In the dashboard, open API access.
  3. Click Create token and grant it the jobs:read scope.
Your key is shown exactly once, at creation, so copy it right away. We store only a SHA-256 hash, so it can never be recovered (or leaked) later.
Create a free account

Authentication

Every request carries your key as a bearer token. Keys are per-account, start with alk_, and can be revoked at any time from the same API access page. Revocation takes effect immediately.

HTTP header
Authorization: Bearer alk_YOUR_TOKEN

CORS is open for GET requests, so the API is callable directly from browser apps too.

Jobs API

GET/api/v1/jobs

Returns jobs newest-first (by discovered_at). Suppressed postings (captcha, login walls, closed roles) and platforms with a temporarily disabled apply flow are excluded. You only ever see actionable jobs.

Query parameters

All parameters are optional.

ParameterDescription
atsComma-separated platform slugs to include, e.g. ats=greenhouse,lever. Omit for all platforms.
qCase-insensitive substring match on job title or company name.
locationCase-insensitive substring match on location, e.g. location=remote.
levelCareer-ladder bucket derived from the job title: intern, junior, mid, senior, or lead (lead = Lead and above). Unknown values are ignored.
categoryRole family derived from the job title: data-scientist, data-analyst-eng, ai-ml, network-security, cybersecurity, cloud-devops, software-eng, other. Unknown values are ignored.
sinceEpoch milliseconds: return only jobs discovered after this moment. Ideal as an incremental polling cursor.
limitPage size, 1 to 100. Default 50.
cursorKeyset pagination cursor: pass the nextCursor value from the previous page to fetch the next (older) page.

Response

A JSON object: { jobs, nextCursor, count }.

200 response
{
  "jobs": [
    {
      "id": "job_9f1c2ab4",
      "ats": "greenhouse",
      "title": "Machine Learning Engineer",
      "company": "Acme AI",
      "company_domain": "acme.ai",
      "location": "Remote, US",
      "apply_url": "https://boards.greenhouse.io/acmeai/jobs/4123456",
      "posted_at": 1753180000000,
      "discovered_at": 1753210000000
    }
  ],
  "nextCursor": 1753210000000,
  "count": 1
}
FieldTypeDescription
idstringStable job identifier.
atsstringSource platform slug, e.g. greenhouse, lever, ashby.
titlestringJob title.
companystringCompany name.
company_domainstring | nullCompany website domain, when known.
locationstring | nullLocation as posted (US-filtered, see note below).
apply_urlstringDirect link to the application page on the source ATS.
posted_atnumber | nullEpoch ms when the role was posted, when the source ATS exposes it.
discovered_atnumberEpoch ms when our scout first saw the role. Sort key: results are newest-first.

Pagination: pass nextCursor back as cursor to fetch the next page, and stop when it's null. A US-location filter is applied per page after fetching, so count can be lower than your limit while more pages still remain. Always paginate to the end rather than stopping at a short page.

Errors

StatusBodyWhen
401{"error":"unauthorized"}Missing, invalid, or revoked token, or the token lacks the jobs:read scope.
429{"error":"rate_limited","retryAfterSec":n}Per-key requests-per-minute ceiling hit. The retry-after header carries the same value in seconds.
429{"error":"too_many_concurrent_requests"}Too many simultaneous in-flight requests on one key. Sent with retry-after: 1.
503{"error":"jobs_api_not_enabled"}Only on the shared service-key path when that key is not configured on the deployment. Personal alk_ tokens never see this.

Requests sent with Accept: text/html (e.g. pasting the URL into a browser) are redirected to the dashboard's API access page instead of showing raw JSON errors.

Code examples

Replace alk_YOUR_TOKEN with your own key. The Python and JavaScript examples paginate through the full result set.

curl
curl "https://applyloop.pro/api/v1/jobs?q=machine+learning&limit=50" \
  -H "Authorization: Bearer alk_YOUR_TOKEN"
Python
import requests

BASE = "https://applyloop.pro/api/v1/jobs"
HEADERS = {"Authorization": "Bearer alk_YOUR_TOKEN"}

jobs, cursor = [], None
while True:
    params = {"q": "machine learning", "limit": 100}
    if cursor:
        params["cursor"] = cursor
    page = requests.get(BASE, headers=HEADERS, params=params).json()
    jobs += page["jobs"]
    cursor = page.get("nextCursor")
    if not cursor:
        break

print(f"{len(jobs)} jobs")
JavaScript
const BASE = "https://applyloop.pro/api/v1/jobs";
const headers = { Authorization: "Bearer alk_YOUR_TOKEN" };

const jobs = [];
let cursor = null;
do {
  const url = new URL(BASE);
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", String(cursor));
  const page = await fetch(url, { headers }).then((r) => r.json());
  jobs.push(...page.jobs);
  cursor = page.nextCursor;
} while (cursor);

console.log(`${jobs.length} jobs`);

Rate limits

Limits are enforced per key, so one consumer can never starve another. Current defaults:

LimitDefaultNotes
Requests per minute60Fixed one-minute window, counted per key.
Concurrent requests4Maximum simultaneous in-flight requests per key. Parallel fan-out beyond this returns 429.

Successful responses include an x-ratelimit-remaining header; when you exceed a limit you get a 429 with a retry-after header (see Errors above). These are fair-use defaults and may be tuned server-side. If you need more headroom, write to founders@applyloop.app.

Account endpoints

Personal tokens can carry more than jobs:read. These endpoints act on your own ApplyLoop account:

EndpointScopeWhat it does
GET /api/v1/meany tokenYour plan, quota and applications remaining.
GET /api/v1/matchesapply:readYour pending matches (the same queue the dashboard shows).
GET /api/v1/applicationsapply:readYour applications with statuses and receipts.
POST /api/v1/applyapply:writeApprove one match by queue id (identical to tapping Apply).

Coming soon

The token scopes apply:read and apply:write already exist in the dashboard. The surfaces they unlock are in preview, and their docs will land here as they stabilize:

apply:read

Your application pipeline over API: statuses, submissions, and outcomes.

apply:write

Trigger applications programmatically: one role or the whole matched queue.

MCP server & bots

Drive ApplyLoop from agents: an MCP server plus chat surfaces built on the same tokens.