API Reference

Programmatically match CVs against job descriptions using the CV Matching API.

Base URL:https://cv-matching-api.fly.dev

Quick Start

  1. Get an API key — Create one from your Account page.
  2. Submit a match job POST /api/match with your CVs and a job description.
  3. Get results — Poll GET /api/match/{job_id} until processing completes.

Authentication

All API requests require an API key. Include it via the X-API-Key header (preferred) or as a Authorization: Bearer token.

Create and manage API keys on your Account page. Keys are created with the match:execute scope by default, which implies match:read.

Note:API keys work for all match endpoints. Some account endpoints (e.g. credit balance) require JWT authentication — use the dashboard for those.
curl https://cv-matching-api.fly.dev/api/match \
  -H "X-API-Key: sk_live_your_key_here" \
  -F "cvs=@resume.pdf" \
  -F "jd_text=Registered Nurse — ICU Department..."

Submit Match Job

POST/api/match

Submit CVs and a job description for matching. The request must be multipart/form-data.

Parameters

FieldTypeRequiredDescription
cvsFile[]YesPDF, DOCX, TXT. Max 5MB each. Batch limit: Free 10, Starter 20, API 25.
jd_fileFileNo*Job description file.
jd_textstringNo*Job description text (max 50,000 chars).

*One of jd_file or jd_text is required.

# With a text JD
curl -X POST https://cv-matching-api.fly.dev/api/match \
  -H "X-API-Key: sk_live_your_key_here" \
  -F "cvs=@resume1.pdf" \
  -F "cvs=@resume2.pdf" \
  -F "jd_text=Warehouse Associate — Day shift, forklift certification preferred..."

# With a file JD
curl -X POST https://cv-matching-api.fly.dev/api/match \
  -H "X-API-Key: sk_live_your_key_here" \
  -F "cvs=@resume.pdf" \
  -F "jd_file=@job_description.pdf"

Response

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "cv_count": 3,
  "message": "Job created. Poll /api/match/{job_id} for results.",
  "skipped_cvs": []
}

Poll Progress

GET/api/match/{job_id}/progress

Check how many CVs have been scored. Poll every 1-2 seconds until status is "completed".

curl https://cv-matching-api.fly.dev/api/match/550e8400-e29b-41d4-a716-446655440000/progress \
  -H "X-API-Key: sk_live_your_key_here"

Response

{
  "status": "processing",
  "total": 3,
  "completed": 1,
  "pending": 1,
  "processing": 1
}

Get Results

GET/api/match/{job_id}

Retrieve the full match results once processing is complete. Each CV receives a score from 0-100 along with a detailed assessment.

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "results": [
    {
      "cv_filename": "alice_chen_resume.pdf",
      "match_score": 82,
      "executive_summary": "Strong backend engineer with 6 years of Python and FastAPI experience. Excellent systems design skills with minor gaps in frontend technologies.",
      "strengths": [
        "6 years of Python development including FastAPI and Django",
        "Strong systems design and distributed systems experience",
        "AWS and Docker deployment experience"
      ],
      "gaps": [
        "No React or frontend framework experience listed",
        "Limited experience with the specific industry domain"
      ],
      "recommendation": "Interview",
      "verdict": "STRONG_MATCH"
    },
    {
      "cv_filename": "bob_smith_resume.pdf",
      "match_score": 31,
      "executive_summary": "Junior developer with limited experience in the required tech stack. Shows potential but lacks seniority for the role.",
      "strengths": [
        "Computer Science degree from reputable university",
        "Some exposure to Python through coursework"
      ],
      "gaps": [
        "Only 1 year of professional experience vs 5+ required",
        "No production API development experience",
        "Missing cloud infrastructure skills"
      ],
      "recommendation": "Not recommended",
      "verdict": "WEAK_MATCH"
    }
  ]
}

Verdicts

VerdictScore RangeRecommendation
STRONG_MATCH75-100Interview
GOOD_MATCH60-74Interview
MODERATE_MATCH40-59Consider
WEAK_MATCH20-39Not recommended
NOT_SUITABLE0-19Not recommended

