Upload CVs
Upload candidate CVs to automatically extract structured information like work experience, skills, and contact details. Our AI-powered parsing eliminates manual data entry and builds your searchable talent database.
Quick Start
Choose your upload method and get started in minutes:
Perfect for automation - just provide a URL to your CV file:
# Upload from public URL (ONE request!)
curl -X POST "https://api.floreal.aiv1/public/documents/upload-from-url" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://drive.google.com/uc?export=download&id=1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc",
"documentName": "John Doe - Software Engineer",
"documentDate": "11-2025"
}'
# Check status (poll every 5 seconds)
curl "https://api.floreal.aiv1/public/documents/DOCUMENT_ID" \
-H "X-API-Key: YOUR_API_KEY"Simple single-step - upload file bytes directly:
curl -X POST "https://api.floreal.aiv1/public/documents/upload-direct?documentName=John%20Doe&documentDate=11-2025" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/pdf" \
--data-binary @resume.pdfFor large files - upload directly to S3 (3 steps):
# Step 1: Get presigned URL
curl -X POST "https://api.floreal.aiv1/public/documents/upload-presigned" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"fileName":"resume.pdf","contentType":"application/pdf","fileSize":245760}'
# Step 2: Upload to S3
curl -X PUT "PRESIGNED_URL" \
-H "Content-Type: application/pdf" \
--data-binary @resume.pdf
# Step 3: Finalize
curl -X POST "https://api.floreal.aiv1/public/documents/upload-presigned-finalize" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"uploadId":"...","documentName":"John Doe","documentDate":"11-2025"}'Processing takes 30 to 90 seconds. Once status: "completed", you get the full parsed candidate data.
Why Upload CVs?
🚀 Speed up screening
Extract key qualifications instantly from hundreds of CVs
🎯 Build talent database
Automatically parse and store candidate information
🔍 Search candidates
Find qualified candidates based on parsed skills and experience
🔗 Integrate with ATS
Connect CV parsing to your recruitment workflow
What You Need
Before you start, make sure you have:
✅ API Key - Get yours from your dashboard
✅ CV Files - PDF, DOC, DOCX, or TXT (max 10 MB each)
✅ HTTP Client - cURL, Postman, or any programming language
Choose Your Upload Method
We offer three ways to upload CVs - pick the one that fits your use case:
🌟 Method 1: Upload from URL (Recommended)
Best for: Webhooks, ATS integrations, batch imports, automation
Pros:
- ✅ Simplest method (1 request)
- ✅ No file handling on your end
- ✅ Perfect for automation
- ✅ Works with S3, Google Drive, Dropbox URLs
How it works: Provide a public URL to your CV file, and our server fetches, processes, and parses it automatically.
Perfect for integrations! If CVs are already hosted (S3, Drive, Dropbox), this is the easiest method.
📤 Method 2: Direct Upload
Best for: Quick integration, small to medium files, simple workflows
Pros:
- ✅ Single request
- ✅ Simple implementation
- ✅ Works with local files
- ✅ Good for small to medium files (up to 10MB)
How it works: Send CV file bytes directly in the request body with metadata in query parameters.
🚀 Method 3: Presigned URL (Advanced)
Best for: Large files, browser uploads, bandwidth optimization
Pros:
- ✅ Fastest for large files
- ✅ Direct-to-S3 upload
- ✅ Better for concurrent uploads
- ✅ Scales better
Cons:
- ❌ More complex (3 steps)
- ❌ More implementation code
How it works: Get a presigned S3 URL, upload directly to S3, then finalize the document record.
File Requirements
| Requirement | Details |
|---|---|
| Max Size | 10 MB per file |
| Formats | PDF (recommended), DOCX, DOC, TXT |
| URL Requirements | Must be publicly accessible, direct file link (not HTML page) |
| Languages | English, French, German, Spanish, and more |
| Layout | Simple single-column works best |
Timeline:
- 0 to 15s: File fetched/uploaded and validated
- 15 to 50s: AI analyzes CV content
- 50 to 90s: Data extracted, embedded, and indexed
- Result: Fully searchable candidate profile
Step-by-Step: Upload from URL (Easiest)
Step 1: Prepare Your URL
Make sure your URL is a direct file link, not a sharing page:
Common Mistakes:
❌ Google Drive sharing link: https://drive.google.com/file/d/FILE_ID/view?usp=sharing
✅ Direct download link: https://drive.google.com/uc?export=download&id=FILE_ID
❌ Dropbox preview link: https://dropbox.com/s/abc/file.pdf?dl=0
✅ Direct download link: https://dropbox.com/s/abc/file.pdf?dl=1
Test your URL:
# Should return Content-Type: application/pdf (not text/html)
curl -I "https://your-url.com/file.pdf"Step 2: Upload from URL
Send your CV URL to the API:
curl -X POST "https://api.floreal.aiv1/public/documents/upload-from-url" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://drive.google.com/uc?export=download&id=1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc",
"documentName": "John Doe - Software Engineer",
"documentType": "cv",
"documentDate": "11-2025"
}'const response = await fetch(
'https://api.floreal.aiv1/public/documents/upload-from-url',
{
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://drive.google.com/uc?export=download&id=1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc',
documentName: 'John Doe - Software Engineer',
documentType: 'cv',
documentDate: '11-2025'
})
}
);
const { documentId } = await response.json();
console.log('Upload started! Document ID:', documentId);import requests
response = requests.post(
'https://api.floreal.aiv1/public/documents/upload-from-url',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'url': 'https://drive.google.com/uc?export=download&id=1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc',
'documentName': 'John Doe - Software Engineer',
'documentType': 'cv',
'documentDate': '11-2025'
}
)
document_id = response.json()['documentId']
print(f'Upload started! Document ID: {document_id}')Response:
{
"documentId": "789e4567-e89b-12d3-a456-426614174000",
"status": "uploading",
"message": "Document fetched from URL and processing started",
"sourceUrl": "https://drive.google.com/uc?export=download&id=...",
"file": {
"name": "john_doe_resume.pdf",
"size": 245760,
"sizeFormatted": "240 KB",
"contentType": "application/pdf"
},
"estimatedProcessingTime": "30 to 60 seconds",
"statusEndpoint": "/v1/public/documents/789e4567-..."
}Step 3: Poll for Completion
Check the processing status every 5 seconds:
async function waitForCompletion(documentId) {
const maxAttempts = 18; // 90 seconds max
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.floreal.aiv1/public/documents/${documentId}`,
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();
if (data.status === 'completed') {
console.log('✅ Processing complete!');
return data;
}
if (data.status === 'failed' || data.status === 'invalid') {
throw new Error(`Processing failed: ${data.error?.message}`);
}
console.log(`⏳ Status: ${data.status} - waiting...`);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error('Timeout waiting for processing');
}
const result = await waitForCompletion(documentId);
console.log('Candidate:', result.contact);
console.log('Profile:', result.profile);import time
def wait_for_completion(document_id):
max_attempts = 18 # 90 seconds max
for i in range(max_attempts):
response = requests.get(
f'https://api.floreal.aiv1/public/documents/{document_id}',
headers={'X-API-Key': 'YOUR_API_KEY'}
)
data = response.json()
if data['status'] == 'completed':
print('✅ Processing complete!')
return data
if data['status'] in ['failed', 'invalid']:
raise Exception(f"Processing failed: {data.get('error', {}).get('message')}")
print(f"⏳ Status: {data['status']} - waiting...")
time.sleep(5)
raise Exception('Timeout waiting for processing')
result = wait_for_completion(document_id)
print('Candidate:', result['contact'])
print('Profile:', result['profile'])Completed Response:
{
"documentId": "789e4567-e89b-12d3-a456-426614174000",
"status": "completed",
"summary": "John Doe is a Senior Software Engineer with 8 years of experience...",
"extractedText": "JOHN DOE\\nSoftware Engineer\\n\\nEXPERIENCE\\n...",
"contact": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"linkedin": "linkedin.com/in/johndoe",
"location": {
"city": "San Francisco",
"country": "United States"
}
},
"profile": {
"domain": "Technology",
"specialization": "Backend Development",
"seniorityLevel": "Senior",
"experienceYears": 8,
"technicalStack": ["Python", "JavaScript", "PostgreSQL"],
"industries": ["Fintech", "SaaS"],
"hasManagement": true
}
}Professional Profile
{
"profile": {
"domain": "Technology",
"specialization": "Backend Development",
"seniorityLevel": "Senior",
"experienceYears": 8,
"technicalStack": ["Python", "JavaScript", "PostgreSQL", "AWS"],
"industries": ["Fintech", "SaaS", "E-commerce"],
"recentExpertise": ["API Design", "Microservices", "Cloud Architecture"],
"hasManagement": true
}
}Structured Attributes
Over 100+ structured attributes for advanced filtering:
{
"attributes": {
"languages": {
"english": 1,
"english_fluent": 1,
"french": 1,
"languages_count": 2
},
"technical_skills": {
"python_experience": 1,
"javascript_experience": 1,
"aws_experience": 1,
"docker_experience": 1,
"programming_languages_count": 4
},
"professional_experience": {
"total_experience_years": 8,
"number_of_employers": 3,
"management_experience": 1,
"remote_work_experience": 1
},
"education_indicators": {
"masters_degree": 1,
"computer_science_degree": 1,
"university_name": "Stanford University"
}
}
}AI-Generated Summary
{
"summary": "John Doe is a Senior Software Engineer with 8 years of experience specializing in backend development and cloud architecture. He has deep expertise in Python, JavaScript, and AWS, with a proven track record of designing and implementing scalable microservices. John has led teams of 5+ engineers and has experience across fintech and SaaS industries. He holds a Master's degree in Computer Science from Stanford University."
}Full CV Text
{
"extractedText": "JOHN DOE\nSenior Software Engineer\n\nCONTACT\nEmail: john.doe@example.com\nLinkedIn: linkedin.com/in/johndoe\nLocation: San Francisco, CA\n\nEXPERIENCE\n\nSenior Software Engineer | TechCorp Inc. | 2020 - Present\n• Led development of microservices architecture serving 1M+ users\n• Designed and implemented RESTful APIs using Python and FastAPI\n• Managed team of 5 engineers\n..."
}URL Requirements & Tips
Valid URL Formats
✅ AWS S3 Public URLs
https://my-bucket.s3.amazonaws.com/resumes/cv.pdf
https://my-bucket.s3.us-east-1.amazonaws.com/public/cv.pdf✅ Google Drive Direct Download
https://drive.google.com/uc?export=download&id=FILE_ID✅ Dropbox Direct Download
https://www.dropbox.com/s/abc123/file.pdf?dl=1✅ Azure Blob Storage
https://mystorageaccount.blob.core.windows.net/public/cv.pdf✅ Your Own Server
https://api.yourcompany.com/files/cv.pdf
https://yourserver.com/static/uploads/resume.pdfCommon URL Mistakes
These URLs won't work:
❌ Google Drive sharing links with /view
❌ Dropbox links with ?dl=0
❌ URLs requiring login/authentication
❌ URLs that return HTML pages
❌ Private IP addresses (localhost, 10.x.x.x, 192.168.x.x)
❌ CDN URLs with hotlink protection (Webflow, some CloudFlare configs)
How to Convert Google Drive URLs
# From sharing link
https://drive.google.com/file/d/1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc/view?usp=sharing
# Extract FILE_ID (between /d/ and /view)
1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jc
# Create direct download URL
https://drive.google.com/uc?export=download&id=1niWNOc_FeSjt03vTpwl3TwFvW2KzU0jcComparison Table
| Feature | URL Upload | Direct Upload | Presigned URL |
|---|---|---|---|
| Requests | 1 | 1 | 3 |
| Complexity | ⭐ Simple | ⭐ Simple | ⭐⭐⭐ Complex |
| File Source | Remote URL | Local file | Local file |
| Best For | Automation, webhooks | Quick integration | Large files, browsers |
| Webhook Friendly | ✅ Yes | ❌ No | ❌ No |
| Max File Size | 10 MB | 10 MB | 10 MB |
| Network | Server-side | Through API | Direct to S3 |
API Reference
Upload from URL
Easiest method - upload from public URLs (recommended)
Direct Upload
Simple single-request upload for local files
Presigned URL Upload
Advanced 3-step upload for large files and browsers
Get Document Status
Check processing status and retrieve parsed data
List Documents
Browse all uploaded CVs with filtering
Delete Document
Remove documents you no longer need
Processing Issues
Processing stuck in "uploading"
Wait time: Up to 20 seconds
Solution: If longer than 30s, file may be corrupted
Processing stuck in "pending"
Wait time: Up to 60 seconds for complex CVs
Solution: If longer than 90s, contact support
Status returns "invalid"
Cause: AI didn't recognize document as a CV
Solution: Ensure file is actually a resume/CV, not job posting or other document
Extracted data is incomplete
Causes:
- Complex multi-column layouts
- Text embedded in images
- Unusual formatting
Solutions:
- Use simple single-column CV format
- Convert to PDF from Word
- Avoid heavy graphics
Need higher limits? Contact sales
Security & Privacy
- ✅ SSRF Protection - Blocks internal/private URLs
- ✅ Encrypted in transit - All uploads use HTTPS
- ✅ Encrypted at rest - Files stored in secure S3
- ✅ Scoped to your org - No cross-company access
- ✅ GDPR compliant - Delete CVs anytime
- ✅ Audit trail - Track who uploaded what
- ✅ 30s timeout - Prevents hanging on slow URLs
Next Steps
Ready to start uploading CVs? Here's your roadmap:
- Get your API key from the dashboard
- Choose upload method:
- Files on S3/Drive/Dropbox? → Use URL upload
- Local files on server? → Use Direct upload
- Large files from browser? → Use Presigned URL
- Upload
- Search candidates using the parsed data