Skip to main content
All requests carry your service-account token and ideally a pinned Gleap-Version. Send an Idempotency-Key (any unique string, e.g. a UUID) on POSTs you might retry.

1. Upsert the contact

Contacts are addressed by your user identifier and deduplicate with SDK-created contacts on the same id.
The response includes unread — the contact’s total unread conversation count for your badge.

2. Open a conversation

The first message rides along. workflowId starts a workflow exactly like the SDK’s startConversation; agentId engages an AI agent directly (the two are mutually exclusive). attributes values land as ticket attributes — define an attribute in Settings → Data attributes with shared visibility disabled and it is visible to your agents but never to the customer (the AI-handover-summary pattern):
A workflow’s first step lands asynchronously (~1 second). React to the workflow.step.presented event, or fetch GET /v3/s2s/conversations/{id}/workflow.

3. Send and read messages

Read oldest → newest, cursor-paginated (max 100 per page). Pass after = the last message id you already have:
author.type is contact, agent, bot or system. Internal team notes never appear on this surface.

4. Mark read

Reading messages never changes unread state — send the explicit receipt when your UI displays the conversation:

5. List the contact’s conversations

Most recent activity first; bot-only conversations without human interaction are hidden, exactly like the widget’s list:

6. Close / reopen

While closed, customer messages are rejected with problem code conversation_closed; POST …/reopen re-enables them. Your support team closing a conversation in the dashboard behaves identically and emits the same conversation.closed event.

Uploads & voice notes

Attach the returned descriptor to a message’s attachments. Max 25 MB per file.

Diagnostics: events & network logs

In the SDK flow the widget attaches the recent Gleap.trackEvent() buffer and Gleap.logNetwork() requests to a conversation when it is created. Without the SDK, push the same snapshots yourself — per conversation, so events from other sessions of the same contact never mix in:
Both return 204 and show up in the conversation’s Logs panel for agents. Each call replaces the previous snapshot for that conversation (an empty array clears it). Limits: 500 events / 100 requests, 2 MB per call. Nothing is emitted on webhooks or the stream.
POST /v3/s2s/contacts/{userId}/events is different: those events belong to the contact, feed outbound rules and the contact timeline, and are not attached to any conversation.
File URLs are signed and expire (about 1 day in API responses, about 30 days inside webhook payloads) and their signatures rotate. Never persist or deduplicate by URL — store the message id and re-fetch the message when you need a fresh link.