Complete Example

import time
import requests

API_KEY = "sk_live_your_key_here"
BASE = "https://cv-matching-api.fly.dev"
headers = {"X-API-Key": API_KEY}

# 1. Submit match job
with open("alice.pdf", "rb") as f1, open("bob.pdf", "rb") as f2:
    resp = requests.post(
        f"{BASE}/api/match",
        headers=headers,
        files=[
            ("cvs", ("alice.pdf", f1, "application/pdf")),
            ("cvs", ("bob.pdf", f2, "application/pdf")),
        ],
        data={"jd_text": "Construction Project Manager — 5+ years commercial builds..."},
    )
job = resp.json()
job_id = job["job_id"]
print(f"Job created: {job_id}")

# 2. Poll until complete (timeout after ~4 min)
for _ in range(120):
    progress = requests.get(
        f"{BASE}/api/match/{job_id}/progress", headers=headers
    ).json()
    print(f"  {progress['completed']}/{progress['total']} done")
    if progress["status"] == "completed":
        break
    if progress["status"] == "failed":
        raise RuntimeError("Job failed")
    time.sleep(2)

# 3. Get results
results = requests.get(
    f"{BASE}/api/match/{job_id}", headers=headers
).json()

for r in results["results"]:
    print(f"{r['cv_filename']}: {r['match_score']}/100 — {r['verdict']}")

Credits

Each CV matched against a job description consumes 1 credit. Credits are deducted when a match job is submitted.

Credit Packs

PackPricePer Match
100 credits$1.00$0.010
500 credits$4.00$0.008
1,000 credits$7.00$0.007

Purchase credit packs on the Pricingpage. Check your balance on the dashboard — the GET /api/credits/balance endpoint requires JWT authentication (not an API key).

When your credit balance reaches zero, API requests will return a 402 error.

Rate Limits

API keys are rate limited to 60 requests per minute by default. Limits are tracked per API key using a sliding window.

Response Headers

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets

When rate limited, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait before retrying.

Error Codes

Errors are returned as JSON with a detail field describing the issue.

{
  "detail": "Invalid or missing API key"
}
CodeMeaning
400Bad request (missing fields, invalid file type)
401Invalid or missing API key
402Insufficient credits
404Job not found
429Rate limit exceeded
500Server error

MCP Server (AI Agent Integration)

Use our MCP (Model Context Protocol) server to integrate CV matching into AI assistants like Claude Desktop. The MCP server wraps the same REST API with 3 tools for file-based matching.

Setup

Add this to your Claude Desktop config (claude_desktop_config.json):

{
  "mcpServers": {
    "cv-matching": {
      "command": "python",
      "args": ["~/mcp_server.py"],
      "env": {
        "CV_MATCH_API_URL": "https://cv-matching-api.fly.dev",
        "CV_MATCH_API_KEY": "your-api-key-here"
      }
    }
  }
}

Download mcp_server.py and save it to your home directory. Get your API key from the Account page. Requires pip install mcp httpx.

Tools

match_cvsSubmit CVs for matching
FieldTypeRequiredDescription
cv_pathsstring[]YesAbsolute paths to CV files (PDF, DOCX, TXT)
jd_textstringYesJob description text

Returns: job_id, status, cv_count

get_match_resultsGet results for a completed job
FieldTypeRequiredDescription
job_idstringYesJob ID from match_cvs

Returns: results[] with scores, summaries, strengths, gaps

get_match_progressCheck processing progress
FieldTypeRequiredDescription
job_idstringYesJob ID from match_cvs

Returns: total, completed, pending, status

Example Usage

# In Claude Desktop, just ask:
"Match these CVs against the Senior Engineer JD"

# Claude will use the MCP tools to:
# 1. Call match_cvs with your file paths
# 2. Poll get_match_progress until complete
# 3. Retrieve results with get_match_results
# 4. Present the ranked candidates

Back to Home