Skip to main content
These recipes show how to chain API calls for complete recruiting workflows. Each recipe includes the exact endpoints, request bodies, and expected responses.

Manage project pipeline entries

Use this workflow when an integration needs to read candidates from a project, filter them by stage, add new leads to a project, or move existing leads through the pipeline.
1

Get the project stages

Pipeline entry filters use stage IDs, not stage names. Start by reading the project and storing the stage ID you need, for example the Sourced stage.
curl -X GET "https://app.leonar.app/api/v1/projects/project-uuid" \
  -H "Authorization: Bearer leo_your_api_key"
Response excerpt:
{
  "data": {
    "id": "project-uuid",
    "name": "Senior Frontend Engineers",
    "pipeline": {
      "stages": [
        {
          "id": "sourced-stage-uuid",
          "name": "Sourced",
          "position": 0,
          "system_category": "sourced",
          "entries_count": 12
        }
      ]
    }
  }
}
2

List only entries in a given stage

Pass the stage UUID in stage_id. Values like Sourced are not accepted directly.
curl -X GET "https://app.leonar.app/api/v1/projects/project-uuid/entries?stage_id=sourced-stage-uuid&limit=100&offset=0" \
  -H "Authorization: Bearer leo_your_api_key"
3

Create or update the contact

If the lead is new, create a contact first:
curl -X POST "https://app.leonar.app/api/v1/contacts" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Sophie",
    "last_name": "Martin",
    "title": "Senior Software Engineer",
    "current_company": "Doctolib",
    "linkedin_profile": "https://www.linkedin.com/in/sophie-martin"
  }'
If the lead already exists and you only need to update their profile, use:
curl -X PUT "https://app.leonar.app/api/v1/contacts/contact-uuid" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Staff Software Engineer",
    "current_company": "Doctolib"
  }'
4

Add the contact to the project

Add the contact to the project pipeline. If stage_id is omitted, Leonar adds the contact to the first stage of the project pipeline.
curl -X POST "https://app.leonar.app/api/v1/projects/project-uuid/entries" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "contact-uuid",
    "stage_id": "sourced-stage-uuid"
  }'
5

Move an existing project lead to another stage

Use the pipeline entry ID from GET /projects/{id}/entries, then pass the target stage UUID.
curl -X PUT "https://app.leonar.app/api/v1/pipeline-entries/pipeline-entry-uuid" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "stage_id": "target-stage-uuid"
  }'

Source candidates and add to project

Find candidates on LinkedIn and add them to a recruiting project’s pipeline.
1

Get your connected LinkedIn account

curl -X GET "https://app.leonar.app/api/v1/connected-accounts" \
  -H "Authorization: Bearer leo_your_api_key"
Response — pick an account with api_status.recruiter: "active" or api_status.sales_navigator: "active":
{
  "data": [
    {
      "id": "acc-uuid-here",
      "name": "Alice Recruiter",
      "license_type": "recruiter",
      "api_status": {
        "classic": "active",
        "sales_navigator": "inactive",
        "recruiter": "active"
      }
    }
  ]
}
2

Look up location IDs (for LinkedIn filters)

curl -X GET "https://app.leonar.app/api/v1/sourcing/linkedin/locations?q=Paris&account_id=acc-uuid-here&api_type=recruiter" \
  -H "Authorization: Bearer leo_your_api_key"
Response:
{
  "data": [
    {"id": "105015875", "title": "Paris, Ile-de-France, France"},
    {"id": "104482823", "title": "Paris Area, France"}
  ]
}
3

Search LinkedIn profiles

curl -X POST "https://app.leonar.app/api/v1/sourcing/linkedin/search" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "project-uuid",
    "account_id": "acc-uuid-here",
    "job_titles": ["Software Engineer", "Backend Developer"],
    "location_ids": {"105015875": "Paris, France"},
    "years_experience": {"min": 3, "max": 10},
    "page": 1,
    "page_size": 25
  }'
Response — profiles with already_in_project: false can be added:
{
  "data": {
    "profiles": [
      {
        "profile_id": "urn:li:member:123456",
        "first_name": "Sophie",
        "last_name": "Martin",
        "headline": "Senior Software Engineer at Doctolib",
        "current_job": {"title": "Senior Software Engineer", "company_name": "Doctolib"},
        "already_in_project": false,
        "existing_contact_id": null
      }
    ],
    "total_count": 342,
    "filtered_count": 340,
    "has_more": true,
    "next_page": 2
  }
}
4

Add selected profiles to project

Pass the full profile objects directly from the search response. Include experiences, educations, skills, summary, and picture_url to create rich contact records:
curl -X POST "https://app.leonar.app/api/v1/sourcing/add-to-project" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "project-uuid",
    "profiles": [
      {
        "profile_id": "urn:li:member:123456",
        "first_name": "Sophie",
        "last_name": "Martin",
        "headline": "Senior Software Engineer at Doctolib",
        "picture_url": "https://media.licdn.com/dms/image/example.jpg",
        "location": "Paris, Île-de-France, France",
        "linkedin_url": "https://www.linkedin.com/in/sophie-martin",
        "summary": "Experienced engineer with 8 years in full-stack development...",
        "current_job": {
          "title": "Senior Software Engineer",
          "company_name": "Doctolib"
        },
        "experiences": [
          {
            "title": "Senior Software Engineer",
            "company_name": "Doctolib",
            "start_date": "2021-03-01",
            "end_date": null,
            "description": "Leading backend team, Python/Django stack...",
            "is_current": true
          },
          {
            "title": "Software Engineer",
            "company_name": "Criteo",
            "start_date": "2018-01-01",
            "end_date": "2021-02-28",
            "description": "Built real-time bidding systems...",
            "is_current": false
          }
        ],
        "educations": [
          {
            "educational_establishment": "École Polytechnique",
            "diploma": "Master of Engineering",
            "specialization": "Computer Science",
            "start_date": "2014-09-01",
            "end_date": "2018-06-30"
          }
        ],
        "skills": ["Python", "Django", "TypeScript", "PostgreSQL"],
        "total_years_experience": 8.2
      }
    ]
  }'
