API Reference

Screenly's REST API lets you build jobs, upload resumes, and pull ranked candidates from any tool — Zapier, Make, internal HRIS, or your own dashboard.

Authentication

All API requests use a Bearer token. Create one in Settings → API keys. Tokens are scoped — a key with only jobs:read can list jobs but cannot create or modify them.

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Rate limits: 10 req/s reads, 20 req/s writes, 5 req/s multipart uploads (per IP+route). Slow down if you receive 429.

Scopes

ScopeDescription
jobs:readList and fetch jobs and their candidates.
jobs:writeCreate, update, archive jobs.
candidates:readRead candidate profiles, scores, and rankings.
candidates:writeUpdate recruiter status / notes; trigger re-evaluation; remove candidates.
resumes:readDownload original resume files via presigned URLs.
resumes:writeUpload new resumes (multipart).
*All scopes. Tread carefully — only for trusted integrations.

Endpoints

Base URL: https://screenly.qubith.in · All endpoints are mounted under /api/v1.

Jobs

Create, list, update, archive jobs.

GET/api/v1/jobsscope: jobs:read

List jobs in your company. Supports pagination via limit and offset.

Request

curl https://screenly.qubith.in/api/v1/jobs?limit=50&offset=0 \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "jobs": [
    { "id": 42, "title": "Senior Frontend Engineer",
      "description": "5+ years React, TypeScript…",
      "status": "active", "created_at": "2026-09-29T…" }
  ],
  "total": 7, "limit": 50, "offset": 0
}
GET/api/v1/jobs/:idscope: jobs:read

Get a single job with its top 200 ranked candidates.

Request

curl https://screenly.qubith.in/api/v1/jobs/42 \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "job": { "id": 42, "title": "…", "description": "…", "status": "active" },
  "candidates": [
    { "id": 1001, "candidate_name": "Priya Sharma",
      "overall_score": 92, "fit_classification": "STRONG_FIT" }
  ]
}
POST/api/v1/jobsscope: jobs:write

Create a new job. Description is the JD text the ranker uses (min 20 chars).

Request

curl -X POST https://screenly.qubith.in/api/v1/jobs \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Frontend Engineer",
    "description": "5+ years React. TypeScript. Ship to production. …"
  }'

Response

{
  "ok": true,
  "id": 43,
  "job": { "id": 43, "title": "Senior Frontend Engineer",
           "description": "5+ years React…", "status": "active" }
}
PATCH/api/v1/jobs/:idscope: jobs:write

Update a job. Any of title, description, or status (active | archived).

Request

curl -X PATCH https://screenly.qubith.in/api/v1/jobs/43 \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Staff Frontend Engineer", "status": "archived" }'

Response

{ "ok": true, "id": 43 }
DELETE/api/v1/jobs/:idscope: jobs:write

Soft-archive a job (status='deleted'). Candidates and history are preserved.

Request

curl -X DELETE https://screenly.qubith.in/api/v1/jobs/43 \
  -H "Authorization: Bearer sk_live_…"

Response

{ "ok": true, "id": 43, "status": "deleted" }

Resumes

Upload resume files and download originals.

POST/api/v1/jobs/:jobId/resumesscope: resumes:write

Upload one or more resume files (multipart, field name: files). PDF or text. Up to 5 MB per file, 50 files per request. Scoring runs asynchronously — poll the returned candidate IDs.

Request

curl -X POST https://screenly.qubith.in/api/v1/jobs/42/resumes \
  -H "Authorization: Bearer sk_live_…" \
  -F "files=@priya_sharma.pdf" \
  -F "files=@arjun_patel.pdf" \
  -F "files=@neha_verma.txt"

Response

{
  "ok": true,
  "job_id": 42,
  "batch_id": 8812,
  "uploaded": 3,
  "failed": 0,
  "resume_ids": [12001, 12002, 12003],
  "errors": []
}
GET/api/v1/candidates/:id/downloadscope: resumes:read

Get a 1-hour presigned URL to download the original resume file.

Request

curl https://screenly.qubith.in/api/v1/candidates/12001/download \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "url": "https://tigris.example/screenly/…?X-Amz-Signature=…",
  "expires_in": 3600,
  "filename": "priya_sharma.pdf"
}

Candidates

Read ranked candidates, update status/notes, trigger re-evaluation.

GET/api/v1/jobs/:jobId/candidatesscope: candidates:read

