New You can now talk to your Gelee agent from Claude, ChatGPT or Cursor through our MCP. Read the docs →

Reference

Leads and people

Read every lead with its whole story, change fields, tags and flags, and record outcomes.

Last updated 22 October 2026

The whole story on every lead

Every endpoint that returns people returns the same block, so you can write one mapper and use it everywhere: /prospects, /people, /leads/{id}, /campaigns/{id}/leads, /drafts, /needs-human, /stalled-leads and /inbox. One call answers who this is, who reached them, and where things stand.

FieldWhat it is
name, linkedin_url, public_identifierWho they are. linkedin_url is built only from a real /in/ handle, so it is a link that works or null, never a guess.
role, company, headline, industry, locationTheir job and where they are.
company_website, company_linkedin_url, company_sizeTheir company. company_linkedin_url is the company page, not the person.
campaign{ id, name } of the campaign this row belongs to.
senderThe seat that last reached out: seat_id, name, public_identifier, linkedin_url. null before any outreach.
stageWhere they are, the same stage the Leads table shows.
booking_likelihood0 to 100, how likely they are to book. booking_likelihood_tier is the grade: A (75+), B (50+), C (25+), D.
icp_score, icp_tierHow well they fit your ideal customer.
timelineinvited_at, connected_at, first and last messaged_at, first and last reply_at, booked_at. Across every campaign they were in.
bookingTheir latest call: start_time, end_time, provider, title, meeting_url, status, booked_at.
chatchat_id, and app_url, a link that opens the conversation in Gelee.
flagsThe same badges the inbox shows: interested, engaged, follow_up (+ follow_up_on), referral, lost, removed, no_response, booked, converted.
custom_fields, tags, notes_countYour own data on the lead. See Update a lead below.

Every key is always there. Anything unknown is null, so every row has the same shape.

List leads

GET/prospects

One row per person per campaign. The endpoint most CRM syncs poll. GET /prospects/{id} returns one row in the same shape.

Query
campaign_idstring
Only this campaign.
statusstring
pending, active, connection_sent, connected, messaged, replied, opted_out or completed.
stagestring
The Leads table stage.
linkedin_url / linkedin_idstring
Find one person: every campaign row they have.
tagstring
Rows carrying this tag (exact).
tierA | B | C | D
Booking likelihood grade.
min_score0-100
Booking likelihood at least this. Use 50 for A and B leads only.
limit, offsetinteger
Default 50, max 200.
curl "https://www.gelee.ai/api/v1/prospects?campaign_id=9a2c%E2%80%A6&min_score=50&limit=100" \
  -H "Authorization: Bearer gk_your_key"
Response
{ "data": [
  { "id": "3f81…", "campaign_id": "9a2c…", "linkedin_id": "ACoAA…",
    "name": "Jane Doe", "status": "replied", "current_step": 2,
    "linkedin_url": "https://www.linkedin.com/in/janedoe",
    "public_identifier": "janedoe",
    "role": "VP Sales", "company": "Acme", "headline": "VP Sales at Acme",
    "industry": "Computer Software", "location": "Toronto, Ontario, Canada",
    "company_website": "https://acme.example",
    "company_linkedin_url": "https://www.linkedin.com/company/acme",
    "company_size": "51-200", "follower_count": 4820,
    "campaign": { "id": "9a2c…", "name": "Q4 Founders" },
    "sender": { "seat_id": "SExF…", "name": "Sofia Salazar",
                "public_identifier": "sofiasalazar",
                "linkedin_url": "https://www.linkedin.com/in/sofiasalazar" },
    "stage": "replied",
    "booking_likelihood": 78, "booking_likelihood_tier": "A",
    "icp_score": 82, "icp_tier": "A",
    "timeline": { "invited_at": "2026-10-01T14:02:00Z",
                  "connected_at": "2026-10-02T09:40:00Z",
                  "first_messaged_at": "2026-10-02T10:05:00Z",
                  "last_messaged_at": "2026-10-09T10:05:00Z",
                  "first_reply_at": "2026-10-09T16:31:00Z",
                  "last_reply_at": "2026-10-10T08:12:00Z",
                  "booked_at": null },
    "booking": null,
    "chat": { "chat_id": "chat_88",
              "app_url": "https://web.gelee.ai/inbox?chatId=chat_88" },
    "flags": { "interested": true, "engaged": true, "follow_up": false,
               "follow_up_on": null, "referral": false, "lost": false,
               "removed": false, "no_response": false,
               "booked": false, "converted": false },
    "custom_fields": { "report_link": "https://acme.example/r/5d70" },
    "tags": ["Series A"], "notes_count": 1,
    "source": "evergreen_post_engager",
    "created_at": "2026-10-01T09:14:00Z" }
],
"pagination": { "limit": 50, "offset": 0, "total": 342 } }

Update a lead

PATCH/prospects/{id}read_write

Send only what changes. Answers with the lead as GET /prospects/{id} returns it.

Body
outcomestring
booked, converted, interested or lost. Writes the real fact, see the table below.
custom_fieldsobject
Your own fields, used in messages as {{custom.key}}. null deletes a key. Names are yours: letters, numbers and underscores, starting with a letter, up to 40 characters. Up to 50 fields of 1,000 characters. Links must be normal http or https addresses.
tagsarray | object
["a", "b"] replaces them all; { "add": [...], "remove": [...] } edits. Up to 30.
flagsobject
interested, lost, referral: true or false. follow_up: a future date or false. If a flag cannot change, the answer carries notes saying why.
outcomeWhat it does
interestedTags them Interested, in the app and in analytics.
lostTags them Lost and stops all outreach. flags.lost: false undoes a loss you marked by hand.
bookedRecords a real booking: counts in your stats, fires call_booked (marked manual), ends their sequence and closes follow-ups.
convertedRecords a conversion of your workspace's primary metric.

