Updated June 15, 2026
/api/v1/candidates
curl -X POST \
"https://app.recruitsome.com/api/v1/candidates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
const response = await fetch('https://app.recruitsome.com/api/v1/candidates', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json',
},
});
const data = await response.json();
console.log(data);
use Illuminate\Support\Facades\Http;
$response = Http::withToken('YOUR_API_KEY')
->acceptJson()
->post('https://app.recruitsome.com/api/v1/candidates');
$data = $response->json();
Create a new candidate by uploading their resume. The resume is processed asynchronously in the background — the API immediately returns a processing_id you can log as a reference for support questions (there is no progress-lookup endpoint). Once processing is complete, the responsible user receives an assistant request notification within the application.
Authentication
Requires an API key with the candidates:write scope (included in the Chrome Plugin preset). Calls with a key that lacks the scope return a 403 with error code INSUFFICIENT_SCOPE.
How It Works
The candidate creation process is asynchronous and follows this flow:
- Upload: You submit the resume via the API
- Accepted: The API returns
202 Acceptedwith aprocessing_id - Processing: AI extracts candidate information from the resume in the background
- Notification: The user specified by
user_idreceives an assistant request in the application with the result
This is the same processing pipeline used when uploading a resume through the application UI. The candidate is created, enriched, and the user is notified through the normal assistant request flow.
Simple Example
curl -X POST https://app.recruitsome.com/api/v1/candidates \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": 1,
"resume": {
"filename": "john_doe_cv.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf"
}
}'// Read file and convert to base64
async function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
});
}
const resumeFile = document.getElementById('resume-input').files[0];
const resumeBase64 = await fileToBase64(resumeFile);
const response = await fetch('https://app.recruitsome.com/api/v1/candidates', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_id: 1,
resume: {
filename: resumeFile.name,
content: resumeBase64,
mime_type: resumeFile.type
}
})
});
if (response.status === 202) {
const result = await response.json();
console.log('Processing started:', result.data.processing_id);
}import requests
import base64
# Read resume file
with open('resume.pdf', 'rb') as f:
resume_content = base64.b64encode(f.read()).decode('utf-8')
response = requests.post(
'https://app.recruitsome.com/api/v1/candidates',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'user_id': 1,
'resume': {
'filename': 'resume.pdf',
'content': resume_content,
'mime_type': 'application/pdf'
}
}
)
if response.status_code == 202:
result = response.json()
print('Processing started:', result['data']['processing_id'])Response Example
{
"message": "Resume uploaded successfully. The candidate will be created in the background.",
"data": {
"processing_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}With Intake Creation
If the tenant has the Intake feature enabled, you can request that an intake is automatically created for the new candidate:
curl -X POST https://app.recruitsome.com/api/v1/candidates \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": 1,
"resume": {
"filename": "jane_smith_cv.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf"
},
"create_intake": true
}'The create_intake flag is only effective when the tenant has the Intake feature enabled. If the feature is not enabled, this parameter is silently ignored.
Request Fields
Required Fields
| Field | Type | Description |
|---|---|---|
user_id | integer | Required. The tenant user ID to associate the candidate with. This user will receive the assistant request notification. |
resume | object | Required. The resume document to process |
resume.filename | string | Required. Original filename (max 255 chars) |
resume.content | string | Required. Base64 encoded file content |
resume.mime_type | string | Required. MIME type of the file |
Optional Fields
| Field | Type | Description |
|---|---|---|
create_intake | boolean | Request automatic intake creation for the new candidate (requires Intake feature) |
Resume Document
The resume must be base64 encoded and include metadata:
{
"filename": "resume.pdf",
"content": "base64_encoded_content_here",
"mime_type": "application/pdf"
}Supported Document Types
| Allowed MIME Types | Max Size |
|---|---|
application/pdf | 10MB |
application/msword (.doc) | 10MB |
application/vnd.openxmlformats-officedocument.wordprocessingml.document (.docx) | 10MB |
application/zip | 10MB |
application/x-ole-storage | 10MB |
application/octet-stream | 10MB |
The application/zip, application/x-ole-storage, and application/octet-stream types are accepted because browsers and older Word files often misreport .doc/.docx MIME types — pass the type your file API gives you. The file itself should still be a PDF or Word document for the AI processing to succeed.
Warning
Base64 encoding increases file size by approximately 33%. A 10MB file will be approximately 13.3MB when base64 encoded.
Error Handling
Validation Errors (422)
{
"message": "The given data was invalid.",
"errors": {
"user_id": ["The specified user does not exist."],
"resume": ["A resume document is required to create a candidate."],
"resume.mime_type": ["The resume must be a PDF or Word document (application/pdf, application/msword, or application/vnd.openxmlformats-officedocument.wordprocessingml.document)."]
}
}The resume.mime_type message names the primary document types. The endpoint also accepts the fallback MIME types listed under Supported Document Types above — you only see this error when the type is outside the full list.
Invalid Base64 Content (422)
{
"message": "The given data was invalid.",
"errors": {
"resume.content": ["The resume content is not valid base64 encoded data."]
}
}File Size Exceeded (422)
{
"message": "The given data was invalid.",
"errors": {
"resume": ["The resume file size exceeds the maximum allowed limit of 10MB."]
}
}Rate Limiting (429)
The endpoint accepts 10 requests per minute per API key. Exceeding it returns the standard throttle response with a Retry-After header (seconds until the window resets):
{
"message": "Too Many Attempts."
}Server Error (500)
{
"message": "An unexpected error occurred while processing the resume.",
"error": "PROCESSING_FAILED"
}What Happens After Submission
Once the API returns 202 Accepted, the following happens in the background:
- Resume Analysis: AI extracts personal information, work experience, education, and skills from the resume
- Duplicate Detection: The system checks if a candidate with the same email already exists
- Candidate Creation: If the candidate is new, their profile is created with the extracted data
- Enrichment Workflow: Additional AI processing enriches the candidate profile (tag analysis, summary generation)
- Notification: The user specified by
user_idreceives an assistant request with the result
Possible Outcomes
| Scenario | What Happens |
|---|---|
| New candidate | Candidate is created, user receives "candidate created" notification |
| Existing candidate (same email) | Resume is attached for review, user receives "resume review" notification |
| Missing email in resume | Candidate is saved as "pending", user receives "needs completion" notification |
| Processing failure | User receives "processing failed" notification |
Tip
All outcomes result in an assistant request notification to the user — you don't need to poll for status. The user can take appropriate action directly in the application.
Notes
- The
user_idmust reference a valid user within the tenant. This user becomes the "owner" of the candidate and receives all notifications. - Processing usually completes within a few minutes, depending on resume complexity
- The
processing_idis a UUID that can be stored for reference, though the primary notification mechanism is the assistant request - Remember to handle personal data according to GDPR requirements