docs sourcing
Runs
Start from job text, an intent, or a plan; read candidates; resume without paying twice.
A run executes a plan in the background: it searches tier by tier, fetches full profiles, drops duplicates, suppressed people, and people already seen, and stops at the target or the budget.
Start
POST /v1/runs takes exactly one source:
| Send | The server |
|---|---|
plan_id | Runs that plan |
intent_id | Plans the intent, then runs it |
job_description and/or intent | Drafts the intent, plans it, then runs it |
Add target, budget (max_credits, max_pages, max_profile_fetches), and mark_seen (default true).
{
"job_description": "Backend engineer in Ghent, 3-6 years, Go.",
"intent": { "location": { "countries": ["Belgium"] } },
"budget": { "max_credits": 30 }
}
With ?dry_run=true the response is the plan and the estimate, and nothing is stored or charged. Without it, send an Idempotency-Key. The response is 202 with { "run": …, "plan": … } and a Location header. The same key returns the same run.
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${RECRUITMCP_DOMAIN:-recruitmcp.com}"
BASE="${RECRUITMCP_BASE:-https://api.${DOMAIN}}"
MCP="${RECRUITMCP_MCP:-https://mcp.${DOMAIN}/mcp}"
WS=$(curl -fsS -X POST "$BASE/v1/workspaces" -H 'content-type: application/json' -d '{"name":"Northwind Search","email":"ada@northwind.example"}')
KEY=$(node -e 'process.stdout.write(JSON.parse(process.argv[1]).api_key)' "$WS")
BODY='{"job_description":"Senior backend engineer in Gent, Belgium. Go, 5+ years.","target":40,"budget":{"max_credits":10}}'
ONE=$(curl -fsS -X POST "$BASE/v1/runs" -H "authorization: Bearer $KEY" -H 'content-type: application/json' -H 'idempotency-key: rerun-gent' -d "$BODY")
BAL1=$(curl -fsS "$BASE/v1/workspace" -H "authorization: Bearer $KEY")
TWO=$(curl -fsS -X POST "$BASE/v1/runs" -H "authorization: Bearer $KEY" -H 'content-type: application/json' -H 'idempotency-key: rerun-gent' -d "$BODY")
BAL2=$(curl -fsS "$BASE/v1/workspace" -H "authorization: Bearer $KEY")
node -e 'const [one,two,a,b]=process.argv.slice(1).map((v)=>JSON.parse(v)); if(!one.run?.id||one.run.id!==two.run?.id) process.exit(1); if(a.balance_credits!==b.balance_credits) process.exit(2);' "$ONE" "$TWO" "$BAL1" "$BAL2"
Set budget.max_credits from the estimate's credits_max. The server stops at the budget or when the balance runs out; it does not reserve the whole budget up front.
Follow
Listen for run.completed, run.failed, or run.cancelled on a webhook endpoint, or poll GET /v1/runs/{run_id}. The SDKs have waitForRun / wait_for_run.
| Status | Meaning |
|---|---|
queued, running, fetching | Working |
waiting_for_quota | The data source is busy. retry_at says when the run continues |
completed | Done. stop_reason is finish (target reached or ladder exhausted), budget, profile_cap, or time |
completed_no_audience | The plan found nobody new |
failed | Stopped by an error, a revoked key (key_revoked), or a suspended workspace |
aborted | Cancelled |
progress shows the current tier, people looked at, duplicates skipped, and candidates delivered. spent shows credits, pages, and profile fetches so far.
Read candidates
GET /v1/runs/{run_id}/candidates returns candidates in delivery order, with cursor pagination. Filter before paging with min_years, max_years, max_distance_km, and tier. view=compact returns one flat row per candidate. Send Accept: text/csv for a spreadsheet of every matching candidate.
More, or stop
POST /v1/runs/{run_id}/extend with add_target (default 20) and an optional add_budget continues a finished run from its checkpoints: pages already read are not paid again. It takes dry_run and Idempotency-Key like any paid call.
POST /v1/runs/{run_id}/cancel stops after the current step. Candidates already delivered stay.
Checkpoints are kept per query_key, so a new run with an overlapping plan also skips pages your workspace already paid for.
What it costs
Between credits_min and the budget. Each candidate returned is 1 credit, once. Each live profile is 2 credits. Cached profiles, profiles that no longer exist, duplicates, and suppressed people are free.
Ask Claude
The plan looks right. Confirm with a budget of the maximum, wait for the results, and list the first ten with distance, experience, and current company. No scores.