Skip to main content
FastHire
API Reference — Draft v1

Build on FastHire.

Search results, candidate records, outreach sequences, inbox threads, and interviews — read from and written to the same data your recruiters see in the app.

This endpoint set is not live yet. It specifies the public API FastHire is building against its current recruiter data model, so engineering and docs can be built from one source of truth. Treat every request/response shown here as the intended contract, not something you can call today. This banner comes down once v1 ships.

Introduction

The FastHire API is organized around the same objects recruiters work with in the app: searches (an AI sourcing run against a role), the candidates it surfaces, lists recruiters curate from results, sequences that run outreach across LinkedIn, email and in-app steps, the inbox those sequences populate, and interviews scheduled from a reply. Every object is scoped to one organization — your API key determines which org’s data you see.

The API accepts and returns application/json, uses standard HTTP response codes, and is versioned in the URL.

Base URL
https://api.thefasthire.com/v1

Authentication

Authenticate by sending a secret API key as a bearer token. Generate keys from Settings → Developer in the FastHire app — each key is scoped to one org and inherits no more access than the role that created it (an ORG_ADMIN key can manage sequences and connections; a RECRUITER key cannot).

curl https://api.thefasthire.com/v1/searches \
  -H "Authorization: Bearer fh_live_51H8x...cQ2k"
Keep keys server-side. A key carries full read/write access to the org’s candidate and outreach data — never embed one in client-side code. Use fh_test_… keys against the sandbox org while integrating; they behave identically but never send real LinkedIn, email, or WhatsApp messages.

Conventions

ConventionDetail
IdentifiersAll object ids are opaque strings (e.g. cnd_9mK2pQ...). Don’t parse them.
TimestampsISO 8601, UTC, e.g. 2026-08-20T09:30:00Z. Fields ending in At follow this format.
MoneySalary fields are free-text strings (currentSalary, expectedSalary) — candidates self-report these in whatever format they reply with, so the API does not coerce them into a number/currency pair.
IdempotencyPOST requests that create an object accept an Idempotency-Key header; replaying the same key returns the original response instead of creating a duplicate.
ExpansionWhere noted, pass ?expand=field to inline a related object instead of just its id.

Errors

Errors return a 4xx/5xx status and a JSON body describing what went wrong.

{
  "error": {
    "type": "invalid_request",
    "code": "missing_field",
    "message": "criteria.mandatory is required for sourceType=MANUAL",
    "field": "criteria.mandatory"
  }
}
StatusMeaning
400 invalid_requestMalformed body, or a field failed validation.
401 unauthenticatedMissing, malformed, or revoked API key.
403 permission_deniedKey's role can't perform this action (e.g. a RECRUITER key managing connections).
404 not_foundObject doesn't exist, or belongs to a different org.
409 conflictState doesn't allow the action (e.g. activating an ARCHIVED sequence).
429 rate_limitedToo many requests — see rate limit headers below.
500 api_errorSomething failed on FastHire's side. Safe to retry.

Pagination & rate limits

List endpoints are cursor-paginated. Pass limit (default 25, max 100) and cursor from the previous page’s next_cursor.

{
  "data": [ /* … */ ],
  "has_more": true,
  "next_cursor": "eyJpZCI6ImNuZF85..."
}

Every response carries rate-limit headers; the default org limit is 300 requests/minute, shared across all keys on that org.

HeaderMeaning
X-RateLimit-LimitRequests allowed in the current window.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix timestamp when the window resets.

Searches

A search is one AI sourcing run for a role — a natural-language brief, a pasted job description, or a manually-built candidate set. Activating one spins up an agent that scores candidates against mandatory and desirable criteria.

GET/v1/searches

List searches for the org, most recent first.

