Getting Started with the FastHire API
Rakesh · September 19, 2026 · 7 min read
Before you build against this: the FastHire API is real and callable today, but it's an early version — several endpoints described on the full API Reference page aren't implemented yet, and a few behave differently than documented there. This article only describes what's actually live, verified against the current code. See "What's live vs. planned" below before you start.
Step 1: Generate an API key
- Go to Settings → Developer. Only an Org Admin can see this page.
- Select Generate API key.
- Give it a name (e.g. "Production integration") so you can tell your keys apart later.
- Choose an environment: Test or Live.
- Select Generate key.
Your key is shown exactly once, immediately after generation — copy it somewhere safe now. FastHire only stores a prefix (enough to identify the key in your list afterward) and a hash of the full value; if you close the dialog without copying it, there's no way to retrieve it again — you'd need to revoke it and generate a new one.
Keep it server-side. A key carries full read/write access to your org's candidate and outreach data (see the note on scoping below). Never embed one in client-side code, a mobile app, or anywhere a user of your own product could extract it — call the FastHire API from your own backend only.
Step 2: Authenticate your requests
Send the key as a bearer token on every request:
curl https://api.thefasthire.com/v1/searches \
-H "Authorization: Bearer fh_live_yourkeyhere"
Every key belongs to one organization — you only ever see and modify that org's data. There is currently no role-based restriction on a key beyond that: a key generated by an Org Admin can read and write anything the API supports, and there's no separate, more limited key type today, despite what you may see referenced elsewhere.
What Test vs. Live actually changes
Important — this is a genuine safety gap, not a minor detail: the environment
you chose when generating a key currently only changes its prefix
(fh_test_... vs. fh_live_...). It does not sandbox
anything. A search created with a fh_test_ key sources real candidates and spends
real credits exactly like a live key. Scheduling an interview with a fh_test_ key
creates a real interview, sends a real calendar invite, and sends a real confirmation
email/WhatsApp message to the actual candidate — nothing is suppressed. Treat every key as live
until FastHire actually builds a sandboxed test mode; don't test against real candidate data with
either kind of key.
What's live vs. planned
Every endpoint below exists and works today unless marked Planned. This list is deliberately more conservative than any spec-style documentation you might see elsewhere — if it's not in this table, don't rely on it existing yet.
| Endpoint | Status | Notes |
|---|---|---|
GET /v1/searches | Live | Returns every search in your org, no filtering. |
POST /v1/searches | Live | Creates and queues a real sourcing run. |
GET /v1/searches/:id | Live | |
GET /v1/searches/:id/candidates | Live | Returns every matched candidate, unfiltered and unpaginated. |
GET /v1/candidates/:id | Live | Intake details are embedded in this same response, not a separate call. |
GET /v1/lists | Live | |
POST /v1/lists | Live | Creates an empty list — takes only a name. |
| Add/remove a candidate on a list via the API | Planned | Not implemented — do this in the app for now. |
GET /v1/sequences | Live | |
GET /v1/sequences/:id | Live | |
POST /v1/sequences | Live, draft-only | Always creates a DRAFT. Passing "activate": true is rejected with a 400 — activate it in the app instead. |
| Pause/activate a sequence via the API | Planned | |
| List a sequence's enrolled candidates via the API | Planned | |
GET /v1/inbox/conversations | Live | Note the path — it's /inbox/conversations, not /inbox. |
GET /v1/inbox/conversations/:id | Live | Full thread for one candidate. |
| Send a reply via the API | Planned | Read-only for now. |
GET /v1/interviews | Live | |
POST /v1/interviews | Live | See the Test/Live warning above — this really sends things. |
| Reschedule or cancel an interview via the API | Planned | Do this in the app for now. |
| Webhooks (any event) | Planned | No subscription, signing, or delivery system exists yet — you must poll. |
Pagination (limit/cursor) | Planned | Every list endpoint returns its complete result set in one response today. |
| Rate limiting | Planned | No rate-limit headers or enforcement exist yet — be considerate anyway. |
Idempotency-Key header | Planned | A repeated POST creates a second object today — dedupe on your side if that matters to you. |
Response shape and conventions
- No envelope. List endpoints return a plain object keyed by the resource name —
e.g.
{ "searches": [...] },{ "candidates": [...] },{ "lists": [...] },{ "sequences": [...] },{ "conversations": [...] },{ "interviews": [...] }— not a genericdataarray. - Field casing is camelCase throughout (
matchScore,linkedinUrl,createdAt), matching the app's own data model exactly — not snake_case. - Errors are flat. Every error response is
{ "error": "A human-readable message" }— a plain string, not a structured object with a type/code/field breakdown. Check the HTTP status code to branch on the kind of error. - IDs aren't prefixed by object type — don't assume or parse a prefix.
Example calls
List your searches
curl https://api.thefasthire.com/v1/searches \
-H "Authorization: Bearer fh_live_yourkeyhere"
{
"searches": [
{ "id": "abc123", "name": "Senior Backend Engineer", "sourceType": "JOB_DESCRIPTION",
"createdAt": "2026-09-01T04:11:00.000Z", "updatedAt": "2026-09-01T04:15:00.000Z" }
]
}
Create a search
criteria is the same object the app itself builds when you fill out the search form —
it's a larger structure than you might expect. searchName, roles,
companies, languages, education, location, and
keywords are all required (empty arrays/nulls are fine for anything you don't need);
skills, experience, companiesTiming, and company
are optional and default to empty. At minimum:
curl https://api.thefasthire.com/v1/searches \
-X POST -H "Authorization: Bearer fh_live_yourkeyhere" \
-H "Content-Type: application/json" \
-d '{
"sourceType": "NATURAL_LANGUAGE",
"criteria": {
"searchName": "Senior Backend Engineer",
"roles": ["Backend Engineer"],
"companies": [],
"languages": [],
"education": {
"fieldsOfStudy": [], "degreeTypes": [], "institutions": [], "excludedInstitutions": [],
"minGraduationYear": null, "maxGraduationYear": null, "minEducationLevel": null
},
"location": { "radiusKm": 50, "entries": [] },
"keywords": { "mustHave": ["Go", "Kubernetes"], "niceToHave": ["distributed systems"] }
}
}'
sourceType must be "NATURAL_LANGUAGE" or "JOB_DESCRIPTION" — "MANUAL" isn't accepted through the API today. A successful call returns { "id": "..." } with a 201.
Read a search's matched candidates
curl https://api.thefasthire.com/v1/searches/abc123/candidates \
-H "Authorization: Bearer fh_live_yourkeyhere"
{
"candidates": [
{
"resultId": "res_1", "candidateId": "cnd_1", "name": "Priya Nair",
"headline": "Staff Engineer at Canva", "location": "Sydney, Australia",
"phone": null, "email": "priya@example.com",
"skills": ["Go", "Kubernetes"], "experience": [ /* ... */ ], "education": [ /* ... */ ],
"matchScore": 87, "matchReasoning": "Strong backend depth, based in target metro.",
"percentile": 92
}
]
}
matchScore is 0–100, not 0–1, and there's no tier field — FastHire doesn't sort
candidates into named tiers anywhere, in the app or the API.
Create a list, then a draft sequence targeting it
curl https://api.thefasthire.com/v1/lists \
-X POST -H "Authorization: Bearer fh_live_yourkeyhere" \
-H "Content-Type: application/json" \
-d '{ "name": "Q4 backend candidates" }'
Returns { "id": "..." }. There's no API to add candidates to it yet — do that in the app.
Check inbox activity
curl https://api.thefasthire.com/v1/inbox/conversations \
-H "Authorization: Bearer fh_live_yourkeyhere"
Each conversation includes hasUnread, hasReplied, and
intakeStatus (null until the candidate has expressed interest). Fetch one
thread's full message history with GET /v1/inbox/conversations/:candidateId.
Schedule an interview
curl https://api.thefasthire.com/v1/interviews \
-X POST -H "Authorization: Bearer fh_live_yourkeyhere" \
-H "Content-Type: application/json" \
-d '{
"candidateId": "cnd_1",
"scheduledAt": "2026-09-25T10:00:00Z",
"timezone": "Asia/Kolkata",
"durationMinutes": 30
}'
Remember: this really schedules it. If the recruiter who created the key has Google Calendar or
Microsoft Teams connected and no meetingLink was supplied, a real calendar event and
meeting link are created automatically, and a confirmation is sent to the candidate.
Handling errors
| Status | Meaning |
|---|---|
400 | Malformed body, a field failed validation, or you tried something not supported via the API yet (like activating a sequence). |
401 | Missing, malformed, or revoked API key. |
402 | Your org's search cap for the current billing period would be exceeded. |
403 | The team member who created this key has since been deactivated. |
404 | The object doesn't exist, or belongs to a different org than your key. |
500 | Something failed on FastHire's side. |
Every error body is { "error": "message" } — read the message, it's written for humans, not parsed by machines yet.
Revoking a key
Go back to Settings → Developer and select Revoke next to any key. This is immediate and permanent — a revoked key returns 401 on every future request. There's no way to temporarily disable and later re-enable the same key; generate a new one if you need to rotate.
Frequently asked questions
Is there a sandbox I can safely test integration code against?
Not yet. Both Test and Live keys act on your organization's real data — see the warning under "What Test vs. Live actually changes" above.
Can I limit a key to read-only, or to specific objects?
No — every key currently has full read/write access to everything the API exposes for your org. There's no scoping today.
Why does creating a search sometimes return a 402?
Your organization has hit its search cap for the current billing period (this mirrors the same limit enforced in the app). Wait for the next period or check Settings → Billing.
Can I paginate a large list of candidates or searches?
Not yet — every list endpoint returns its full result set in a single response.
Does the full API Reference page match this article?
Not entirely — it documents FastHire's intended future shape for this API, and some of what it shows (pagination, webhooks, structured errors, role-scoped keys) isn't built yet. This article reflects what you can actually call today; treat the reference page as a roadmap.
Last reviewed September 2026, verified directly against the deployed /api/v1 route implementations.
