MatchingAgent API Documentation
Welcome to the MatchingAgent API documentation. This guide will help you integrate our AI-powered candidate matching service into your application.
Base URL
https://api.matchingagent.aiAll API requests should be made to this base URL.
Quick Start
Get started with the MatchingAgent API in 3 simple steps:
- Sign up and get your API key
Create an account at matchingagent.ai and generate an API key from your dashboard.
- Make your first request
Use your API key to match multiple candidates against a job offer with
/v1/match-candidates:curl -X POST https://api.matchingagent.ai/v1/match-candidates \ -H "X-API-Key: ma_sk_live_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "offer": { "external_id": "job-456", "title": "Full-Stack Developer", "company": "TechCorp", "required_skills": ["React", "Node.js", "TypeScript"], "seniority_required": "senior" }, "candidates": [ { "external_id": "candidate-001", "name": "Alice Martin", "experience_years": 6, "seniority": "senior", "skills": ["React", "Node.js", "TypeScript", "PostgreSQL"] }, { "external_id": "candidate-002", "name": "Bob Johnson", "experience_years": 3, "seniority": "mid", "skills": ["React", "Python", "Django"] } ] }' - Process the results
The API returns scored matches with detailed breakdowns, recommendations, and automatic pagination for large batches.
3 API Endpoints
POST/v1/match-candidatesMatch up to 5,000 candidates against 1 offer (auto-paginated)
POST/v1/match-offersMatch 1 candidate against up to 100 offers
POST/v1/matching-sessionGet paginated results from large matching requests
Authentication
All API requests require authentication using an API key. Include your API key in the request header:
X-API-Key: ma_sk_live_your_key_hereRate Limits
Rate limits vary by plan tier:
| Plan | Requests/Minute | Monthly Quota |
|---|---|---|
| Pay-as-you-go | 100 | Unlimited (billed per match) |
| Starter | 500 | 15,000 matches |
| Professional | 2,000 | 100,000 matches |
| Enterprise | 10,000 | 500,000 matches |
Usage Quotas
Each plan includes a monthly quota of matches. When you reach 80% of your quota, you'll receive an email warning. When you exceed 100%, API requests will be blocked with a 402 Payment Required response.
Match Candidates Endpoint
Match multiple candidates against a single job offer. This is the primary endpoint for high-volume candidate screening and supports up to 5,000 candidates with automatic pagination.
Request Body
{
"offer": {
"external_id": "string",
"title": "string",
"company": "string",
"required_skills": ["string"],
"nice_to_have_skills": ["string"],
"seniority_required": "junior" | "mid" | "senior" | "lead",
"experience_years_min": number,
"experience_years_max": number
},
"candidates": [{
"external_id": "string",
"name": "string",
"experience_years": number,
"seniority": "junior" | "mid" | "senior" | "lead",
"skills": ["string"],
"location": "string"
}],
"output_language": "en" | "fr" (optional)
}matching_session_id returned to fetch additional pages.Response
{
"success": true,
"request_id": "ma-req-uuid",
"offer_external_id": "job-456",
"matching_session_id": "ms-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"pagination": {
"current_page": 1,
"total_pages": 5,
"total_items": 450,
"items_per_page": 100,
"has_next": true
},
"matches": [{
"candidate_external_id": "candidate-001",
"candidate_name": "Alice Martin",
"score": {
"overall": 9.2,
"confidence": 0.95,
"grade": "A"
},
"breakdown": {
"skills": {
"score": 9.5,
"weight": 0.40,
"details": "3/3 required skills matched + 1 bonus skill"
},
"experience": {
"score": 9.0,
"weight": 0.35,
"details": "6 years vs 4-8 year range"
},
"seniority": {
"score": 10.0,
"weight": 0.25,
"details": "Exact match: senior = senior"
}
},
"analysis": {
"pros": ["All required skills present", "Strong experience match", "Bonus PostgreSQL skill"],
"cons": [],
"recommendation": "STRONGLY_RECOMMEND"
}
}],
"metadata": {
"processing_time_ms": 1850,
"candidates_evaluated": 100
}
}Match Offers Endpoint
Match a single candidate against multiple job offers (up to 100). Useful for candidate-centric workflows where you need to find the best job matches for a candidate.
Request Body
{
"candidate": {
"external_id": "string",
"name": "string",
"experience_years": number,
"seniority": "junior" | "mid" | "senior" | "lead",
"skills": ["string"],
"education": {
"degree": "string",
"field": "string"
},
"location": "string"
},
"offers": [{
"external_id": "string",
"title": "string",
"company": "string",
"required_skills": ["string"],
"nice_to_have_skills": ["string"],
"seniority_required": "junior" | "mid" | "senior" | "lead",
"experience_years_min": number,
"experience_years_max": number
}],
"output_language": "en" | "fr" (optional)
}Matching Session Endpoint
Retrieve paginated results from a large matching request. Use the session_id returned from /v1/match-candidates.
Request Body
{
"session_id": "ms-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"page": 2,
"include_analysis": true,
"lang": "en" (optional)
}Response
{
"success": true,
"session_id": "ms-a1b2c3d4-...",
"page": 2,
"pagination": {
"current_page": 2,
"total_pages": 5,
"total_items": 450,
"items_per_page": 100,
"has_next": true,
"has_previous": true
},
"matches": [...],
"from_cache": false,
"processing_time_ms": 8500
}Pagination for Large Requests
When matching more than 100 candidates against an offer, the API automatically creates a matching session and returns paginated results. Use the matching_session_id to fetch additional pages of results.
# Step 1: Initial request with 500 candidates
response = requests.post("/v1/match-candidates", json={
"offer": {...},
"candidates": [... 500 candidates ...]
})
# Response includes session_id and first 100 results
session_id = response.json()["matching_session_id"]
first_100 = response.json()["matches"]
# Step 2: Get page 2 (candidates 101-200)
page2 = requests.post("/v1/matching-session", json={
"session_id": session_id,
"page": 2
})
# Step 3: Continue for remaining pages...Response Format
{
"success": true,
"request_id": "ma-req-uuid",
"offer_external_id": "job-456",
"matches": [{
"candidate_external_id": "candidate-123",
"candidate_name": "John Doe",
"score": {
"overall": 8.7,
"confidence": 0.92,
"grade": "A-"
},
"breakdown": {
"skills": {
"score": 9.0,
"weight": 0.40,
"details": "2/2 required skills matched"
},
"experience": {
"score": 8.5,
"weight": 0.35,
"details": "5 years vs 3-7 year range"
},
"seniority": {
"score": 10.0,
"weight": 0.25,
"details": "Exact match: senior = senior"
}
},
"analysis": {
"pros": ["All required skills present"],
"cons": [],
"recommendation": "STRONGLY_RECOMMEND"
}
}],
"metadata": {
"processing_time_ms": 1250,
"candidates_evaluated": 1
}
}Python Examples
Match Candidates (Recommended)
Match multiple candidates against a single job offer with automatic pagination:
import requests
api_key = "ma_sk_live_your_key_here"
base_url = "https://api.matchingagent.ai"
headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
# Match multiple candidates against one offer (recommended approach)
payload = {
"offer": {
"external_id": "job-456",
"title": "Full-Stack Developer",
"company": "TechCorp",
"required_skills": ["React", "Node.js", "TypeScript"],
"seniority_required": "senior"
},
"candidates": [
{
"external_id": f"cand-{i}",
"name": f"Candidate {i}",
"skills": ["React", "Node.js", "TypeScript"],
"experience_years": 5,
"seniority": "senior"
}
for i in range(500) # 500 candidates
]
}
response = requests.post(f"{base_url}/v1/match-candidates", headers=headers, json=payload)
data = response.json()
# First 100 results are returned immediately, sorted by score
print(f"Got {len(data['matches'])} matches on page 1")
print(f"Top candidate: {data['matches'][0]['candidate_name']} - Score: {data['matches'][0]['score']['overall']}")
# Use session_id to get more pages
if "matching_session_id" in data:
session_id = data["matching_session_id"]
total_pages = data["pagination"]["total_pages"]
# Fetch all remaining pages
for page in range(2, total_pages + 1):
page_response = requests.post(
f"{base_url}/v1/matching-session",
headers=headers,
json={"session_id": session_id, "page": page}
)
page_data = page_response.json()
print(f"Got {len(page_data['matches'])} matches on page {page}")Match Offers (Alternative)
Match a single candidate against multiple job offers:
import requests
api_key = "ma_sk_live_your_key_here"
base_url = "https://api.matchingagent.ai"
headers = {"X-API-Key": api_key, "Content-Type": "application/json"}
# Match one candidate against multiple offers
payload = {
"candidate": {
"external_id": "candidate-123",
"name": "John Doe",
"experience_years": 5,
"seniority": "senior",
"skills": ["React", "Node.js", "TypeScript"]
},
"offers": [{
"external_id": "job-456",
"title": "Full-Stack Developer",
"required_skills": ["React", "Node.js"],
"seniority_required": "senior"
}]
}
response = requests.post(f"{base_url}/v1/match-offers", headers=headers, json=payload)
if response.status_code == 200:
data = response.json()
for match in data["matches"]:
print(f"Match: {match['offer_title']}")
print(f"Score: {match['score']['overall']}/10")
print(f"Recommendation: {match['analysis']['recommendation']}")
elif response.status_code == 402:
data = response.json()
print(f"Quota exceeded: {data['used']}/{data['quota']}")
else:
print(f"Error: {response.status_code}")Node.js Example
Match Candidates with Pagination
const apiKey = "ma_sk_live_your_key_here";
const baseUrl = "https://api.matchingagent.ai";
const headers = {
"X-API-Key": apiKey,
"Content-Type": "application/json"
};
// Generate 500 test candidates
const candidates = Array.from({ length: 500 }, (_, i) => ({
external_id: `cand-${i}`,
name: `Candidate ${i}`,
skills: ["React", "Node.js", "TypeScript"],
experience_years: Math.floor(Math.random() * 10) + 1,
seniority: ["junior", "mid", "senior"][Math.floor(Math.random() * 3)]
}));
// Match candidates against one offer (recommended)
const payload = {
offer: {
external_id: "job-456",
title: "Full-Stack Developer",
company: "TechCorp",
required_skills: ["React", "Node.js", "TypeScript"],
seniority_required: "senior"
},
candidates
};
const response = await fetch(`${baseUrl}/v1/match-candidates`, {
method: "POST",
headers,
body: JSON.stringify(payload)
});
if (response.ok) {
const data = await response.json();
console.log(`Page 1: ${data.matches.length} matches`);
console.log(`Top candidate: ${data.matches[0].candidate_name}`);
console.log(`Score: ${data.matches[0].score.overall}/10`);
// Fetch remaining pages if needed
if (data.matching_session_id) {
const sessionId = data.matching_session_id;
const totalPages = data.pagination.total_pages;
for (let page = 2; page <= totalPages; page++) {
const pageRes = await fetch(`${baseUrl}/v1/matching-session`, {
method: "POST",
headers,
body: JSON.stringify({ session_id: sessionId, page })
});
const pageData = await pageRes.json();
console.log(`Page ${page}: ${pageData.matches.length} matches`);
}
}
} else if (response.status === 402) {
const data = await response.json();
console.log(`Quota exceeded: ${data.used}/${data.quota}`);
}Error Handling
The API uses standard HTTP response codes:
| Code | Meaning |
|---|---|
| 200 | Success - Request completed successfully |
| 400 | Bad Request - Invalid parameters or malformed JSON |
| 401 | Unauthorized - Invalid or missing API key |
| 402 | Payment Required - Monthly quota exceeded. Upgrade your plan or enable pay-as-you-go. |
| 404 | Not Found - Session not found or expired (for matching-session endpoint) |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Something went wrong on our end |
Quota Exceeded Response (402)
When your monthly quota is exceeded, the API returns:
{
"error": "quota_exceeded",
"message": "Monthly quota exceeded. Please upgrade your plan or enable pay-as-you-go.",
"quota": 15000,
"used": 15234,
"plan_tier": "starter",
"upgrade_url": "https://matchingagent.com/billing/upgrade",
"billing_url": "https://matchingagent.com/billing",
"pay_as_you_go_available": true,
"period_end": "2026-02-01T00:00:00Z"
}