// HireAll API
API reference
A read-first, open HTTP API over the HireAll job catalogue — query jobs by rich filters, read companies, and (with a key) track applications.
Base URL
All endpoints are served under https://freehire.me/api/v1. The API is read-first and open: the job, search, facet, and company endpoints need no authentication and may be called cross-origin.
Authenticated endpoints accept either the browser session cookie (set by sign-in, same-origin) or a personal API key sent as a Bearer token — see Authentication and API keys below.
Response envelope
Single items are wrapped as { "data": ... }. Collections add pagination metadata: { "data": [...], "meta": { "total", "limit", "offset" } }. Errors are { "error": "message" } with a matching HTTP status.
{ "data": { "...": "single item" } }
{ "data": [ ... ], "meta": { "total": 4213, "limit": 20, "offset": 0 } }
{ "error": "job not found" }Pagination
List and search endpoints page with limit (default 20, max 100) and offset (default 0). meta.total reports the total matching the current filters, so you can compute the number of pages.
Search pagination is bounded: offset + limit may not exceed 10000 (pagination too deep → 400). This is deep-paging protection, not a cap on the reported total — use filters to narrow rather than paging that far.
Errors
Errors use standard HTTP status codes: 400 (bad request / invalid value), 401 (missing or invalid credentials), 403 (authenticated but not allowed, e.g. a non-moderator), 404 (no such job, company, or owned resource), and 503 (search temporarily unavailable). The body is always { "error": ... }.
Authentication model
Browser clients authenticate with an HttpOnly session cookie set on sign-in (same-origin; the SPA cannot read it). Non-browser clients use a personal API key as Authorization: Bearer <token>.
Endpoints marked “Session or API key” accept either; endpoints marked “Session only” (API-key management, saved searches, subscriptions) accept only the cookie, so a leaked key cannot manage credentials. “Moderator” endpoints additionally require the moderator role.
What is not here
This reference covers every endpoint you can call. A handful are deliberately left out because calling them directly is meaningless: the Gmail and calendar consent redirects (/me/gmail/connect, /me/calendar/connect, and their callbacks), which only a browser can complete; the Telegram bot webhook and the Discord interaction webhook; the browser-tool websocket relay; the sitemap-cursor helpers behind /sitemap.xml; and the /og/*.png social-preview cards, which render an image rather than answer with JSON.
The /jobs/{slug}/fit endpoints are pre-rename aliases of /jobs/{slug}/match-analysis and hit the same handlers. They still work, so existing clients do not break — use the match-analysis paths in new code.
Most of this API is also a CLI. If you are writing an agent rather than an integration, HireAll covers the same surface with less ceremony — search, tracking, the inbox and CV tailoring — over one API key.
Filtering jobs
These parameters apply to GET /jobs/search and GET /jobs/facets.
Combine any of them with full-text q.
Modifiers — apply to every facet
- ›Pass multiple values as a comma-separated list to OR them:
skills=go,rustmatches either. Repeating the param (skills=go&skills=rust) also works. - ›Add
<param>_mode=andto require all selected values:skills=go,rust&skills_mode=andmatches both. - ›Add
<param>_exclude=<value>to exclude matches:company_type_exclude=outstaffdrops outstaff jobs. - ›Different facets are ANDed together; numeric and boolean filters are ANDed too. The geography facets are the one exception — see below.
- ›Geography is a single OR group:
regions,countriesandcitieswiden each other instead of narrowing.regions=eu&countries=ITmeans "in Europe **or** in Italy", so it returns everythingregions=eualone would. To search one country, drop the region:countries=IT. The three name a single concept — *where* — so picking two places reads as "either", which is what makesregions=eu&countries=BR("Europe or Brazil") useful. There is no AND to switch on:_mode=anddoes not apply to geography. - ›Use
regions=noneto match jobs with no resolved geography (an empty region set); it ORs with real region values and supports_excludelike any region. - ›A param no filter reads is ignored rather than refused — so old links and saved searches keep working — and comes back in
meta.ignored_params, withdid_you_meanwhen it is only the singular of a real facet. Check it: a dropped filter otherwise looks like a genuinely broad result. At most 10 are listed per response. The same report rides on/jobs/facets,/market/coverageand/companies, which answer{"data": ...}and grow ametablock only when there is something to warn about./companiesfilters on its own vocabulary, so a jobs facet sent there is reported as ignored.
Facets
Every facet below supports repeat-OR, _mode=and, and _exclude as described above.
| Param | Filter | Values |
|---|---|---|
collections | Collection | yc, techstars, a16z-portfolio, a16z-speedrun, european, ai, mag7, bigtech, unicorn, fortune500, eastern-roots, indian-roots, ai-native, uk-skilled-worker-sponsor, nl-recognised-sponsor, us-h1b-sponsor |
regions | Region | global, north_america, latam, eu, uk, mena, africa, apac, cis, none |
work_mode | Work format | remote, hybrid, onsite |
role | Role | Open vocabulary — call /jobs/facets for live values |
category | Specialization | software_engineering, backend, frontend, fullstack, mobile, devops, sre, network_engineering, data_engineering, data_science, data_analytics, ml_ai, ai_engineering, qa, security, hardware, embedded, blockchain, architecture, design, engineering_design, product, project_management, management, marketing, sales, support, business_analysis, solutions_engineering, developer_relations, technical_writing, recruiting, hr, finance, legal, operations, customer_success, other |
ai_archetype | AI Specialization | rag_app_builder, agent_builder, cloud_ml_platform_engineer, ml_trainer_researcher, fullstack_ai_engineer, devops_infra_engineer |
seniority | Seniority | intern, junior, middle, senior, lead, staff, principal, c_level |
role_type | Role type | people_manager — the title names a people-management role. One value only: carrying nothing means no management marker was found, NOT that the posting is individual-contributor work, so role_type_exclude means "no marker", not "IC" |
skills | Skills | Open vocabulary — call /jobs/facets for live values |
domains | Industry | fintech, crypto, ecommerce, gambling, gamedev, media, travel, healthcare, edtech, govtech, devtools, cybersecurity, ai, hrtech, adtech, proptech, logistics, mobility, climatetech, other |
company_type | Company type | product, startup, outsource, outstaff, agency, inhouse, government |
countries | Countries | Open vocabulary — call /jobs/facets for live values |
cities | City | Open vocabulary — call /jobs/facets for live values |
relocation | Relocation | not_supported, supported, required |
employment_type | Employment | full_time, part_time, contract, internship, fellowship |
english_level | English | none, a1, a2, b1, b2, c1, c2, native |
posting_language | Job language | Open vocabulary — call /jobs/facets for live values |
reality | Posting reality | fresh, stale, likely-evergreen |
salary_currency | Currency | USD, EUR, GBP, RUB |
company_slug | Company | Open vocabulary — call /jobs/facets for live values |
source | Source | Open vocabulary — call /jobs/facets for live values |
company_size | Company size | 1-10, 11-50, 51-200, 201-500, 501-1000, 1000+ |
education_level | Education level | none, bachelor, master, phd |
salary_period | Salary period | year, month, day, hour |
Numeric & boolean filters
| Param | Filter | Values |
|---|---|---|
visa_sponsorship | Visa sponsorship | true, false |
requires_clearance | Security clearance required | true, false |
salary_min | Minimum salary | integer — jobs whose minimum salary is at least this (pair with salary_currency) |
salary_max | Maximum salary | integer — jobs whose maximum salary is at most this (pair with salary_currency) |
experience_years_min | Minimum experience | integer — jobs requiring at least this many years |
experience_years_max | Maximum experience | integer — jobs requiring at most this many years, the same figure experience_years_min bounds from below. Use 0 for jobs stating no prior experience is required. Either bound excludes jobs that state no requirement at all |
posted_within_days | Posted within | integer — jobs whose effective posting date falls in the last N days |
Recipes
Senior Go, remote, in the CIS region
?q=go&seniority=senior&work_mode=remote®ions=cis
Backend roles, freshest first, in Germany
?category=backend&countries=DE&sort=posted_at&order=desc
One country only — no region param, or it widens back out
?countries=IT&employment_type=contract
Must use both Go and Rust
?skills=go,rust&skills_mode=and
Exclude outstaff companies
?company_type_exclude=outstaff
At least $100k, with visa sponsorship
?salary_currency=USD&salary_min=100000&visa_sponsorship=true
Excluding jobs that need a security clearance
?requires_clearance=false
Only jobs that need a security clearance
?requires_clearance=true
Endpoints
Every endpoint has its own page. Pick one below or from the sidebar.
Jobs
- GET /jobs List jobs, newest first, with limit/offset pagination.
- GET /jobs/search Full-text + faceted search over open jobs.
- GET /agent/jobs/search Search with full descriptions, for programmatic/agent consumers.
- GET /jobs/facets Count of matching jobs per facet value (and numeric stats).
- GET /jobs/{slug} A single job by its public slug (serves closed jobs too).
- GET /jobs/{slug}/similar Jobs similar to the given one (semantic; may be empty).
- GET /jobs/{slug}/copies Other open postings in the same role cluster (per-city duplicates).
- GET /jobs/{slug}/apply-form The captured ATS application form for the posting.
AI analysis
- GET /jobs/{slug}/match Deterministic skill match of the job against your profile (no LLM).
- GET /jobs/{slug}/match-analysis The cached AI match analysis for the job (never runs the LLM).
- POST /jobs/{slug}/match-analysis Run the three-stage AI match analysis and cache it.
- GET /jobs/{slug}/match-analysis/stream Run the match analysis over Server-Sent Events.
- POST /market/coverage Score a supplied skill list against the filtered job market.
Companies
Company feedback
- GET /companies/{slug}/feedback List a company's feedback, newest first.
- GET /companies/{slug}/feedback/mine Your own feedback on this company, across every category (empty if none).
- POST /companies/{slug}/feedback Create or overwrite your feedback in one category on a company.
- DELETE /companies/{slug}/feedback Delete your feedback in one category (no-op if absent).
- POST /company-feedback/{id}/report Report a specific review.
- GET /company-feedback/reported Every review with at least one report, most-reported first.
- POST /company-feedback/{id}/hide Hide a review, dropping it from the company's public list and average.
Authentication
- POST /auth/register Create an account and start a session.
- POST /auth/login Sign in and start a session.
- POST /auth/logout Clear the session cookie.
- GET /auth/me The current user (cookie or API key).
- GET /auth/oauth/providers List the enabled OAuth providers.
- GET /auth/oauth/{provider}/start Begin the OAuth sign-in redirect.
- POST /auth/verify/request Send (or resend) a six-digit email verification code.
- POST /auth/verify/confirm Confirm the address with the mailed code.
- POST /auth/password/forgot Request a password-reset code by email.
- POST /auth/password/reset Set a new password against a mailed code.
- POST /auth/logout-all Sign out every session on the account, including this one.
- POST /auth/oauth/exchange Redeem a mobile OAuth callback code for a session.
- GET /auth/extension/connect Consent screen for "Sign in with HireAll" from the browser extension.
- POST /auth/extension/connect Submit the consent decision and mint the extension’s session token.
API keys
Job interactions
- POST /jobs/{slug}/view Record that you viewed the job.
- POST /jobs/{slug}/apply Mark the job as applied to.
- POST /jobs/{slug}/save Save (bookmark) the job.
- DELETE /jobs/{slug}/save Unsave the job (no-op if not saved).
- PATCH /jobs/{slug}/track Set the application stage and/or notes.
- DELETE /jobs/{slug}/stage Clear the application stage.
- DELETE /jobs/{slug}/track Remove the interaction record entirely.
- PATCH /me/applications/{id} Set the application stage and/or notes, addressed by row id.
- DELETE /me/applications/{id} Remove the interaction record entirely, addressed by row id.
- DELETE /me/applications/{id}/stage Clear the application stage, addressed by row id.
- POST /jobs/{slug}/dismiss Dismiss (swipe away) the job.
- DELETE /jobs/{slug}/dismiss Undismiss the job (no-op if not dismissed).
- GET /me/tracking Your tracked jobs joined with the job data.
- GET /me/tracking/viewed Slugs of jobs you have viewed.
- GET /me/tracking/analyses Jobs you have run the AI match analysis on.
- GET /me/plan Your plan and what it allows today.
- GET /me/tracking/saved Slugs of jobs you have saved.
- GET /me/tracking/pipeline Your application-pipeline snapshot (counts per stage).
- GET /me/tracking/swipe A batch of open jobs for the swipe triage deck.
- GET /me/timeline What happened to your applications over a date range.
- GET /me/interviews Arranged meetings whose start falls in the date range.
In-app assistant
- POST /assistant/sessions Start a new conversation.
- GET /assistant/sessions List your chat conversations, newest activity first.
- GET /assistant/sessions/{id} One owned conversation with its full transcript.
- DELETE /assistant/sessions/{id} Delete an owned conversation and its transcript.
- POST /assistant/sessions/{id}/messages Send a message and stream the turn as Server-Sent Events.
- POST /assistant/sessions/{id}/cancel Stop the session’s running turn.
- POST /assistant/sessions/{id}/opening Have the assistant speak first, on an `interview`/`debrief` session.
- POST /assistant/sessions/{id}/retry Resume after a failed turn, without adding another user message.
- POST /assistant/sessions/{id}/extend Buy a CV editing session another ceiling’s worth of turns.
- POST /assistant/sessions/{id}/voice-token Mint a short-lived credential for a hands-free voice call.
- POST /assistant/sessions/{id}/voice-turns Append one completed spoken exchange to the transcript.
- POST /assistant/sessions/{id}/autopilot Run an unattended CV-tailoring pass as one long streamed turn.
Job submissions
- POST /submissions Submit a vacancy for review.
- POST /submissions/prefill Parse a job URL into a draft submission for review before posting.
- GET /me/submissions Your own submission queue.
- GET /submissions The pending submission queue (moderators).
- POST /submissions/{id}/approve Approve a submission, minting a live job.
- POST /submissions/{id}/reject Reject a submission with a reason.
Job reports
Ghost job reports
Profile & résumé
- GET /me/profile Your career profile, or null if you have not saved one.
- PUT /me/profile Create or replace your profile.
- DELETE /me/profile Clear your profile (idempotent).
- GET /me/profile/verdict Market-coverage verdict for your profile skills.
- GET /me/profile/ats-report CV ATS-readiness report (deterministic + any cached LLM review).
- POST /me/profile/ats-report Run the optional LLM qualitative ATS review and cache it.
- POST /me/resume/extract Extract a structured profile from an uploaded résumé (no LLM).
- PUT /me/resume Store or replace your résumé.
- GET /me/resume Your résumé status (enabled / present / uploaded_at).
- DELETE /me/resume Delete your stored résumé.
- PUT /me/resume/contacts Override one or more contact-block fields on your profile.
- POST /me/resume/contacts/replace-from-cv Reset every contact override from your current structured résumé.
Screening answers
Activity & shared boards
Saved searches & subscriptions
- GET /me/searches List your saved searches.
- POST /me/searches Save a search.
- PATCH /me/searches/{id} Rename or re-query a saved search.
- DELETE /me/searches/{id} Delete a saved search.
- GET /me/subscriptions List your subscriptions.
- POST /me/subscriptions Subscribe a saved search to a digest channel.
- PATCH /me/subscriptions/{id} Pause or resume a subscription.
- DELETE /me/subscriptions/{id} Delete a subscription.
- GET /me/telegram Your Telegram link status (for digests).
- POST /me/telegram/link Start linking your Telegram account.
- DELETE /me/telegram Unlink your Telegram account.
- GET /me/discord Your Discord link status (for the `/contribute` bot command).
- POST /me/discord/link Mint a one-time token to link your Discord account.
- DELETE /me/discord Unlink your Discord account. Idempotent.
Push notifications & alerts
- POST /me/push-tokens Register (or reassign) a mobile device’s Expo push token.
- GET /me/push-tokens List your own registered devices.
- DELETE /me/push-tokens Unregister one of your own device tokens.
- POST /me/push-tokens/test Send a test push to all of your own registered devices.
- GET /me/notifications List your notification-center entries, newest first.
- GET /me/notifications/{id} One of your notifications, including its jobs snapshot.
- POST /me/notifications/{id}/read Mark one notification read (idempotent).
- POST /me/notifications/read-all Mark every unread notification read.
Account, plan & extension
- POST /me/password Change a known password.
- DELETE /me Delete your account and everything under it.
- GET /me/plan/history What you spent your allowances on, newest first.
- GET /me/usage Your AI request activity today.
- GET /me/tracking/{slug} One tracked application, with the mail linked to it and its history.
- GET /me/tracking/dismissed The slugs you dismissed, so a client can hide them.
- POST /me/match-text Score any job text against your profile.
- GET /me/autofill-profile Your contact details in canonical autofill fields.
- POST /me/autofill/run Drive your own browser to fill an application form.
- PATCH /me/timezone Set your account’s IANA timezone.
- PATCH /me/language Set your preferred interface language.
Link intake & discovery
- GET /jobs/find Resolve a posting URL to a catalogue slug.
- POST /jobs/resolve Hand HireAll a link: import the posting, and the board behind it.
- GET /me/contributions The boards you contributed, and their onboarding state.
- POST /me/jd/resolve Turn a URL, pasted text, or an existing job into one usable by CV tailoring.
Votes, notifications & discussions
- POST /jobs/{slug}/vote Vote on a job.
- DELETE /jobs/{slug}/vote Clear your vote on a job.
- POST /companies/{slug}/vote Vote on a company.
- DELETE /companies/{slug}/vote Clear your vote on a company.
- GET /me/notification-settings Your notification rule (gates saved-job reminders and both lifecycle nudges).
- PUT /me/notification-settings Change your notification rule.
- GET /threads Public discussion threads.
- GET /threads/count How many threads there are.
- GET /threads/{id} One thread with its replies.
- POST /threads Start a thread.
- POST /threads/{id}/replies Reply to a thread.
- POST /threads/{id}/close Close a thread.
Market insights & stats
- GET /stats/catalog The headline catalogue-scale figures (open jobs, companies, sources, …).
- GET /insights/roles Roles (category × seniority) ranked by openings or growth.
- GET /insights/skills Skills ranked by openings or growth.
- GET /insights/salary Salary bands by category, seniority and country.
- GET /insights/velocity How fast a slice of the market is hiring, over time.
- GET /insights/companies Companies ranked by hiring activity.
- GET /stats/facets Facet distribution snapshot: countries, skills, seniority, work mode.
- GET /stats/user-growth Cumulative member growth per UTC day.
- GET /stats/engagement Jobs saved, applied to and viewed across all users, plus CV and inbox usage.
- GET /status Ingest-fleet health, per provider.
Employee referrals
- POST /me/referrals/offers Offer to refer into a company. Multipart — proof required.
- GET /me/referrals/offers Your referral offers and their moderation state.
- DELETE /me/referrals/offers/{id} Withdraw an offer.
- POST /me/referrals/requests Ask a company's approved referrers for an intro.
- GET /me/referrals/requests The intros you asked for, and where they stand.
- GET /me/referrals/incoming Requests waiting on you as an approved referrer.
- GET /me/referrals/incoming/{id}/cv View the candidate's CV for one incoming request.
- POST /me/referrals/incoming/{id}/resolve Mark an incoming request contacted or declined.
- GET /referrals/offers The offer-moderation queue.
- GET /referrals/offers/{id}/proof View an offer's proof document.
- POST /referrals/offers/{id}/decide Approve or reject an offer.
Talent Network
CV builder & tailoring
- GET /me/cvs List your CVs, without their documents.
- POST /me/cvs Create a CV, optionally seeded from your stored history.
- GET /me/cvs/{id} One CV with its full document.
- PUT /me/cvs/{id} Replace a CV — title, template and document.
- PATCH /me/cvs/{id} Apply a batch of edits, addressed by path.
- PUT /me/cvs/{id}/template Switch the template only.
- DELETE /me/cvs/{id} Delete a CV.
- GET /me/cvs/{id}/pdf Render the CV to PDF.
- GET /cv-templates The template gallery.
- GET /cv-fonts The typefaces a CV may use.
- POST /me/cvs/tailor Start tailoring a CV toward one vacancy.
- POST /me/cvs/{id}/tailor-session Mint a fresh agent session for an existing tailored CV.
- POST /me/cvs/base/reset-from-resume Rebuild your base CV from your résumé.
- POST /me/cvs/{id}/reset-from-resume Rebuild this tailored CV from your résumé.
- GET /me/cvs/{id}/tailor-context The match analysis a tailored CV should reframe toward.
- PUT /me/cvs/{id}/session Bind an agent session to a CV.
- PUT /me/cvs/{id}/tracer-links Turn link tracing on or off for this CV's PDF.
- GET /me/cvs/{id}/tracer-links What is known about this CV's traced links.
- GET /me/cvs/{id}/revisions The edit history of this CV, newest first.
- POST /me/cvs/{id}/revisions/{rid}/undo Reverse one revision, leaving later edits in place.
- POST /me/cvs/{id}/revisions/batch/{bid}/undo Reverse every standing edit of one agent turn, newest first.
- GET /me/cvs/{id}/ats-delta How tailoring changed this CV's ATS-readiness score.
- GET /me/cvs/{id}/job-match How well a tailored CV matches the vacancy it was written for.
Photo
Experience bank
- GET /me/experience Your employments and their evidence atoms.
- PUT /me/experience/employments/{id} Edit one employment.
- DELETE /me/experience/employments/{id} Remove an employment and its atoms.
- PUT /me/experience/atoms/{id} Edit one evidence atom.
- DELETE /me/experience/atoms/{id} Remove an evidence atom.
- POST /me/experience/employments Record a new place — a job or a project.
- POST /me/experience/atoms Record a new achievement.
- POST /me/experience/atoms/merge Fold two of your atoms into one richer keep.
Application mail
- GET /me/tracking/{slug}/followup Draft a chase for a silent application.
- POST /me/tracking/{slug}/followup Record that you sent a chase.
- POST /me/tracking/{slug}/mail-recall Sweep your connected mailbox for mail belonging to this application.
- POST /me/tracking/{slug}/mail-recall/link Import and link one message a mail-recall sweep proposed.
- GET /me/inbox List your mail, newest first, excluding deleted.
- GET /me/emails/{id} One message in full. Marks it read.
- POST /me/emails Push a batch your own mail client fetched.
- POST /me/emails/{id}/triage Record what a message is, and optionally which application it belongs to.
- POST /me/emails/{id}/link Attach a message to one of your applications.
- POST /me/emails/{id}/unlink Clear a message's application link; its classification stays.
- POST /me/emails/{id}/confirm Accept a suggested link.
- POST /me/emails/{id}/reject Dismiss a suggested link without attaching it.
- POST /me/emails/{id}/application Record an application from a message, and link the message to it.
- POST /me/inbox/read-all Mark every unread message matching the filters as read.
- POST /me/emails/{id}/delete Soft-delete a message. Answers 204.
- POST /me/emails/{id}/restore Undo a soft-delete. Answers 204.
- GET /me/mailbox Your hosted HireAll address, and whether the feature is configured.
- POST /me/mailbox Claim your hosted address.
- DELETE /me/mailbox Release the address; it stops receiving.
- GET /me/gmail Gmail connection status.
- POST /me/gmail/sync Start an incremental sync.
- DELETE /me/gmail Disconnect Gmail and purge the mail it synced.