Get started
Keys and limits
API keys, scopes, the send permission, safe retries, rate limits and pagination.
API keys
Every request carries Authorization: Bearer gk_…. Make keys in the Gelee app under Settings, Integrations, API Keys. A key belongs to one workspace and only ever sees that workspace's data. Asking for something in another workspace answers 404, exactly like something that does not exist, so a key can never be used to probe other workspaces.
Keep keys on your server. Anyone holding one acts as an admin of that workspace, within its permission.
Permissions
Pick one when you make the key:
| Permission | What it allows |
|---|---|
| Read | Every GET: leads, people, conversations, campaigns, analytics, seats, settings, webhooks. |
| Read + write | Also every change: push leads and exclusions, change leads, campaigns, seats, the AI SDR and webhooks, record outcomes and conversions. |
| Read + write + send messages | Also anything the other person sees on LinkedIn: replies, new conversations, InMails, approved drafts, edits, unsends and reactions. |
A read key on a write endpoint gets 403 read_only_key. A key without the send permission gets 403 send_not_allowed on a send. Keys made before write support existed are read keys: make a new one.
Safe retries
Send an Idempotency-Key header with any send. If the network drops and you retry with the same key, you get the first answer back and nothing is sent twice. Use a value that is unique to that one message, for example your own message id.
Idempotency-Key: crm-msg-5d70-1Writes that are not sends are safe to repeat by design: pushing the same lead returns the same lead_id, adding a blocklist entry twice is a no-op, and marking someone booked twice records one booking.
Rate limits
| Limit | Value |
|---|---|
| Every endpoint | 120 requests a minute per workspace, shared by all of its keys. |
GET /inbox | 30 a minute, because it reads LinkedIn live. |
GET /health | 30 a minute, because it adds up the whole day. |
A 429 carries these headers. Wait for Retry-After seconds and try again.
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1786988000
Retry-After: 12Messages also count against each LinkedIn seat's own limits, exactly like campaign sends, to keep the account healthy. When a seat is out for now you get 429 seat_limit_reached with a time to try again. That is about the seat, not your key.
Pagination
Most lists take limit (default 50, max 200) and offset, and answer with { "pagination": { "limit", "offset", "total" } }. A few long lists (/people, conversation threads) use a cursor instead: pass the cursor from one page to get the next.
Versioning
Every path starts with /api/v1. We add fields and endpoints without warning, so ignore fields you do not know. Anything that would break your code ships as a new version.