Requires
linkedin_accesson your subscription or plan. All/linkedin/*and/channels/linkedin/*routes return403withlinkedin_upgrade_requiredwhen the feature is not enabled.
Overview
GET /api/v1/linkedin/overview
Returns connection status, inbox stats, active LinkedIn campaigns, InMail balance, and whether a Recruiter contract is detected on the account.
Connect LinkedIn
LinkedIn uses the account email or LinkedIn username + password, with optional 2FA — same credential flow as Instagram.
| Endpoint | Method |
|---|---|
/channels/linkedin/connect | POST |
/channels/linkedin/2fa | POST |
/channels/linkedin/2fa/resend | POST |
/channels/linkedin/status | GET |
/channels/linkedin/refresh | POST |
/channels/linkedin/disconnect | POST |
Connect example:
curl -X POST https://dashboard.skylightchat.com/api/v1/channels/linkedin/connect \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"username": "[email protected]",
"password": "YOUR_PASSWORD",
"country": "SA"
}'
username is the LinkedIn login email or username (not a profile URL). If 2FA is required, the response includes requires_2fa: true and an account_id. Submit the code to POST /channels/linkedin/2fa.
See Channels for full request/response shapes and sync_status values.
People search (sourcing)
POST /api/v1/linkedin/sourcing/search
At least one filter is required: keywords, title, industry, location, or company.
{
"title": "مدير تسويق",
"location": "الرياض",
"company": "شركة سحاب الخليج",
"limit": 25
}
Each items[] entry is a LinkedIn profile with:
| Field | Description |
|---|---|
provider_id | Profile identifier to pass into campaigns — usually the public slug from /in/{slug}, or a member id when that is what search returns |
name | Display name |
headline | Profile headline |
location | Location string when available |
company | Current company when available |
profile_url | Public profile URL, e.g. https://www.linkedin.com/in/sarah-alqahtani |
picture | Profile picture URL, or null |
Response example:
{
"success": true,
"data": {
"items": [
{
"provider_id": "sarah-alqahtani",
"name": "سارة القحطاني",
"headline": "مديرة تسويق رقمي | SaaS",
"location": "الرياض، المملكة العربية السعودية",
"company": "شركة سحاب الخليج",
"profile_url": "https://www.linkedin.com/in/sarah-alqahtani",
"picture": "https://media.licdn.com/dms/image/..."
},
{
"provider_id": "khalid-alshammari-ksa",
"name": "خالد الشمري",
"headline": "مؤسس مشارك | تقنية مالية",
"location": "جدة",
"company": "منصة رصد",
"profile_url": "https://www.linkedin.com/in/khalid-alshammari-ksa",
"picture": null
}
],
"next_cursor": "eyJwYWdlIjoyfQ==",
"total": 142
},
"message": "Search completed."
}
Always reuse provider_id exactly as returned by search (or extract the /in/{slug} segment from profile_url). Do not invent member ids.
Launch outreach from search
POST /api/v1/linkedin/sourcing/launch-campaign
| Field | Description |
|---|---|
name | Campaign label |
campaign_type | invite or sequence |
provider_ids | Profile identifiers from search items[].provider_id |
invite_note | Optional connection note (max 200 chars) |
sequence_messages | Follow-up DMs after invite is accepted (sequence only) |
Example - invite + follow-up:
{
"name": "تواصل مع مديري التسويق في الرياض",
"campaign_type": "sequence",
"provider_ids": [
"sarah-alqahtani",
"khalid-alshammari-ksa"
],
"invite_note": "مرحباً، أتابع أعمالكم في قطاع التقنية وأحب التواصل معكم.",
"sequence_messages": [
{
"text": "شكراً على قبول الدعوة - هل يناسبك اتصال قصير الأسبوع القادم؟",
"wait_days": 3
}
]
}
Outreach campaigns
Manage running campaigns:
| Endpoint | Method |
|---|---|
/linkedin/outreach/campaigns | GET, POST |
/linkedin/outreach/campaigns/{id} | GET |
/linkedin/outreach/campaigns/{id}/stats | GET |
/linkedin/outreach/campaigns/{id}/contacts | GET |
/linkedin/outreach/campaigns/{id}/pause | POST |
/linkedin/outreach/campaigns/{id}/resume | POST |
/linkedin/outreach/campaigns/{id}/cancel | POST |
POST outreach campaigns accept provider_ids or a targets string — full profile URLs (https://www.linkedin.com/in/sarah-alqahtani) or public identifiers (sarah-alqahtani), one per line.
LinkedIn invite/sequence campaigns are separate from WhatsApp/Telegram campaigns, which use
messages[]and contact lists.
Send a LinkedIn DM
Use Messages with a contact whose type is linkedin:
{
"contact_id": 418,
"message": "مرحباً سارة، شكراً على تواصلك معنا. كيف أقدر أساعدك؟"
}
Recruiter (seat required)
Requires a LinkedIn Recruiter contract on the connected account.
| Endpoint | Method |
|---|---|
/linkedin/recruiter | GET - list jobs + quotas |
/linkedin/recruiter/jobs | POST - create job |
/linkedin/recruiter/jobs/{id} | GET |
/linkedin/recruiter/jobs/{id}/publish | POST |
/linkedin/recruiter/jobs/{id}/close | POST |
/linkedin/recruiter/jobs/{id}/sync-applicants | POST |
/linkedin/recruiter/applicants/{id}/stage | POST |
/linkedin/recruiter/applicants/{id}/ai-screen | POST |
/linkedin/recruiter/applicants/{id}/resume | GET - PDF download |
Create job example:
{
"title": "مطور Laravel أول (Full Stack)",
"description": "نبحث عن مطور Laravel بخبرة 3+ سنوات للانضمام لفريق منتج منصة المحادثات في الرياض.",
"location": "الرياض، السعودية",
"company_name": "شركة نور التقنية",
"employment_type": "FULL_TIME",
"workplace_type": "HYBRID",
"publish_now": true
}
Subscription Quotas & Limits
All LinkedIn Recruiter endpoints are subject to plan-specific quotas and limits based on your active SkyLight subscription.
Available Limits
| Limit | Field Name | Description |
|---|---|---|
| Job posts | max_linkedin_jobs | Maximum number of LinkedIn jobs you can publish on your subscription. |
| AI screenings | max_recruiter_ai_screens | Maximum number of AI candidate screenings. |
| Resume downloads | max_recruiter_resume_downloads | Maximum number of candidate PDF resumes you can download. |
Quota Depletion
When you create/publish a new job, perform an AI screening (/applicants/{id}/ai-screen), or download a resume (/applicants/{id}/resume), the corresponding limit count decreases by 1.
If your remaining quota is empty (0), the endpoint will return a 403 Forbidden status with an error payload:
{
"success": false,
"error": "insufficient_linkedin_jobs_limit",
"message": "You have reached your subscription limit for LinkedIn Job Posts. Please upgrade your plan."
}
You can retrieve your current limits and remaining counts at any time via the API or by viewing your subscription status inside the Dashboard under My Subscription.
