Why Resume Scoring Should Be an API Call, Not a Custom Build
Every ATS team eventually faces the same crossroads: applicant volume is growing, manual screening can't keep up, and someone proposes building an in-house scoring system.
Don't. Building resume scoring from scratch means maintaining prompt engineering, handling edge cases across hundreds of resume formats, calibrating scores so they're consistent across job types, and paying for GPU infrastructure or LLM API management. That's a product, not a feature.
A scoring API externalizes all of that. Your integration is a single HTTP call — send a resume and a job description, get back a structured score with explanations. You keep your existing workflow, your existing ATS, and your existing tooling. The scoring intelligence lives behind a REST endpoint that you call like any other service.
Stackwright's API scores resumes in under 3 seconds using contextual AI — not keyword matching. It evaluates actual job fit: does this person's experience demonstrate the skills you need, or did they just learn to put "TypeScript" on their resume? The response is structured JSON with numeric scores, strength/weakness analysis, and skill-by-skill matching. Deterministic, auditable, and fast.
By the end of this guide: a working integration that scores resumes via API, parses the structured response, and optionally handles batch processing via webhooks. Total time: about 5 minutes of actual coding.
Prerequisites
You need three things:
- An API key. Use the free demo key below to follow along, or grab your own from the docs page. The demo key gives you 100 calls/day — more than enough to evaluate the API.
- An HTTP client. cURL (comes with macOS/Linux), Node.js 18+, or Python 3.8+ with
requests. - A resume and job description. Plain text. We'll use example data in the snippets, but swap in real content for meaningful scores.
Use sk-sw-demo-stackwright2025 for all examples in this guide. 100 calls/day, no signup, no credit card. Rate limits apply: 10 requests/minute for demo keys.
One endpoint. One POST request. Send a resume and a job description, get a structured score back. Here's the call in all three languages.
cURL
curl -X POST https://stackwright.polsia.app/api/v1/score-resume \
-H "Content-Type: application/json" \
-H "X-API-Key: sk-sw-demo-stackwright2025" \
-d '{
"resume_text": "Sarah Chen. Senior Software Engineer, 6 years experience. Built distributed caching layer handling 50k req/s at Datadog. Led migration from monolith to microservices (Node.js, Go, PostgreSQL). Open-source maintainer of redis-cluster-kit (2.1k stars). AWS certified, strong in system design and observability.",
"job_description": "Senior Backend Engineer. We need someone to design and scale our API infrastructure (Node.js, PostgreSQL). Must have experience with distributed systems, caching, and high-throughput services. 5+ years required."
}'JavaScript (Node.js)
const response = await fetch('https://stackwright.polsia.app/api/v1/score-resume', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'sk-sw-demo-stackwright2025'
},
body: JSON.stringify({
resume_text: 'Sarah Chen. Senior Software Engineer, 6 years...',
job_description: 'Senior Backend Engineer. We need someone to...'
})
});
const score = await response.json();
console.log('Fit score:', score.fit_score);
console.log('Strengths:', score.strengths);
console.log('Gaps:', score.gaps);Python
import requests
response = requests.post(
'https://stackwright.polsia.app/api/v1/score-resume',
headers={
'Content-Type': 'application/json',
'X-API-Key': 'sk-sw-demo-stackwright2025'
},
json={
'resume_text': 'Sarah Chen. Senior Software Engineer, 6 years...',
'job_description': 'Senior Backend Engineer. We need someone to...'
}
)
score = response.json()
print(f"Fit score: {score['fit_score']}")
print(f"Strengths: {score['strengths']}")
print(f"Gaps: {score['gaps']}")That's it. One HTTP call. The API handles prompt engineering, caching (identical inputs return cached results), and response normalization. You get back structured JSON in under 3 seconds.
The API returns a JSON object with everything you need to make a hiring decision. Here's what a real response looks like:
What Each Field Means
80+ = strong match, likely worth interviewing. 60–79 = partial match, review gaps before deciding. Below 60 = significant misalignment with this specific role. Scores are contextual — the same resume scores differently against different job descriptions.
Using scores in your pipeline: Most teams set a threshold (e.g., 70+) to auto-advance candidates to the next stage, review 50–69 manually, and auto-reject below 50. The gaps array feeds directly into interview prep — ask about the areas where the API found weak signal.
The synchronous endpoint works for real-time scoring (candidate applies, score appears in your ATS within 3 seconds). But if you're batch-processing — importing a backlog of 500 resumes, or scoring against a new job description — you'll want async processing.
Stackwright's webhook integration flips the model: instead of your app polling for results, Stackwright pushes scores to your endpoint as they complete. This is how ATS integrations work in production.
Setting Up a Webhook Receiver
import express from 'express';
const app = express();
app.use(express.json());
// Stackwright sends POST to this endpoint when scoring completes
app.post('/webhooks/stackwright/score', (req, res) => {
const { candidate_id, fit_score, strengths, gaps, skill_matches } = req.body;
// Update your database / ATS
console.log(`Candidate ${candidate_id} scored ${fit_score}`);
// Auto-advance high scorers
if (fit_score >= 70) {
// Move to interview stage in your ATS
advanceCandidate(candidate_id, 'interview');
}
res.status(200).json({ received: true });
});
app.listen(3000);Python (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/stackwright/score', methods=['POST'])
def handle_score():
data = request.get_json()
score = data['fit_score']
candidate = data['candidate_id']
print(f"Candidate {candidate} scored {score}")
# Update your ATS, send notifications, etc.
if score >= 70:
advance_candidate(candidate, 'interview')
return jsonify({'received': True}), 200For a full walkthrough of webhook architecture — including retry logic, signature verification, and multi-ATS patterns (Ashby, Greenhouse, Lever) — see How to Automate Resume Screening with ATS Webhooks.
The demo key is for evaluation. When you're ready to run scoring in production, here's the checklist.
Upgrade to Pro
Pro tier removes rate limits and unlocks production features:
- Unlimited API calls — no daily caps, no per-minute throttling
- Priority processing — dedicated capacity, consistent sub-2s response times
- Webhook support — push-based scoring for batch and ATS integration
- Usage dashboard — per-key analytics, cost tracking, error monitoring
Production Best Practices
- Store your API key securely. Use environment variables, not hardcoded strings. Never commit keys to version control.
-
Handle rate limit responses. The API returns
429 Too Many Requestswith aRetry-Afterheader. Implement exponential backoff:
async function scoreWithRetry(payload, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch('https://stackwright.polsia.app/api/v1/score-resume', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.STACKWRIGHT_API_KEY
},
body: JSON.stringify(payload)
});
if (res.status === 429) {
const wait = parseInt(res.headers.get('Retry-After') || '2') * 1000;
await new Promise(r => setTimeout(r, wait * (i + 1)));
continue;
}
return res.json();
}
throw new Error('Max retries exceeded');
}- Validate inputs. Send plain-text resumes (not HTML or PDF binary). If you're extracting from PDFs, strip formatting first — the scoring model works on content, not layout.
- Use caching. The API caches responses by content hash. Identical resume + job description pairs return instantly. Don't re-score unchanged content on your side either.
- Monitor error codes.
400= bad payload (checkresume_textandjob_descriptionare present).401= invalid API key.503= temporary outage (retry). The API returns structured error messages in every failure response.
Rate Limits by Tier
Start scoring resumes now
Use the demo key to test the API immediately. Upgrade to Pro when you're ready for production.
What You Can Build From Here
The scoring endpoint is your foundation. Once it's integrated, the natural next steps are:
- Automated interview questions — Use
POST /api/v1/generate-questionsto create role-specific technical questions based on the score'sgapsarray. Interviewers get targeted questions instead of generic ones. - ATS webhook automation — Connect Ashby, Greenhouse, or Lever webhooks so every applicant is scored the moment they apply. See our webhook integration guide for full setup.
- Candidate ranking — Score all applicants against the same job description, sort by
fit_score, and present recruiters with a pre-ranked shortlist. - Bias auditing — Use the structured
skill_matchesdata to verify scoring consistency across resume styles and backgrounds. See how to build fair scoring for the methodology.
Each extension builds on the same API. No new infrastructure, no new dependencies, no ML pipeline to maintain.
Ready to integrate?
Start scoring resumes in minutes. Free tier ships immediately — no credit card. Pro starts at $49/mo for production scale.