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:

SendThe server
plan_idRuns that plan
intent_idPlans the intent, then runs it
job_description and/or intentDrafts 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.

StatusMeaning
queued, running, fetchingWorking
waiting_for_quotaThe data source is busy. retry_at says when the run continues
completedDone. stop_reason is finish (target reached or ladder exhausted), budget, profile_cap, or time
completed_no_audienceThe plan found nobody new
failedStopped by an error, a revoked key (key_revoked), or a suspended workspace
abortedCancelled

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.

API reference