Reference
Conversations and sending
Read whole threads, reply, start new conversations and InMails, edit or unsend your own messages, and work the AI SDR's waiting drafts. Sends go out at once: there is no approval step on the API.
Anything the other person sees needs a key made with Read + write + send messages. Every message is checked the same way the app checks one: your do-not-contact list, people who opted out, your workspace's link rules and the safety checks on the text. One that fails answers 422 with the reason, and nothing is sent.
Recent conversations
Read live from LinkedIn across every connected seat, with the whole story of each person. Slower than other reads, so it is capped at 30 calls a minute.
seats names any seat whose inbox could not be read (failed) or was not reached in time (not_read), so a gap is never silent. A seat shared with another workspace only ever shows your own campaign conversations.
curl "https://www.gelee.ai/api/v1/inbox?limit=50" \
-H "Authorization: Bearer gk_your_key"{ "data": [
{ "id": "chat_88", "seat_id": "SExF…", "attendee_name": "Jane Doe",
"attendee_provider_id": "ACoAA…", "unread_count": 1,
"last_message": { "text": "Sounds great!",
"at": "2026-10-14T13:04:11Z", "from_me": false },
"linkedin_url": "https://www.linkedin.com/in/janedoe",
"campaign": { "id": "9a2c…", "name": "Q4 Founders" },
"sender": { "seat_id": "SExF…", "name": "Sofia Salazar", … },
"booking_likelihood": 78, "booking_likelihood_tier": "A",
"flags": { "interested": true, … }, … }
],
"scope": "campaign",
"seats": { "total": 8, "failed": [], "not_read": [] } }Read a whole thread
From our stored copy, so it is fast and costs the seat nothing on LinkedIn. The newest page comes first and each page reads oldest to newest. Pass cursor to page back.
curl "https://www.gelee.ai/api/v1/inbox/chat_88/messages?limit=30" \
-H "Authorization: Bearer gk_your_key"{ "data": [
{ "id": "msg_90…", "chat_id": "chat_88",
"text": "Hi Jane, saw your post about hiring SDRs…",
"from_me": true, "sender_name": "Sofia Salazar",
"sent_at": "2026-10-02T10:05:00Z", "message_type": "MESSAGE",
"subject": null, "attachments": [], "reactions": [] },
{ "id": "msg_91…", "text": "Sounds great!", "from_me": false, … }
],
"chat": { "chat_id": "chat_88", "seat_id": "SExF…",
"attendee_name": "Jane Doe", "attendee_provider_id": "ACoAA…" },
"cursor": "eyJ0IjoiMjAyNi0xMC0wMiJ9" }Reply in a conversation
Any AI draft waiting in that conversation is dismissed, so the person never gets two answers. counted_as is conversation when they wrote to you in the last 14 days and outreach otherwise, in which case it counts against the seat's own message limits like a campaign message.
| Refused with | Why |
|---|---|
409 duplicate_message | The same text already went to this person in the last day. |
422 text_blocked / link_blocked | It failed a safety check, or has a link that is not one of your workspace's own. |
429 seat_paced | This seat sent a message a few seconds ago. Wait and retry. |
429 seat_limit_reached | The seat is out of messages for now. The message says when to try again. |
curl -X POST "https://www.gelee.ai/api/v1/inbox/chat_88/messages" \
-H "Authorization: Bearer gk_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm-msg-5d70-1" \
-d '{
"text": "Thanks Jane, here is the report: https://acme.example/r/5d70"
}'{ "data": { "message_id": "msg_92…", "chat_id": "chat_88",
"seat_id": "SExF…", "sent_at": "2026-10-22T15:04:11Z",
"drafts_dismissed": 1, "ai_stopped": true,
"counted_as": "conversation" } }Start a conversation or InMail
GET /me or GET /seats.{ "subject": "…" } sends an InMail instead. Needed for anyone who is not a 1st-degree connection.Counts against the seat's message or InMail limits exactly like a campaign send. Connection requests are not sent here: they go through a campaign, so pacing and your campaign rules always apply.
curl -X POST "https://www.gelee.ai/api/v1/conversations" \
-H "Authorization: Bearer gk_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm-open-5d70" \
-d '{
"seat_id": "SExF…",
"linkedin_id": "ACoAAB…",
"text": "Hi Jane, congrats on the Series A.",
"inmail": {
"subject": "Quick idea for Acme"
}
}'{ "data": { "message_id": "msg_93…", "chat_id": "chat_97",
"seat_id": "SExF…", "sent_at": "2026-10-22T15:06:00Z",
"drafts_dismissed": 0, "ai_stopped": false,
"counted_as": "outreach" } }Edit, unsend, react, mark read
Only your own seat's messages can be changed. The other person's messages never can.
| Call | What it does |
|---|---|
PATCH …/messages/{message_id} | Edit a message your seat sent: { "text": "…" }. The change shows on LinkedIn. |
DELETE …/messages/{message_id} | Unsend it. It disappears on LinkedIn too. |
POST …/messages/{message_id}/reactions | React with an emoji: { "reaction": "👍" }. The other person sees it. |
POST /inbox/{chat_id}/read | Mark it read in Gelee and on LinkedIn. Needs Read + write only. |
curl -X PATCH "https://www.gelee.ai/api/v1/inbox/chat_88/messages/msg_92…" \
-H "Authorization: Bearer gk_your_key" \
-H "Content-Type: application/json" \
-d '{
"text": "Thanks Jane, here is the report (updated link): https://acme.example/r/5d70"
}'AI drafts waiting for a yes
The person's message, the AI's draft and the whole story of the person, newest first.
| Call | What it does |
|---|---|
GET /drafts/{id} | One draft. |
PATCH /drafts/{id} | { "text": "…" } changes the words without sending. A draft about to auto-send is taken back for a person. |
POST /drafts/{id}/approve | Send it, like Approve in the app. Optional { "text" } sends your edit instead. Send permission. A draft that already went out answers 409 draft_not_pending. |
POST /drafts/{id}/skip | Nothing is sent and the AI stops drafting in that conversation. Optional { "reason" }. |
curl "https://www.gelee.ai/api/v1/drafts?status=pending" \
-H "Authorization: Bearer gk_your_key"{ "data": [
{ "id": "77c1…", "status": "pending", "name": "Jane Doe",
"their_message": "What does pricing look like for 3 seats?",
"ai_draft": "Happy to walk you through it. Does Thursday at 2pm work?",
"intent": "pricing_question",
"campaign": { "id": "9a2c…", "name": "Q4 Founders" },
"sender": { "seat_id": "SExF…", "name": "Sofia Salazar", … },
"chat": { "chat_id": "chat_88", "app_url": "…" },
"booking_likelihood": 78, … ,
"created_at": "2026-10-22T14:58:00Z" }
],
"pagination": { "limit": 50, "offset": 0, "total": 3 } }Replies handed to a person
Replies the AI SDR would not answer on its own, the same list as Inbox, Needs Human. reason_label is the plain-English version to show a person.
| reason | reason_label |
|---|---|
needs_human | The SDR could not answer this one |
wants_email | They asked to be emailed instead |
ai_callout | They asked whether they are talking to a bot |
auto_booked | A booking attempt needs a person to confirm it |
empty_or_too_short | The draft came back empty |
apology / leaked_reasoning / ai_admission | The draft failed a quality check |
bump_recheck_failed | We could not re-read the thread before following up |
blacklist_check_failed | We could not verify this person against the blocklist |
curl "https://www.gelee.ai/api/v1/needs-human" \
-H "Authorization: Bearer gk_your_key"{ "data": [
{ "id": "77c1…", "chat_id": "chat_88", "name": "Jane Doe",
"message": "Can you send pricing to jane@acme.com instead?",
"ai_draft": "Happy to send that over. What is the best address?",
"reason": "wants_email",
"reason_label": "They asked to be emailed instead",
"waiting_since": "2026-10-22T03:12:00Z", "hours_waiting": 6, … }
],
"pagination": { "limit": 50, "offset": 0, "total": 3 } }Went quiet after a yes
People who replied positively and then went quiet, stalest first. Each row has the whole story plus days_since_activity, last_activity_at and sentiment.
curl "https://www.gelee.ai/api/v1/stalled-leads?days=5" \
-H "Authorization: Bearer gk_your_key"Follow-up reminders
The inbox Follow-ups tab. The seat comes from the conversation, never from the request. When one comes due, a follow-up draft appears for approval, as in the app.
| Call | What it does |
|---|---|
GET /followups | Soonest first. ?status=pending (default), snoozed or done. |
PATCH /followups/{id} | { "status": "done" | "pending" | "snoozed", "due_at", "note" } |
DELETE /followups/{id} | Remove the reminder. |
curl -X POST "https://www.gelee.ai/api/v1/followups" \
-H "Authorization: Bearer gk_your_key" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "chat_88",
"due_at": "2026-11-03",
"note": "Asked to reconnect after their board meeting"
}'{ "data": { "id": "f_3c…", "chat": { "chat_id": "chat_88", "app_url": "…" },
"name": "Jane Doe", "sender": { "seat_id": "SExF…", … },
"due_at": "2026-11-03", "status": "pending",
"note": "Asked to reconnect after their board meeting" } }Common patterns
- Your own inbox: subscribe to the
reply_receivedwebhook, read the thread, and answer withPOST /inbox/{chat_id}/messages. The AI steps back from that conversation by default. - Approve from your own tool: list
GET /drafts, show the draft, then approve or skip. - Never double-send: always pass an
Idempotency-Keythat is unique to the message.