Bijgewerkt 22 april 2026
/api/v1/applications
curl -X POST \
"https://app.recruitsome.com/api/v1/applications" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
const response = await fetch('https://app.recruitsome.com/api/v1/applications', {
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/applications');
$data = $response->json();
Sollicitatie indienen
Het endpoint voor het indienen van sollicitaties stelt kandidaten in staat om te solliciteren op gepubliceerde vacatures door hun gegevens en ondersteunende documenten te versturen. Dit endpoint ondersteunt het uploaden van meerdere documenten, uitgebreide kandidaatprofielen en trackinginformatie.
Implementatiestrategie
Waarschuwing
Cruciaal implementatiepatroon: Sla sollicitaties altijd lokaal op vóór verzending en implementeer retry-logica. Netwerkfouten, rate limits of tijdelijke serverproblemen mogen nooit leiden tot verloren sollicitaties.
Aanbevolen implementatiestroom
graph TD
A[User Fills Form] --> B[Validate Locally]
B --> C[Store in Local Storage/DB]
C --> D[Submit to API]
D --> E{Response}
E -->|Success 201| F[Clear Local Storage]
E -->|Error 4xx/5xx| G[Keep in Queue]
G --> H[Retry with Backoff]
H --> D
- Valideer invoer lokaal vóór verzending
- Sla sollicitatiegegevens op in lokale opslag of database
- Toon de status aan de gebruiker
- Verstuur naar de API met correcte foutafhandeling
- Bij succes (201): Wis de lokale opslag en toon een bevestiging
- Bij een fout: Bewaar in de wachtrij en implementeer retry met exponentiële backoff
Eenvoudig voorbeeld
Dien een eenvoudige sollicitatie in met alleen de verplichte velden:
``bash cURL
curl -X POST https://app\.recruitsome\.com/api/v1/applications \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vacancy": "senior-software-engineer-amsterdam",
"candidate": {
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]"
}
}'
javascript JavaScript
const applicationData = {
vacancy: "senior-software-engineer-amsterdam",
candidate: {
given_name: "John",
family_name: "Doe",
email: "[email protected]"
}
};
// Sla eerst lokaal op
localStorage.setItem('pending_application', JSON.stringify(applicationData));
try {
const response = await fetch('https://app\.recruitsome\.com/api/v1/applications', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(applicationData)
});
if (response.ok) {
localStorage.removeItem('pending_application');
const result = await response.json();
console.log('Application submitted:', result);
} else {
// Bewaar in local storage voor herpoging
throw new Error(Failed: ${response.status});
}
} catch (error) {
console.error('Submission failed, will retry:', error);
}
python Python
import requests
import json
application_data = {
"vacancy": "senior-software-engineer-amsterdam",
"candidate": {
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]"
}
}
Sla eerst lokaal op (voorbeeld met bestand)
with open('pending_application.json', 'w') as f:
json.dump(application_data, f)
try:
response = requests.post(
'https://app\.recruitsome\.com/api/v1/applications',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json=application_data
)
if response.status_code == 201:
# Gelukt - verwijder lokale opslag
import os
os.remove('pending_application.json')
print('Application submitted:', response.json())
else:
raise Exception(f'Failed: {response.status_code}')
except Exception as e:
print(f'Submission failed, will retry: {e}')
Voorbeeld van een response
json
{
"message": "Application submitted successfully",
"data": {
"id": 456,
"vacancy": {
"id": 123,
"slug": "senior-software-engineer-amsterdam",
"title": "Senior Software Engineer"
},
"candidate": {
"id": 789,
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]"
},
"status": "screening",
"source": "api",
"documents": [],
"submitted_at": "2024-01-20T14:30:00Z",
"created_at": "2024-01-20T14:30:00Z"
}
}
Aanbevolen voorbeeld
Dien een sollicitatie in met alle sterk aanbevolen velden voor de beste kans op succes:
bash cURL
curl -X POST https://app\.recruitsome\.com/api/v1/applications \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vacancy": "senior-software-engineer-amsterdam",
"candidate": {
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]",
"mobile_phone": "+31612345678"
},
"documents": {
"resume": {
"filename": "john_doe_resume.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf"
}
},
"privacy_policy_accepted": true
}'
javascript JavaScript
// Bestand inlezen en converteren naar base64
async function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = reject;
});
}
// Sollicitatie voorbereiden met cv
const resumeFile = document.getElementById('resume-input').files[0];
const resumeBase64 = await fileToBase64(resumeFile);
const applicationData = {
vacancy: "senior-software-engineer-amsterdam",
candidate: {
given_name: "John",
family_name: "Doe",
email: "[email protected]",
mobile_phone: "+31612345678"
},
documents: {
resume: {
filename: resumeFile.name,
content: resumeBase64,
mime_type: resumeFile.type
}
},
privacy_policy_accepted: true
};
// Opslaan en indienen met retry
async function submitWithRetry(data, attempt = 1) {
try {
const response = await fetch('https://app\.recruitsome\.com/api/v1/applications', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.ok) {
localStorage.removeItem('pending_application');
return await response.json();
} else if (response.status === 429 && attempt < 3) {
// Rate limited - opnieuw proberen met backoff
await new Promise(resolve => setTimeout(resolve, attempt * 2000));
return submitWithRetry(data, attempt + 1);
} else {
throw new Error(Mislukt: ${response.status});
}
} catch (error) {
localStorage.setItem('pending_application', JSON.stringify(data));
throw error;
}
}
python Python
import requests
import base64
import time
def submit_with_retry(data, attempt=1):
try:
response = requests.post(
'https://app\.recruitsome\.com/api/v1/applications',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json=data
)
if response.status_code == 201:
return response.json()
elif response.status_code == 429 and attempt < 3:
# Rate limited - opnieuw proberen met backoff
time.sleep(attempt * 2)
return submit_with_retry(data, attempt + 1)
else:
response.raise_for_status()
except Exception as e:
# Opslaan voor latere retry
with open('pending_application.json', 'w') as f:
json.dump(data, f)
raise
Cv-bestand inlezen
with open('resume.pdf', 'rb') as f:
resume_content = base64.b64encode(f.read()).decode('utf-8')
application_data = {
"vacancy": "senior-software-engineer-amsterdam",
"candidate": {
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]",
"mobile_phone": "+31612345678"
},
"documents": {
"resume": {
"filename": "john_doe_resume.pdf",
"content": resume_content,
"mime_type": "application/pdf"
}
},
"privacy_policy_accepted": True
}
result = submit_with_retry(application_data)
Volledig voorbeeld
Dien een uitgebreide sollicitatie in met alle beschikbare velden:
bash cURL
curl -X POST https://app\.recruitsome\.com/api/v1/applications \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vacancy": 123,
"candidate": {
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]",
"mobile_phone": "+31612345678",
"fixed_phone": "+31201234567"
},
"documents": {
"resume": {
"filename": "john_doe_resume.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf"
},
"cover_letter": {
"filename": "cover_letter.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf"
},
"additional": [
{
"filename": "portfolio.pdf",
"content": "JVBERi0xLjQKJeLj...",
"mime_type": "application/pdf",
"description": "My design portfolio"
}
]
},
"privacy_policy_accepted": true,
"tracking": {
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"referrer": "https://jobboard.com/jobs/123"
}
}'
Requestvelden
Verplichte velden
Veld Type Beschrijving vacancy string\ integer Verplicht. Vacature-identificatie (slug, publication_slug of ID) candidate.given_name string Verplicht. Voornaam (max 255 tekens) candidate.family_name string Verplicht. Achternaam (max 255 tekens) candidate.email string Verplicht. Geldig e-mailadres (max 255 tekens)
Sterk aanbevolen velden
<div class="not-prose rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-800 dark:bg-amber-900/20"><p class="font-medium text-amber-800 dark:text-amber-300">Waarschuwing</p><p class="mt-1 text-sm text-amber-700 dark:text-amber-400">Sollicitaties zonder deze velden hebben een aanzienlijk lagere slagingskans en kunnen automatisch worden afgewezen door AI-screening.</p></div>
Veld Type Beschrijving documents.resume object Sterk aanbevolen. CV/resumédocument candidate.mobile_phone string Sterk aanbevolen. Mobiel nummer in E.164-formaat (bijv. +31612345678) privacy_policy_accepted boolean Sterk aanbevolen. Expliciete toestemming voor gegevensverwerking
Optionele velden
Veld Type Beschrijving candidate.fixed_phone string Vast telefoonnummer in E.164-formaat candidate.linkedin_url string LinkedIn-profiel-URL (max 255 tekens) documents.cover_letter object Motivatiebrief documents.additional array Maximaal 5 aanvullende documenten tracking.ip_address string IP-adres van de kandidaat tracking.user_agent string Browser user agent (max 1000 tekens) tracking.referrer string Verwijzings-URL (max 1000 tekens)
Documenten uploaden
Documenten moeten base64-gecodeerd zijn en metadata bevatten:
Documentstructuur
json
{
"filename": "document.pdf",
"content": "base64_encoded_content_here",
"mime_type": "application/pdf"
}
Ondersteunde documenttypen
Categorie Toegestane MIME-types Max. grootte CV application/pdf<br/>application/msword<br/>application/vnd.openxmlformats-officedocument.wordprocessingml.document 5MB Motivatiebrief Zelfde als CV 5MB Aanvullend Zelfde als CV + image/jpeg, image/png 20MB
<div class="not-prose rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800"><p class="mt-1 text-sm text-gray-700 dark:text-gray-300">- Maximaal 5 aanvullende documenten
- Maximale grootte van het totale verzoek: 30MB
- Base64-codering vergroot de bestandsgrootte met ~33%</p></div>
Voorbeeld van document uploaden
javascript
// Helper function to convert file to base64
async function prepareDocument(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const base64 = reader.result.split(',')[1];
resolve({
filename: file.name,
content: base64,
mime_type: file.type
});
};
reader.onerror = reject;
});
}
// Process multiple files
const resumeFile = document.getElementById('resume').files[0];
const coverLetterFile = document.getElementById('cover-letter').files[0];
const additionalFiles = document.getElementById('additional').files;
const documents = {
resume: await prepareDocument(resumeFile),
cover_letter: coverLetterFile ? await prepareDocument(coverLetterFile) : undefined,
additional: []
};
// Add additional documents
for (let i = 0; i < Math.min(additionalFiles.length, 5); i++) {
documents.additional.push(await prepareDocument(additionalFiles[i]));
}
javascript+31612345678Telefoonnummerformaat
Telefoonnummers moeten in het internationale E.164-formaat zijn:
Geldige voorbeelden
(Nederlands mobiel)+12125551234(Amerikaans nummer)+447911123456(Brits mobiel)+33612345678(Frans mobiel)0612345678Ongeldige voorbeelden
(landcode ontbreekt)+31 6 1234 5678(bevat spaties)+31-6-12345678(bevat streepjes)(06) 12345678(verkeerd formaat)Hulpfunctie voor telefoonvalidatie
function validateE164(phone) {
const e164Regex = /^\+[1-9]\d{6,14}$/;
return e164Regex.test(phone);
}
function formatPhoneForE164(phone, countryCode = '31') {
// Remove all non-digits
let cleaned = phone.replace(/\D/g, '');
// Remove leading zeros
cleaned = cleaned.replace(/^0+/, '');
// Add country code if missing
if (!cleaned.startsWith(countryCode)) {
cleaned = countryCode + cleaned;
}
// Add + prefix
return '+' + cleaned;
}
// Examples
formatPhoneForE164('06-12345678', '31'); // +31612345678
formatPhoneForE164('(202) 555-1234', '1'); // +12025551234
jsonvacancyVacature-identificatie
Het
veld accepteert drie typen identifiers:123
- Numeriek ID:
"senior-software-engineer"Vacature-slug: "senior-software-engineer-amsterdam"Publicatie-slug: <div class="not-prose rounded-lg border border-emerald-200 bg-emerald-50 p-4 dark:border-emerald-800 dark:bg-emerald-900/20"><p class="font-medium text-emerald-800 dark:text-emerald-300">Tip</p><p class="mt-1 text-sm text-emerald-700 dark:text-emerald-400">Gebruik de publicatie-slug uit de vacaturelijst-API voor de meest betrouwbare matching.</p></div>
Foutafhandeling
Validatiefouten (422)
{
"message": "The given data was invalid.",
"errors": {
"candidate.email": [
"The candidate's email address is required."
],
"candidate.mobile_phone": [
"The candidate.mobile phone field must be a valid phone number."
],
"documents.resume": [
"The file size exceeds the maximum allowed limit."
]
}
}
Bedrijfslogicafouten
Vacature niet gevonden (404)
json
{
"message": "Vacancy not found",
"error": "VACANCY_NOT_FOUND"
}
Vacature gesloten (400)
json
{
"message": "This vacancy is no longer accepting applications",
"error": "VACANCY_CLOSED"
}
Rate Limiting (429)
json
{
"message": "Too many requests. Please try again later.",
"retry_after": 60
}
<div class="not-prose rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-800 dark:bg-amber-900/20"><p class="font-medium text-amber-800 dark:text-amber-300">Waarschuwing</p><p class="mt-1 text-sm text-amber-700 dark:text-amber-400">Rate limit: 10 verzoeken per minuut per API key</p></div>
Best practices voor implementatie
1. Local Storage Pattern
javascript
class ApplicationQueue {
constructor() {
this.storageKey = 'pending_applications';
}
add(applicationData) {
const queue = this.getAll();
queue.push({
id: Date.now(),
data: applicationData,
attempts: 0,
lastAttempt: null
});
localStorage.setItem(this.storageKey, JSON.stringify(queue));
}
getAll() {
const stored = localStorage.getItem(this.storageKey);
return stored ? JSON.parse(stored) : [];
}
remove(id) {
const queue = this.getAll().filter(item => item.id !== id);
localStorage.setItem(this.storageKey, JSON.stringify(queue));
}
async processQueue() {
const queue = this.getAll();
for (const item of queue) {
if (item.attempts >= 3) continue; // Maximaal aantal pogingen bereikt
try {
await this.submit(item.data);
this.remove(item.id);
} catch (error) {
item.attempts++;
item.lastAttempt = Date.now();
this.update(item);
}
}
}
}
2. Validatie vóór verzending
javascript
function validateApplication(data) {
const errors = {};
// Verplichte velden
if (!data.candidate?.given_name?.trim()) {
errors['candidate.given_name'] = 'Voornaam is verplicht';
}
if (!data.candidate?.family_name?.trim()) {
errors['candidate.family_name'] = 'Achternaam is verplicht';
}
if (!data.candidate?.email || !isValidEmail(data.candidate.email)) {
errors['candidate.email'] = 'Een geldig e-mailadres is verplicht';
}
// Sterk aanbevolen velden
const warnings = {};
if (!data.documents?.resume) {
warnings.resume = 'Het toevoegen van een cv vergroot je kansen aanzienlijk';
}
if (!data.candidate?.mobile_phone) {
warnings.mobile_phone = 'Een mobiel nummer helpt recruiters om je snel te bereiken';
}
if (!data.privacy_policy_accepted) {
warnings.privacy = 'Je moet het privacybeleid accepteren';
}
return { errors, warnings, isValid: Object.keys(errors).length === 0 };
}
3. Voortgangsfeedback
javascript
class ApplicationSubmitter {
constructor(onProgress) {
this.onProgress = onProgress;
}
async submit(data) {
this.onProgress({ status: 'validating', progress: 10 });
const validation = validateApplication(data);
if (!validation.isValid) {
throw new ValidationError(validation.errors);
}
this.onProgress({ status: 'preparing', progress: 30 });
// Lokaal opslaan
this.onProgress({ status: 'saving_locally', progress: 40 });
localStorage.setItem('current_application', JSON.stringify(data));
// Verzenden
this.onProgress({ status: 'submitting', progress: 60 });
try {
const response = await fetch('/api/v1/applications', {
method: 'POST',
headers: {
'Authorization': Bearer ${API_KEY},
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
this.onProgress({ status: 'processing_response', progress: 80 });
if (response.ok) {
localStorage.removeItem('current_application');
this.onProgress({ status: 'complete', progress: 100 });
return await response.json();
} else {
throw new SubmissionError(response.status, await response.text());
}
} catch (error) {
this.onProgress({ status: 'error', progress: 0, error });
throw error;
}
}
}
4. Duplicaatpreventie
javascript
function generateApplicationHash(data) {
const key = ${data.vacancy}_${data.candidate.email}_${Date.now()};
return btoa(key);
}
function isDuplicateSubmission(data, timeWindowMs = 60000) {
const hash = generateApplicationHash(data);
const submissions = JSON.parse(localStorage.getItem('recent_submissions') || '[]');
// Oude inzendingen opschonen
const cutoff = Date.now() - timeWindowMs;
const recent = submissions.filter(s => s.timestamp > cutoff);
// Controleren op duplicaat
if (recent.some(s => s.hash === hash)) {
return true;
}
// Nieuwe inzending toevoegen
recent.push({ hash, timestamp: Date.now() });
localStorage.setItem('recent_submissions', JSON.stringify(recent));
return false;
}
Je integratie testen
Testscenario's
- Succesgeval: Geldige sollicitatie met alle verplichte velden
- Validatiefouten: Ontbrekende verplichte velden, ongeldige formaten
- Netwerkfouten: Timeout, verbindingsfouten
- Rate limiting: Verstuur 11 verzoeken binnen een minuut
- Grote bestanden: Test met een cv van 5 MB
- Meerdere documenten: Test met cv + motivatiebrief + 5 extra bijlagen
Testdata
javascript
const testApplication = {
vacancy: "test-vacancy-slug",
candidate: {
given_name: "Test",
family_name: "User",
email: "[email protected]",
mobile_phone: "+31612345678"
},
documents: {
resume: {
filename: "test_resume.pdf",
content: "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoKMiAwIG9iago8PC9UeXBlL1BhZ2VzL0tpZHNbMyAwIFJdL0NvdW50IDE+PgplbmRvYmoKMyAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDIgMCBSL1Jlc291cmNlczw8L0ZvbnQ8PC9GMSA0IDAgUj4+Pj4vTWVkaWFCb3hbMCAwIDYxMiA3OTJdL0NvbnRlbnRzIDUgMCBSPj4KZW5kb2JqCjQgMCBvYmoKPDwvVHlwZS9Gb250L1N1YnR5cGUvVHlwZTEvQmFzZUZvbnQvSGVsdmV0aWNhPj4KZW5kb2JqCjUgMCBvYmoKPDwvTGVuZ3RoIDQ0Pj4Kc3RyZWFtCkJUIC9GMSAxMiBUZiAxMDAgNzAwIFRkIChUZXN0IFJlc3VtZSkgVGogRVQKZW5kc3RyZWFtCmVuZG9iagp4cmVmCjAgNgowMDAwMDAwMDAwIDY1NTM1IGYKMDAwMDAwMDAxNSAwMDAwMCBuCjAwMDAwMDAwNzQgMDAwMDAgbgowMDAwMDAwMTMxIDAwMDAwIG4KMDAwMDAwMDIyOSAwMDAwMCBuCjAwMDAwMDAzMDYgMDAwMDAgbgp0cmFpbGVyCjw8L1NpemUgNi9Sb290IDEgMCBSPj4Kc3RhcnR4cmVmCjQwMgolJUVPRg==",
mime_type: "application/pdf"
}
},
privacy_policy_accepted: true
};
``
Vergeet niet om persoonsgegevens te verwerken conform de AVG-vereisten. Verzamel alleen de noodzakelijke informatie en zorg ervoor dat de juiste toestemmingsmechanismen zijn ingericht.