Analysis
Analysis
Popp's Analysis feature uses AI to screen candidate resumes against job requirements. Upload a CV, and Popp will score the candidate, check mandatory requirements, and provide evidence-backed assessments.
How Analysis Works
┌──────────────────────────────────────────────────────────────────────┐
│ ANALYSIS WORKFLOW │
│ │
│ 1. CREATE ANALYSIS │
│ └─ Define job requirements (mandatory & nice-to-have) │
│ │ │
│ ▼ │
│ 2. SUBMIT CANDIDATES (API) │
│ └─ POST /v1/analysis/candidates with CV (URL or Base64) │
│ │ │
│ ▼ │
│ 3. AI ANALYZES CV │
│ └─ Matches CV content against each requirement │
│ └─ Extracts evidence for matched requirements │
│ └─ Calculates overall score │
│ │ │
│ ▼ │
│ 4. RECEIVE WEBHOOK │
│ └─ CANDIDATE_ANALYSIS_COMPLETED with scores & outcomes │
│ │ │
│ ▼ │
│ 5. PROCESS RESULTS │
│ └─ Update ATS, rank candidates, notify recruiters │
└──────────────────────────────────────────────────────────────────────┘
Key Concepts
| Concept | Description |
|---|---|
| Analysis | A job screening configuration with requirements |
| Requirements | Criteria to evaluate candidates against (skills, experience) |
| Mandatory | Requirements that must be met for a candidate to pass |
| Nice-to-have | Optional requirements that improve the candidate's score |
| Score | Overall score (0-100) based on requirement matching |
| Evidence | Extracted text from CV proving a requirement is met |
Step 1: Create an Analysis
Create an analysis in the Popp platform:
- Navigate to Analysis → Create Analysis
- Enter the job title and description
- Add Requirements:
- Mark critical requirements as Mandatory
- Add nice-to-have requirements as optional
- Save your analysis
- Copy the Analysis ID from your browser's URL bar:
https://ai.joinpopp.com/ranks/a1b2c3d4-5678-90ab-cdef-1234567890ab
└──────────────────────────────────┘
Copy this Analysis ID
Coming Soon: Analysis creation via the API.
Step 2: Submit Candidates
Use the API to submit candidates for analysis. You can provide the CV as a URL or base64-encoded content.
Using Document URL
curl -X POST "https://api.popp.ai/v1/analysis/candidates" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID" \
-H "Content-Type: application/json" \
-d '{
"analysisId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"documentUrl": "https://example.com/resumes/john_doe.pdf",
"firstName": "John",
"lastName": "Doe",
"emailAddress": "[email protected]",
"externalId": "candidate-123"
}'Using Base64-Encoded Document
curl -X POST "https://api.popp.ai/v1/analysis/candidates" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID" \
-H "Content-Type: application/json" \
-d '{
"analysisId": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"documentBase64": "JVBERi0xLjQKJeLjz9...",
"firstName": "John",
"lastName": "Doe",
"externalId": "candidate-123"
}'Using External Analysis ID
If you've set an external ID for your analysis, you can reference it instead:
curl -X POST "https://api.popp.ai/v1/analysis/candidates" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-organization-id: YOUR_ORGANIZATION_ID" \
-H "Content-Type: application/json" \
-d '{
"externalAnalysisId": "your-job-id-123",
"documentUrl": "https://example.com/resumes/john_doe.pdf",
"firstName": "John",
"lastName": "Doe",
"externalId": "candidate-123"
}'Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
analysisId | string | Yes* | The Popp analysis ID |
externalAnalysisId | string | Yes* | Your external reference for the analysis |
documentUrl | string | Yes** | URL to the candidate's CV (publicly accessible) |
documentBase64 | string | Yes** | Base64-encoded CV content |
firstName | string | No | Candidate's first name |
lastName | string | No | Candidate's last name |
emailAddress | string | No | Candidate's email address |
phoneNumber | string | No | Candidate's phone number (E.164 format) |
externalId | string | No | Your external reference ID for the candidate |
*Either analysisId or externalAnalysisId is required
**Either documentUrl or documentBase64 is required
Response
{
"message": "Candidate analysis queued successfully"
}Step 3: Receive Results via Webhook
When analysis completes, you'll receive a CANDIDATE_ANALYSIS_COMPLETED webhook:
{
"event": "CANDIDATE_ANALYSIS_COMPLETED",
"eventId": "evt_abc123",
"eventTimestamp": "2024-01-15T10:30:00.000Z",
"data": {
"recordId": "candidate_xyz789",
"organizationId": "org_123456",
"externalId": "candidate-123",
"externalAnalysisId": "your-job-id-123",
"analysisCandidateUrl": "https://ai.joinpopp.com/ranks/{analysisId}?candidateId={candidateId}",
"totalScoreScaled": 85.5,
"isAllMandatoryRequirementsMet": true,
"requirementOutcomes": [
{
"requirement": "5+ years of software development experience",
"isMandatory": true,
"isMet": true,
"evidence": "7 years of experience as Senior Software Engineer at Tech Corp"
},
{
"requirement": "Experience with React and TypeScript",
"isMandatory": true,
"isMet": true,
"evidence": "4 years of React development, TypeScript proficiency mentioned"
},
{
"requirement": "Leadership experience",
"isMandatory": false,
"isMet": false
}
]
}
}Result Fields
| Field | Type | Description |
|---|---|---|
totalScoreScaled | number | Overall score (0-100) based on requirement matching |
isAllMandatoryRequirementsMet | boolean | Whether all mandatory requirements are satisfied |
requirementOutcomes | array | Detailed results for each requirement |
analysisCandidateUrl | string | Direct link to view the candidate in Popp AI |
Requirement Outcome
| Field | Type | Description |
|---|---|---|
requirement | string | The original requirement text |
isMandatory | boolean | Whether this is a mandatory requirement |
isMet | boolean | Whether the candidate meets this requirement |
evidence | string | Evidence from CV (only present when isMet is true) |
Complete Integration Example
// 1. Submit a candidate for analysis
async function submitCandidateForAnalysis(candidate: {
analysisId: string;
resumeUrl: string;
firstName: string;
lastName: string;
externalId: string;
}) {
const response = await fetch('https://api.popp.ai/v1/analysis/candidates', {
method: 'POST',
headers: {
'x-api-key': process.env.POPP_API_KEY!,
'x-organization-id': process.env.POPP_ORGANIZATION_ID!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
analysisId: candidate.analysisId,
documentUrl: candidate.resumeUrl,
firstName: candidate.firstName,
lastName: candidate.lastName,
externalId: candidate.externalId,
}),
});
return response.json();
}
// 2. Handle the webhook when analysis completes
interface RequirementOutcome {
requirement: string;
isMandatory: boolean;
isMet: boolean;
evidence?: string;
}
interface AnalysisResult {
recordId: string;
externalId: string;
totalScoreScaled: number;
isAllMandatoryRequirementsMet: boolean;
requirementOutcomes: RequirementOutcome[];
analysisCandidateUrl: string;
}
async function handleAnalysisWebhook(payload: {
event: string;
data: AnalysisResult;
}) {
if (payload.event !== 'CANDIDATE_ANALYSIS_COMPLETED') return;
const { data } = payload;
// Update your ATS/CRM with the results
await updateCandidateInATS({
candidateId: data.externalId,
score: data.totalScoreScaled,
qualified: data.isAllMandatoryRequirementsMet,
analysisUrl: data.analysisCandidateUrl,
});
// Auto-advance qualified candidates
if (data.isAllMandatoryRequirementsMet && data.totalScoreScaled >= 80) {
await moveCandidateToNextStage(data.externalId);
await notifyRecruiter({
message: `High-scoring candidate (${data.totalScoreScaled}%) ready for review`,
url: data.analysisCandidateUrl,
});
}
// Log requirement details for reporting
for (const outcome of data.requirementOutcomes) {
console.log(
`${outcome.requirement}: ${outcome.isMet ? '✅' : '❌'}`,
outcome.evidence || '',
);
}
}Use Cases
- High-Volume Screening: Automatically screen hundreds of applicants against job requirements
- ATS Integration: Sync analysis scores and outcomes to your applicant tracking system
- Candidate Ranking: Sort candidates by score to prioritize recruiter review
- Compliance: Ensure consistent, unbiased screening criteria across all candidates
- Time Savings: Reduce manual CV review time
Best Practices
1. Use Specific Requirements
Good:
- "5+ years of experience with Python"
- "Bachelor's degree in Computer Science or related field"
- "Experience leading teams of 3+ people"
Too Vague:
- "Good programming skills"
- "Team player"
2. Mark Critical Requirements as Mandatory
Only mark requirements as mandatory if they are true dealbreakers. Too many mandatory requirements may filter out good candidates.
3. Use External IDs for Tracking
Always provide externalId and externalAnalysisId to easily correlate Popp results with your ATS:
{
"externalAnalysisId": "job-req-12345",
"externalId": "candidate-67890",
...
}API Reference
- Create Analysis Candidate - Submit a candidate for analysis
Next Steps
- Analysis Events - Detailed webhook payload documentation
- Webhooks - Set up webhook endpoints
Updated about 14 hours ago