Alfa API
Applicant intake
When candidates apply through your ATS, send each application to Alfa. Alfa screens the applicant like anyone who applied in Alfa and reports the result with the same webhooks.
Applicant intake needs a platform key with the applications:write scope, and an Alfa job linked to your ATS job.
Sending an applicant
curl -X POST "https://api.welovealfa.com/v1/integration/applications" \
-H "Authorization: Bearer $ALFA_API_KEY" \
-H "Alfa-Company-Id: org_2abcDEF123" \
-H "Content-Type: application/json" \
-d '{"externalJobId":"job_8841","externalCandidateId":"cand_123","externalApplicationId":"appl_456","firstName":"Ada","lastName":"Lovelace","email":"ada@example.com","appliedAt":"2026-10-07T09:30:00Z","resume":{"fileName":"ada-lovelace.pdf","contentType":"application/pdf","contentBase64":"JVBERi0xLjcK…"}}'| Field | Required | Meaning |
|---|---|---|
externalJobId | Required | Your ATS job, linked to an Alfa job. |
externalCandidateId | Required | Your id for the candidate. |
externalApplicationId | Required | Your id for this application. Alfa uses it to spot duplicates. |
firstName, lastName, email | Required | The applicant. |
phone, linkedinUrl, location | Optional | More about the applicant. |
appliedAt | Optional | When they applied, as an ISO 8601 time. |
screeningAnswers | Required when the job has mandatory questions | A list of { question, answer } for the screening questions the job lists in screeningQuestions. Quote each question exactly; an answer is true or false, a number or text. |
resume | Required | An object with fileName, contentType and contentBase64 (the file, base64 encoded). |
Resumes
The resume can be at most 4 MB once decoded (the whole request must stay under 6 MB), its content must match its contentType, and the type must be one of:
application/pdfapplication/mswordapplication/vnd.openxmlformats-officedocument.wordprocessingml.documenttext/plain
Responses and duplicates
202with{ candidateId, jobId, status: "received" }: the applicant was added and will be screened.200withstatus"existing": Alfa already has thisexternalApplicationId. Nothing new is created, and you get the same ids back.
An application counts as received only once its resume is attached and screening is queued. If a request fails before then, for example with invalid_resume, send it again with the same externalApplicationId and a corrected file: Alfa finishes the same application and answers 202.
Sending the same application twice is therefore safe. To retry a request whose response you did not get, you can also send an Idempotency-Key header.
What happens next
- Alfa screens the applicant like any other applicant on the job.
- Alfa sends the applicant no emails; your ATS stays in charge of contacting them.
- The applicant counts toward the company's applicant limit.
candidate.screenedand latercandidate.status_changedwebhooks carry yourexternalCandidateIdandexternalApplicationId, so you can match the result to the application.
Errors
| Status | Code | When |
|---|---|---|
| 422 | ats_job_not_linked | No Alfa job is linked to the ATS job yet. |
| 409 | job_not_accepting_applications | The linked Alfa job is not live, or is full. |
| 409 | application_in_progress | Another request with the same externalApplicationId is still being processed. Retry it shortly. |
| 409 | interview_only_job | The linked Alfa job screens applicants through an AI interview, which applicant intake does not support. |
| 422 | unsupported_resume_type | The contentType is not one listed above. |
| 422 | resume_too_large | The decoded resume is larger than 4 MB. |
| 422 | invalid_resume | The resume is empty, is not valid base64, does not match its contentType, or cannot be read (for example a password-protected PDF). |
| 422 | screening_questions_incomplete | A mandatory screening question has no answer. |
| 422 | unknown_screening_question | An answer quotes a question the job does not have. |
| 422 | validation_failed | A field is missing or invalid. |
| 403 | insufficient_scope | The key does not have the applications:write scope. |
| 429 | rate_limited | More than 60 requests a minute for this key and company. |
See the applicant intake reference, every error code and the changelog.
