icrack.ai · Developers
Push applicants in, rank and approve them, send AI interview invites, and read structured results — the same engine the recruiter dashboard uses, from your own system. Machine-readable spec: /api/v1/openapi.json.
Create a key under Settings → Integrations (account owners). Send it as a bearer token. Keys see only their own account; 240 requests/minute per key; errors are { "error": { "code", "message" } }.
curl https://YOUR-HOST/api/v1/campaigns \ -H "Authorization: Bearer ick_live_…"
external_id, so retries are safe.interview.completed webhooks, or poll the candidates endpoint./api/v1/campaignsList campaigns.
/api/v1/campaignsCreate a campaign: title, job_title, company_name, job_description (+ ranking_criteria, language, invite_channels, invite_ttl_days, credit_budget).
/api/v1/campaigns/{id}Campaign detail with funnel counts.
/api/v1/campaigns/{id}/candidatesPush up to 100 applicants. Each needs external_id and consent:true plus resume_url | resume_text | resume_base64.
/api/v1/campaigns/{id}/candidatesRanked results and interview outcomes. Filters: funnel, pipeline_stage; paginate with limit & cursor.
/api/v1/campaigns/{id}/rankRank everything unranked. Returns what was done and, if credits ran out, exactly how many were left undone.
/api/v1/campaigns/{id}/approveBody { "candidate_ids": [...] } — only ranked candidates can be approved.
/api/v1/campaigns/{id}/inviteInvite all approved candidates.
/api/v1/candidates/{id}One candidate with ranking evidence and interview outcome.
curl -X POST https://YOUR-HOST/api/v1/campaigns/$CAMPAIGN/candidates \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{
"consent_attested": true,
"candidates": [{
"external_id": "foundit-8841",
"name": "Aisha Khan",
"email": "aisha@example.com",
"phone": "+919811100001",
"resume_url": "https://files.example.com/aisha.pdf"
}]
}'Per-item result: created, duplicate (already ingested — safe to ignore), needs_review (no email could be found), or failed. A row with an email but no resume is a roster entry and goes straight to the approval queue.
Add an endpoint under Settings → Integrations. Events: candidate.ingested, candidate.ranked, candidate.approved, candidate.invited, interview.started, interview.completed, candidate.handoff. Delivery is at-least-once: dedupe on the X-Icrack-Delivery id. Respond 2xx within 8 s; failures retry at 1 min, 5 min, 30 min, 2 h, 12 h.
// Verify (Node)
const [t, v1] = req.headers['x-icrack-signature'].split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', SECRET).update(t + '.' + rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) return res.sendStatus(400);
if (Math.abs(Date.now()/1000 - Number(t)) > 300) return res.sendStatus(400); // replay windowCandidates apply without leaving your site; applications land straight in the campaign.
<script src="https://YOUR-HOST/embed.js" data-client="your-slug" data-role="campaign-slug" async></script>
Prefer we poll you? Expose a read-only endpoint and register it on a campaign. We call GET <url>?since=<cursor> every 15 minutes (optional auth header, stored encrypted):
{ "candidates": [{ "external_id": "…", "name": "…", "email": "…", "phone": "…",
"resume_url": "…" | "resume_text": "…" }],
"next_cursor": "…" }