Add profiles to a report
Validate your JSON, understand duplicates and restore previously removed people.
Send a JSON array of profiles
{
"profiles": [
{
"linkedin_url": "https://www.linkedin.com/in/alex-example/",
"name": "Alex Example",
"title": "Marketing Director"
},
{
"linkedin_url": "https://www.linkedin.com/in/jordan-example/",
"name": "Jordan Example"
}
]
}Each profile requires a personal HTTPS LinkedIn URL. Optional display fields are name, title and headline. Send 1–100 profiles per import, up to 1 MiB. Only these fields are accepted. Company pages are not personal profiles. LinkedIn host aliases, trailing slashes and identity casing are normalized before duplicate checks.
Validate the whole batch first
Add ?validation_only=true to the import endpoint. Invalid rows return 422 with one-based row numbers and field errors. A validation failure saves nothing and queues nothing. Successful validation reports would_add or would_restore. It does not reserve work; the commit rechecks the report and current profiles.
{
"data": {
"validation_only": true,
"valid": true,
"counts": {
"submitted": 2,
"would_add": 1,
"would_restore": 0,
"already_present": 1,
"duplicate_in_input": 0,
"would_queue_profiles": 1
},
"rows": [
{
"row_number": 1,
"status": "would_add"
},
{
"row_number": 2,
"status": "already_present"
}
]
},
"request_id": "77777777-7777-4777-8777-777777777777"
}| Profile state | Commit outcome | Scanning |
|---|---|---|
| Not in the report | added | Both person scan modes queued |
| Previously removed from this report | restored, with previously_removed_profile_restored note | Both modes queued; previous details/history preserved |
| Already active in this report | already_present | No new scans |
| Repeated later in this JSON batch | duplicate_in_input | No additional scans; first row takes precedence |
Read the receipt
{
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"report_id": "22222222-2222-4222-8222-222222222222",
"state": "completed",
"counts": {
"submitted": 2,
"added": 1,
"restored": 1,
"already_present": 0,
"duplicate_in_input": 0,
"profiles_queued": 2
},
"scan_requests": [
{
"mode": "full_profile",
"scan_run_id": "55555555-5555-4555-8555-555555555555",
"status_at_commit": "queued",
"jobs_created": 2,
"jobs_coalesced": 0
},
{
"mode": "activity",
"scan_run_id": "66666666-6666-4666-8666-666666666666",
"status_at_commit": "queued",
"jobs_created": 2,
"jobs_coalesced": 0
}
],
"rows": [
{
"row_number": 1,
"status": "added",
"profile_id": "33333333-3333-4333-8333-333333333333",
"scan_requests": [
{
"scan_run_id": "55555555-5555-4555-8555-555555555555",
"mode": "full_profile"
},
{
"scan_run_id": "66666666-6666-4666-8666-666666666666",
"mode": "activity"
}
]
},
{
"row_number": 2,
"status": "restored",
"profile_id": "44444444-4444-4444-8444-444444444444",
"notes": [
{
"code": "previously_removed_profile_restored",
"message": "This profile was previously removed from this report. It has been restored and queued for scanning."
}
],
"scan_requests": [
{
"scan_run_id": "55555555-5555-4555-8555-555555555555",
"mode": "full_profile"
},
{
"scan_run_id": "66666666-6666-4666-8666-666666666666",
"mode": "activity"
}
]
}
],
"created_at": "2026-09-11T12:00:00Z",
"expires_at": "2026-10-11T12:00:00Z"
},
"request_id": "88888888-8888-4888-8888-888888888888"
}Rows preserve input order. Receipt counts distinguish additions, restorations and skips. The receipt contains profile references and scan references, not a copy of submitted personal values. Its completed state confirms admission only.
Reports already being scanned
Imports work while scans or schedules are active. New work is coordinated with the queue; existing schedules and unrelated running jobs remain intact. Imports do not rescan the company page. An archived report returns 409. Adding an active duplicate does not retry its failed scans; use the existing product workflow for scan operations.