Booked and converted twice record nothing new and answer "applied": "already_set", so a scheduled CRM sync cannot inflate your numbers.

curl -X PATCH "https://www.gelee.ai/api/v1/prospects/3f81…" \
  -H "Authorization: Bearer gk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "custom_fields": {
      "report_link": "https://acme.example/r/5d70",
      "finding": "your pricing page loads in 9s"
    },
    "tags": {
      "add": [
        "Series A"
      ]
    },
    "flags": {
      "interested": true
    }
  }'
Response
{ "data": { "id": "3f81…", "name": "Jane Doe",
    "custom_fields": { "report_link": "https://acme.example/r/5d70",
                       "finding": "your pricing page loads in 9s" },
    "tags": ["Series A"],
    "flags": { "interested": true, … },
    … } }

Merge fields in messages

Put {{custom.report_link}} in any campaign step and each lead gets their own value. Give a fallback with {{custom.report_link|our latest report}}.

A step waits for its field

A step that uses a field without a fallback waits for that field before it sends: checked every 15 minutes, for up to 24 hours. That is made for "write the report link onto the lead when they accept, then the next step uses it". After 24 hours it sends as written and the sentence with the missing field is dropped.

You can also set custom_fields and tags when you push leads. A change through the API fires the lead_updated webhook.

Notes

POST/prospects/{id}/notesread_write

Up to 2,000 characters a note, 50 notes per lead.

CallWhat it does
GET /prospects/{id}/notesThe lead's notes, oldest first.
DELETE /prospects/{id}/notes/{note_id}Delete one note.
curl -X POST "https://www.gelee.ai/api/v1/prospects/3f81…/notes" \
  -H "Authorization: Bearer gk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Met at SaaStr, wants the agency plan."
  }'
Response
{ "data": { "id": "n_1a…", "text": "Met at SaaStr, wants the agency plan.",
            "by": "api_key:k_81…", "at": "2026-10-22T15:00:00Z" } }

Pause, resume or remove

POST/prospects/{id}/pauseread_write
CallWhat it does
POST …/pauseStop sending to this lead in this campaign, keeping their place. The same pause as the app's Silence, so either side can undo it.
POST …/resumePut them back exactly where they were.
POST …/removeTake them out of this campaign for good. Nothing is deleted; the row and its history stay. To never contact them anywhere, use the blocklist.
curl -X POST "https://www.gelee.ai/api/v1/prospects/3f81…/pause" \
  -H "Authorization: Bearer gk_your_key"
Response
{ "data": { "id": "3f81…", "result": "paused" } }

Everything that happened

GET/prospects/{id}/activity

Every invite, accept, message, InMail, reply and booking with this person, oldest first, across every campaign they were in. Each entry names the campaign, the seat, the sequence step, and the source: gelee (the campaign), api or manual. Up to 500 entries.

curl "https://www.gelee.ai/api/v1/prospects/3f81…/activity" \
  -H "Authorization: Bearer gk_your_key"
Response
{ "data": [
    { "event": "invite_sent", "at": "2026-10-01T14:02:00Z",
      "campaign": { "id": "9a2c…", "name": "Q4 Founders" },
      "seat": { "seat_id": "SExF…", "name": "Sofia Salazar",
                "public_identifier": "sofiasalazar",
                "linkedin_url": "https://www.linkedin.com/in/sofiasalazar" },
      "step": 1, "source": "gelee" },
    { "event": "connection_accepted", "at": "2026-10-02T09:40:00Z", … },
    { "event": "message_sent", "at": "2026-10-02T10:05:00Z", … },
    { "event": "reply_received", "at": "2026-10-09T16:31:00Z", … }
  ] }

The Leads table

GET/people

One row per person across every campaign, with stage, booking likelihood and grade, last touch and last reply. GET /people/{id} returns the person with every campaign row they have, each with the whole story. For one row per campaign, use /prospects.

Query
stagestring
booked, replied, messaged, connection_sent, qualified, stalled, completed or benched.
tier / min_scorestring / 0-100
Booking likelihood grade or score.
searchstring
Name contains.
sortrecent | score
recent (last touch) is the default.
limit, cursor
Up to 200. Pass the cursor from the previous page.
curl "https://www.gelee.ai/api/v1/people?tier=A&sort=score" \
  -H "Authorization: Bearer gk_your_key"

Booked calls

GET/bookings

Newest first: who, when, which campaign, which calendar, the meeting link and its status.

Query
statusstring
booked, rescheduled, completed, cancelled or no_show.
campaign_id, from, to
from and to are dates, on the call's start time.
limit, offsetinteger
Max 200.
curl "https://www.gelee.ai/api/v1/bookings?status=booked&from=2026-10-01" \
  -H "Authorization: Bearer gk_your_key"

Send conversions in

POST/api/webhooks/conversionsread_write

Tell Gelee when someone converted on your side, so it shows up in your Gelee reporting. This one sits at www.gelee.ai/api/webhooks/conversions, outside /v1.

Body
event_typestringrequired
Your own label, for example demo_booked or signup.
linkedin_idstring
Ties the event to a person Gelee knows.
prospect_name / prospect_emailstring
Used to match when you have no LinkedIn id.
metaobject
Any extra JSON to store with the event.

The same event twice within 24 hours is ignored and answers "deduped": true.

curl -X POST "https://www.gelee.ai/api/webhooks/conversions" \
  -H "Authorization: Bearer gk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "demo_booked",
    "linkedin_id": "ACoAA…",
    "prospect_email": "jane@acme.com",
    "meta": {
      "plan": "pro"
    }
  }'
Response
{ "ok": true, "event_type": "demo_booked" }