This page demonstrates the most common API workflow: creating or finding a session, creating a ticket, and adding a comment to that ticket.
Base URL
The API host depends on the data region of your project:
Data region | API host |
|---|---|
EU (default) |
|
US |
|
https://api.gleap.io with your region's host. API tokens are per project and only valid in the project's region.Common Flow Example
This example walks through a complete workflow that you'll use frequently when integrating with the Gleap API.
Step 1: Create or Find a Session
First, create a session to represent a user or contact. If a session with the same userId already exists, you can use that session ID instead.
Endpoint: POST /v3/sessions
Request:
curl -X POST https://api.gleap.io/v3/sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_12345",
"email": "[email protected]",
"name": "John Doe",
"customData": {
"plan": "premium",
"signupDate": "2024-01-15"
}
}'Response:
{
"_id": "507f1f77bcf86cd799439011",
"id": "507f1f77bcf86cd799439011",
"userId": "user_12345",
"email": "[email protected]",
"name": "John Doe",
"customData": {
"plan": "premium",
"signupDate": "2024-01-15"
},
"createdAt": "2024-01-20T10:30:00.000Z",
"lastActivity": "2024-01-20T10:30:00.000Z"
}_id or id from the response - you'll need it to create a ticket linked to this session.Step 2: Create a Ticket
Now create a ticket and link it to the session you just created. The ticket represents a support request, bug report, or feature request.
Endpoint: POST /v3/tickets
Request:
curl -X POST https://api.gleap.io/v3/tickets \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"title": "Login button not working on mobile app",
"type": "BUG",
"session": "507f1f77bcf86cd799439011",
"formData": {
"description": "Users are unable to log in when clicking the login button on iOS devices. The button appears to be unresponsive."
}
}'Response:
{
"_id": "507f1f77bcf86cd799439022",
"id": "507f1f77bcf86cd799439022",
"title": "Login button not working on mobile app",
"type": "BUG",
"session": {
"_id": "507f1f77bcf86cd799439011",
"email": "[email protected]",
"name": "John Doe"
},
"formData": {
"description": "Users are unable to log in when clicking the login button on iOS devices. The button appears to be unresponsive."
},
"createdAt": "2024-01-20T10:35:00.000Z",
"updatedAt": "2024-01-20T10:35:00.000Z"
}_id or id from the ticket response - you'll need it to add comments to this ticket.Step 3: Create a Comment
Add a comment to the ticket. Comments can be simple text or rich formatted content. You can also attach files.
Endpoint: POST /v3/messages
Request (Simple Text Comment):
curl -X POST https://api.gleap.io/v3/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"ticket": "507f1f77bcf86cd799439022",
"comment": "Thank you for reporting this issue. We are looking into it and will update you soon."
}'Request (Rich Formatted Comment with Attachments):
curl -X POST https://api.gleap.io/v3/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"ticket": "507f1f77bcf86cd799439022",
"comment": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "We have identified the issue and deployed a fix. "
},
{
"type": "text",
"marks": [
{
"type": "bold"
}
],
"text": "Please update to version 2.3.2"
},
{
"type": "text",
"text": " to resolve this problem."
}
]
},
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "If you continue to experience issues, please let us know."
}
]
}
]
},
"attachments": [
{
"name": "fix-screenshot.png",
"url": "https://example.com/screenshots/fix-screenshot.png",
"type": "image/png"
}
]
}'Request (Internal Note):
curl -X POST https://api.gleap.io/v3/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"ticket": "507f1f77bcf86cd799439022",
"comment": "This is a high-priority issue affecting multiple users. Escalating to the mobile team.",
"isNote": true
}'Response:
{
"_id": "507f1f77bcf86cd799439033",
"id": "507f1f77bcf86cd799439033",
"ticket": "507f1f77bcf86cd799439022",
"comment": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "We have identified the issue and deployed a fix. "
},
{
"type": "text",
"marks": [
{
"type": "bold"
}
],
"text": "Please update to version 2.3.2"
},
{
"type": "text",
"text": " to resolve this problem."
}
]
}
]
},
"type": "TEXT",
"attachments": [
{
"name": "fix-screenshot.png",
"url": "https://example.com/screenshots/fix-screenshot.png",
"type": "image/png"
}
],
"user": {
"_id": "507f1f77bcf86cd799439044",
"email": "[email protected]",
"firstName": "Jane",
"lastName": "Support"
},
"createdAt": "2024-01-20T11:00:00.000Z",
"updatedAt": "2024-01-20T11:00:00.000Z"
}Step 4: Create a Comment from Markdown
Instead of building the rich-text JSON structure yourself, you can send Markdown via the markdownComment field. The server converts it to rich text automatically, and it takes precedence over comment if both are set.
Endpoint: POST /v3/messages
Request:
curl -X POST https://api.gleap.io/v3/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"ticket": "507f1f77bcf86cd799439022",
"markdownComment": "We have identified the issue and deployed a fix. **Please update to version 2.3.2** to resolve this problem."
}'Reading a Ticket's Status History
Every internal change to a ticket (status, assignee, team, priority, type, tags, title, due date) is recorded as a history entry. Use the ticket history endpoint to read them:
Endpoint: GET /v3/tickets/{ticketId}/history
Request:
curl -X GET "https://api.gleap.io/v3/tickets/507f1f77bcf86cd799439022/history" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID"Response:
{
"items": [
{
"id": "689b1f77bcf86cd799439031",
"ticket": "507f1f77bcf86cd799439022",
"type": "FEEDBACK_UPDATED",
"data": {
"type": "STATUS",
"value": "INPROGRESS"
},
"user": {
"id": "507f1f77bcf86cd799439012",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe"
},
"bot": false,
"createdAt": "2026-08-07T10:30:00.000Z",
"ticketHistoryRow": true
},
{
"id": "689b1f77bcf86cd799439032",
"ticket": "507f1f77bcf86cd799439022",
"type": "FEEDBACK_UPDATED",
"data": {
"type": "PROCESSING_USER",
"value": {
"id": "507f1f77bcf86cd799439012",
"firstName": "John",
"lastName": "Doe"
}
},
"fallbackUser": { "username": "System" },
"bot": false,
"createdAt": "2026-08-07T10:31:00.000Z",
"ticketHistoryRow": true
}
],
"truncated": false
}Key details:
Entries are returned oldest first. The endpoint is not paginated;
limitdefaults to 1000 (max 5000) andtruncatedistruewhen the ticket has more entries thanlimit, in which case the oldest entries are the ones left out.For
FEEDBACK_UPDATEDentries,data.typeidentifies what changed:STATUS,PROCESSING_USER,PROCESSING_TEAM,PRIORITY,TYPE,SESSION,SESSIONS_ADDED,SESSIONS_REMOVED,ARCHIVED,RESTORED,TAGS_ADDED,TAGS_REMOVED,DUE_DATE,TITLE,TICKET_LINKED,TICKET_UNLINKED,DUPLICATE,QUEUED,MARKED_AS_SPAMorEMAIL_RELAYED.data.valuecarries the new value only (for status changes, the status key of the target Kanban lane); the previous value is the one in the entry before.PROCESSING_TEAMentries carryvalue: { "_id": "<team id>", "name": "<team name>" }(read_id; some entries also carryid), orvalue: nullwhen the team was removed.Besides
FEEDBACK_UPDATED, the history containsSYSTEM_MESSAGEentries (data.typeWORKFLOW_MESSAGEorAGENT_HANDOFF_TO_HUMAN) andINTEGRATION_STATUS_UPDATEDentries.An entry's
idis stored with it and never changes, so you can use it as a deduplication key.History entries are retained for at least 180 days from each event. If you need a longer record, fetch and persist them on your side.
GET /v3/messages as FEEDBACK_UPDATED messages. That endpoint now returns conversation messages only — integrations that reconstruct status history from /v3/messages should switch to /v3/tickets/{ticketId}/history, which returns the same entry shape.Uploading Images for Help Center Articles
Help center article content is rich text (TipTap JSON). Images inside an article are image nodes that reference a hosted image URL, so adding screenshots via the API is a two-step flow: upload each image to get a permanent CDN URL, then reference those URLs in the article content.
Step 1: Upload the Image
Send the file as multipart/form-data in a form field named file (up to 100 MB).
Endpoint: POST /v3/uploads
Request:
curl -X POST https://api.gleap.io/v3/uploads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-F "file=@./screenshots/settings-page.png"Response:
{
"success": true,
"fileUrl": "https://staticfiles.gleap.io/p507f191e810c19729de860ea/20260810093015_4821.png"
}If your images are already hosted at a public URL, you can import them instead of re-uploading. The server downloads the image, validates that it really is one (PNG, JPEG, GIF, WebP, SVG or BMP), and stores a copy on the Gleap CDN:
Endpoint: POST /v3/uploads/from-url
Request:
curl -X POST https://api.gleap.io/v3/uploads/from-url \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{ "url": "https://cdn.example.com/screenshots/settings-page.png" }'Step 2: Reference the Images in the Article Content
Use each returned fileUrl as the src of an image node when creating or updating an article:
Endpoint: POST /v3/helpcenter/collections/{helpcenterCollectionId}/articles
Request:
curl -X POST https://api.gleap.io/v3/helpcenter/collections/HELPCENTER_COLLECTION_ID/articles \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"title": "Configuring your settings",
"content": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Open the settings page:" }]
},
{
"type": "image",
"attrs": { "src": "https://staticfiles.gleap.io/p507f191e810c19729de860ea/20260810093015_4821.png" }
}
]
},
"isDraft": false
}'Bulk Uploads
There is no separate batch endpoint — upload files one request at a time and collect the returned URLs. A small script keeps this manageable:
for f in ./screenshots/*.png; do
url=$(curl -s -X POST https://api.gleap.io/v3/uploads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Project: YOUR_PROJECT_ID" \
-F "file=@$f" | jq -r .fileUrl)
echo "$f -> $url"
done