FieldTypeDescription
statusoptionalstringFilter by agent status.
DRAFTRUNNINGCOMPLETEFAILED
owner_idoptionalstringOnly searches owned by this user.
Response
{
  "data": [
    {
      "id": "src_7bWmA1...",
      "name": "Senior Backend Engineer — Sydney",
      "source_type": "JOB_DESCRIPTION",
      "status": "COMPLETE",
      "result_count": 143,
      "owner_id": "usr_2kTQm...",
      "created_at": "2026-08-12T04:11:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
POST/v1/searches

Create a search and queue its agent. RUNNING is returned immediately; poll the search or listen for the search.completed webhook.

FieldTypeDescription
namerequiredstringInternal label for this search.
source_typerequiredstring
NATURAL_LANGUAGEJOB_DESCRIPTIONMANUAL
criteria.mandatoryrequiredarrayMust-have criteria the agent will not compromise on.
criteria.desirableoptionalarrayNice-to-have criteria used to rank, not filter.
candidate_capoptionalintegerStop sourcing once this many matches are found. Default 200.
Request
curl https://api.thefasthire.com/v1/searches \
  -X POST -H "Authorization: Bearer $FASTHIRE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Senior Backend Engineer — Sydney",
    "source_type": "JOB_DESCRIPTION",
    "criteria": {
      "mandatory": ["5+ years backend", "Right to work in Australia"],
      "desirable": ["Distributed systems", "Fintech background"]
    }
  }'
GET/v1/searches/:id

Retrieve one search, including its agent’s status and criteria.

GET/v1/searches/:id/candidates

List a search’s matched candidates, ranked by score.

FieldTypeDescription
tieroptionalstring
TOP_MATCHGOOD_MATCHPOSSIBLE_MATCH
Response
{
  "data": [
    {
      "candidate_id": "cnd_9mK2pQ...",
      "name": "Priya Nair",
      "headline": "Staff Engineer at Canva",
      "match_score": 0.94,
      "match_tier": "TOP_MATCH",
      "match_reasoning": "7 yrs backend, distributed systems at scale, AU-based."
    }
  ],
  "has_more": true,
  "next_cursor": "eyJpZCI6InNy..."
}

Candidates

A candidate record is deduplicated per org by source profile, and accumulates results, list memberships, sequence history, and interviews as it moves through your pipeline.

GET/v1/candidates/:id

Retrieve a candidate’s full profile.

Response
{
  "id": "cnd_9mK2pQ...",
  "name": "Priya Nair",
  "headline": "Staff Engineer at Canva",
  "email": "priya.nair@example.com",
  "phone": null,
  "linkedin_url": "https://linkedin.com/in/priyanair",
  "location": "Sydney, Australia",
  "education": [ { "school": "UNSW", "degree": "BSc Computer Science" } ],
  "experience": [ { "company": "Canva", "title": "Staff Engineer", "years": 3 } ],
  "skills": ["Go", "Kubernetes", "PostgreSQL"],
  "first_seen_at": "2026-08-12T04:12:31Z"
}
GET/v1/candidates/:id/intake

Fetch the details a candidate supplied after replying with interest — resume link, experience, compensation and availability. Returns 404 if FastHire hasn’t asked this candidate yet (no intake exists until a reply signals interest).

FieldTypeDescription
statusstring
REQUESTEDCOMPLETED
resumestringFree text or a link — however the candidate provided it. No file storage.
total_experience, current_salary, expected_salary, notice_period, interview_availabilitystringSelf-reported, filled in as replies arrive.

Lists

Lists are recruiter-curated candidate sets, independent of any one search — the unit sequences target for outreach.

GET/v1/lists

List the org’s lists.

POST/v1/lists
FieldTypeDescription
namerequiredstringList name.
POST/v1/lists/:id/candidates

Add one or more candidates to a list.

FieldTypeDescription
candidate_idsrequiredarrayUp to 100 candidate ids per call.
DELETE/v1/lists/:id/candidates/:candidate_id

Remove one candidate from a list. Returns 204.

Sequences

A sequence is an outreach campaign: an ordered set of LinkedIn, email, and in-app steps run against one or more target lists.

GET/v1/sequences
FieldTypeDescription
statusoptionalstring
DRAFTACTIVEPAUSEDARCHIVED
POST/v1/sequences

Create a sequence in DRAFT. It only starts sending once activated.

FieldTypeDescription
namerequiredstringCampaign name.
channel_strategyrequiredstring
LINKEDIN_FIRSTINMAIL_FIRSTEMAIL_FIRSTFASTHIRE_FIRST
target_list_idsrequiredarrayLists to enroll candidates from. Active sequences pick up candidates added later, too.
stepsrequiredarrayOrdered steps: channel
LINKEDINEMAILIN_APP
, step_type
CONNECTMESSAGEFOLLOW_UP
, subject (email only), template_body.
PATCH/v1/sequences/:id

Update a sequence’s status — the usual way to activate or pause a campaign.

Request
curl https://api.thefasthire.com/v1/sequences/seq_4LpN.../ \
  -X PATCH -H "Authorization: Bearer $FASTHIRE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "ACTIVE" }'
GET/v1/sequences/:id/candidates

List candidates enrolled in a sequence and where each stands.

FieldTypeDescription
statusstring
NOT_STARTEDIN_PROGRESSREPLIEDBOUNCEDCOMPLETEDPAUSED
next_action_attimestampWhen this candidate's next step is due to send.

Inbox & messages

Every send and reply across LinkedIn, email, and WhatsApp lands in one per-candidate thread.

GET/v1/inbox

List conversations, most recently active first.

FieldTypeDescription
unreadoptionalbooleanOnly conversations with an unread inbound message.
GET/v1/inbox/:candidate_id/messages
Response
{
  "data": [
    {
      "id": "msg_1QvD...",
      "channel": "EMAIL",
      "direction": "INBOUND",
      "body": "Thanks for reaching out — happy to chat this week.",
      "status": "REPLIED",
      "sent_at": "2026-08-19T02:04:00Z",
      "read_at": null
    }
  ]
}
POST/v1/inbox/:candidate_id/messages

Send a reply into an existing thread, on the same channel and connection the candidate last replied on.

FieldTypeDescription
bodyrequiredstringMessage text.
channeloptionalstringDefaults to the channel of the candidate's last inbound message.

Interviews

Interviews link a candidate, a recruiter, and a time — optionally backed by a real Calendar connection.

GET/v1/interviews
FieldTypeDescription
statusoptionalstring
PROPOSEDCONFIRMEDCANCELLEDCOMPLETED
POST/v1/interviews
FieldTypeDescription
candidate_idrequiredstring
recruiter_idrequiredstringMust have an active Calendar connection to auto-create a meeting link.
scheduled_atrequiredtimestampStored as UTC.
timezoneoptionalstringIANA zone for display, e.g. Asia/Kolkata. Defaults to the org’s zone.
meeting_linkoptionalstringSkip auto-generation and set one manually.
PATCH/v1/interviews/:id

Reschedule or update status. A CONFIRMED → CANCELLED transition cancels the linked calendar event, if any.

DELETE/v1/interviews/:id

Cancel an interview. Equivalent to PATCH { "status": "CANCELLED" }; returns 204.

Webhooks

Subscribe to an endpoint from Settings → Developer → Webhooks to be notified as events happen, instead of polling.

EventFires when
search.completedAn agent finishes scoring and its status moves to COMPLETE or FAILED.
candidate.repliedAn inbound message arrives on any channel.
candidate.intake_completedAll six intake fields are captured.
sequence.candidate_completedA candidate finishes, bounces, or pauses in a sequence.
interview.scheduledAn interview is created or confirmed.
Payload envelope
{
  "id": "evt_8pXeC...",
  "type": "candidate.replied",
  "created_at": "2026-08-19T02:04:00Z",
  "data": { /* the object, shaped like its REST response */ }
}

Each request carries an X-FastHire-Signature header — an HMAC-SHA256 of the raw body using your endpoint’s signing secret. Verify it before trusting the payload, and return a 2xx within 10 seconds or FastHire retries with backoff for up to 24 hours.

Status & roadmap

This document is the working spec for FastHire’s public API, generated from the live recruiter data model as of August 2026. Object and field names here are intended to match the eventual implementation exactly, so this page can move from spec to shipped documentation with no renaming pass.

Not yet scoped: candidate CSV import via API (currently UI-only), managing team members/invitations, and org-level billing endpoints. Flag priorities to the FastHire team before the v1 build starts.

FastHire API Reference · Draft v1 · Generated from the current data model, not a live service.