The more fields you include, the richer the contact record. Fields like already_in_project and existing_contact_id from the search response are ignored — they are response-only metadata.
Response:
{
  "data": {
    "added": 1,
    "skipped": 0,
    "contact_ids": ["new-contact-uuid"],
    "skipped_profiles": [],
    "stage": {"id": "stage-uuid", "name": "Sourced", "category": "sourced"}
  }
}

Enrich a contact and find their email

1

Trigger enrichment

curl -X POST "https://app.leonar.app/api/v1/contacts/contact-uuid/enrich" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"type": "work_email"}'
Response:
{
  "data": {
    "request_id": "enrich-request-uuid",
    "type": "work_email",
    "status": "pending"
  }
}
2

Poll until completed

Enrichment is asynchronous. Poll every 5 seconds:
curl -X GET "https://app.leonar.app/api/v1/enrichment/enrich-request-uuid" \
  -H "Authorization: Bearer leo_your_api_key"
Response when completed:
{
  "data": {
    "id": "enrich-request-uuid",
    "contact_id": "contact-uuid",
    "enrichment_type": "work_email",
    "status": "completed",
    "result": {
      "email": "sophie@doctolib.com",
      "confidence": 0.95
    },
    "created_at": "2025-02-10T10:00:00Z",
    "completed_at": "2025-02-10T10:00:08Z"
  }
}
The email is automatically added to the contact record. No need to update the contact manually.

Enroll contacts in a sequence

1

List available sequences

curl -X GET "https://app.leonar.app/api/v1/sequences?status=active&limit=10" \
  -H "Authorization: Bearer leo_your_api_key"
2

Enroll contacts (simple format)

curl -X POST "https://app.leonar.app/api/v1/sequences/sequence-uuid/enroll" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": [
      "contact-uuid-1",
      "contact-uuid-2",
      "contact-uuid-3"
    ]
  }'
3

Or enroll with custom variables

curl -X POST "https://app.leonar.app/api/v1/sequences/sequence-uuid/enroll" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {
        "contact_id": "contact-uuid-1",
        "custom_variables": {
          "project_name": "Senior Frontend Engineers",
          "custom_intro": "I noticed your work on the React component library"
        }
      }
    ]
  }'
Response:
{
  "data": {
    "enrolled": 1,
    "skipped_blacklisted": 0,
    "skipped_already_enrolled": 0,
    "skipped_active_elsewhere": 0,
    "skipped_not_found": 0
  }
}

Create and manage a deal

1

Get pipeline stages

curl -X GET "https://app.leonar.app/api/v1/deal-pipelines" \
  -H "Authorization: Bearer leo_your_api_key"
2

Create a deal

curl -X POST "https://app.leonar.app/api/v1/deals" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Recruitment - 3 Senior Engineers",
    "company_id": "company-uuid",
    "pipeline_id": "pipeline-uuid",
    "amount": 45000,
    "currency": "EUR",
    "expected_close_date": "2025-03-15"
  }'
3

Link a contact to the deal

curl -X POST "https://app.leonar.app/api/v1/deals/deal-uuid/contacts" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"contact_id": "contact-uuid"}'
4

Move deal through stages

curl -X PUT "https://app.leonar.app/api/v1/deals/deal-uuid/stage" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"stage_id": "next-stage-uuid"}'
5

Close the deal

curl -X POST "https://app.leonar.app/api/v1/deals/deal-uuid/close" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "won",
    "signed_amount": 45000,
    "actual_close_date": "2025-03-10"
  }'

Search and tag contacts

1

Create a tag

curl -X POST "https://app.leonar.app/api/v1/tags" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "ai-sourced", "color": "#6366F1", "scope": "contact"}'
2

Search contacts

curl -X POST "https://app.leonar.app/api/v1/contacts/search" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "react typescript",
    "location": "Paris",
    "limit": 50
  }'
3

Tag matching contacts

For each matching contact:
curl -X POST "https://app.leonar.app/api/v1/contacts/contact-uuid/tags" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"tag_id": "tag-uuid"}'

Send a message to a contact

curl -X POST "https://app.leonar.app/api/v1/messages" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "contact-uuid",
    "channel": "email",
    "subject": "Exciting opportunity at Doctolib",
    "content": "Hi Sophie, I came across your profile..."
  }'
For LinkedIn messages, specify the channel and optionally the sender account:
curl -X POST "https://app.leonar.app/api/v1/messages" \
  -H "Authorization: Bearer leo_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "contact-uuid",
    "channel": "linkedin",
    "content": "Hi Sophie, I noticed your experience with React...",
    "sender_account_id": "account-uuid"
  }'