List ranked candidates for a job. Filter by min_score, status (new|shortlisted|rejected|interview|hired), or free-text q on name/email. Paginated.

Request

curl "https://screenly.qubith.in/api/v1/jobs/42/candidates?min_score=70&status=shortlisted&limit=50" \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "job_id": 42,
  "candidates": [
    { "id": 12001, "candidate_name": "Priya Sharma",
      "email": "priya@example.com", "phone": "+91-9876543210",
      "overall_score": 92, "fit_classification": "STRONG_FIT",
      "skills_score": 95, "experience_score": 90,
      "education_score": 88, "location_score": 92,
      "red_flags": false, "recruiter_status": "shortlisted",
      "processed_at": "2026-09-29T17:43:12.000Z",
      "created_at": "2026-09-29T17:42:50.000Z" }
  ],
  "total": 14, "limit": 50, "offset": 0
}
GET/api/v1/candidates/:idscope: candidates:read

Get one candidate's full record — scores, summary, strengths, gaps, notes.

Request

curl https://screenly.qubith.in/api/v1/candidates/12001 \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "id": 12001, "job_id": 42, "candidate_name": "Priya Sharma",
  "email": "priya@example.com", "phone": "+91-9876543210",
  "overall_score": 92, "fit_classification": "STRONG_FIT",
  "fit_probability": 0.92,
  "skills_score": 95, "experience_score": 90,
  "education_score": 88, "location_score": 92,
  "red_flags": false,
  "summary_text": "Senior FE with 6 yrs of React + TS at consumer startups.",
  "strengths_json": ["Strong React/TS fundamentals", "Shipped 0-to-1 product"],
  "gaps_json": ["No prior fintech experience"],
  "recruiter_status": "shortlisted",
  "notes": "Phone screen passed. Take-home next.",
  "processed_at": "2026-09-29T17:43:12.000Z"
}
PATCH/api/v1/candidates/:idscope: candidates:write

Update recruiter status (new|shortlisted|rejected|interview|hired) and/or notes (max 5000 chars).

Request

curl -X PATCH https://screenly.qubith.in/api/v1/candidates/12001 \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "status": "interview", "notes": "Round 2 scheduled Fri 4pm" }'

Response

{ "ok": true, "id": 12001 }
POST/api/v1/candidates/:id/evaluatescope: candidates:write

Re-score a candidate against the current JD. Useful after JD edits or to refresh stale scores. Async — poll the candidate record for the new score.

Request

curl -X POST https://screenly.qubith.in/api/v1/candidates/12001/evaluate \
  -H "Authorization: Bearer sk_live_…"

Response

{
  "ok": true, "id": 12001, "status": "pending",
  "message": "Resume re-queued for scoring. Poll GET /candidates/:id for status."
}
DELETE/api/v1/candidates/:idscope: candidates:write

Permanently remove a candidate and their resume file from your tenant.

Request

curl -X DELETE https://screenly.qubith.in/api/v1/candidates/12001 \
  -H "Authorization: Bearer sk_live_…"

Response

{ "ok": true, "id": 12001 }

Error codes

CodeWhenFix
400Bad request body / missing fieldCheck the schema. The error message names the missing/invalid field.
401No / invalid API keyCheck Authorization header. Key may have been revoked.
403Key lacks required scopeCreate a new key with the scope listed above.
404ID doesn't exist in your tenantList the parent resource (e.g. GET /jobs) to get valid IDs.
413File too largeResume files must be ≤ 5 MB each. Compress or split the batch.
429Rate limit exceededSlow down. Retry after the Retry-After header (seconds).

Webhooks

Subscribe to events at Settings → Webhooks. Payloads are signed with HMAC-SHA256 — verify X-Screenly-Signature using your webhook secret before trusting.

EventWhen
candidate.scoredFired after upload or re-evaluation finishes.
candidate.stage_changedFired when recruiter_status changes (via PATCH).
job.createdFired when a job is created.
payment.completedFired on successful billing.

Payload (candidate.scored)

{
  "event": "candidate.scored",
  "company_id": 6,
  "payload": {
    "resume_id": 1001,
    "job_id": 42,
    "candidate_name": "Priya Sharma",
    "overall_score": 92,
    "fit_classification": "STRONG_FIT"
  },
  "sent_at": "2026-09-29T17:43:12.000Z"
}

Ready to integrate?

Create an API key in Settings, then make your first call in under a minute.

Open Settings