Developers

REST API

Read your project's conversations, visitors, calls and analytics from your own systems, and reply or mark work handled.

Overview

The Glimpze REST API gives your backend the same view of a project that the dashboard has: conversations and their messages, visitors and what they did, calls and their recordings, the analytics rollup, and whether a human is free right now. Four writes let an integration reply to a visitor, mark a conversation handled, correct a visitor's details, and leave an internal note.

Requests use JSON over HTTPS and carry an API key tied to one project. If you are building for the browser, use the JavaScript SDK instead. If you are connecting an AI agent, the MCP server speaks the same data with the same keys.

Base URL: https://api.glimpze.io/functions/v1/api-v1

Create an API key

In the Glimpze app, open Settings > API keys. You need to be the account owner. Pick the project the key is for, choose Read only or Read and write (or tick individual scopes), and create it.

The full key is shown once. Copy it somewhere safe; if you lose it, create a new one. Keys start with glz_live_.

Keep keys on the server, never in a web page or a mobile app. If a key leaks, revoke it in Settings.

Make your first request

Ask whether anyone on the team is online. It needs only the availability:read scope.

curl "https://api.glimpze.io/functions/v1/api-v1/public/projects/$PROJECT_ID/availability" \
  -H "Authorization: Bearer glz_live_..."

The response wraps the payload in data and adds a request id:

{
  "data": {
    "projectId": "ad7e6afd-28a6-48e3-96b5-1ba42695477b",
    "available": true,
    "agentsOnline": 1
  },
  "requestId": "0f0c1d2e-..."
}

Include requestId when you contact support about a request.

Authentication

Send the key as a bearer token in the Authorization header. The x-api-key header also works and takes precedence if both are present. Every request must use HTTPS.

A key belongs to one project. Requests for a different project fail with 403 api_key_wrong_project.

Scopes

Each key has an explicit list of scopes. Write scopes do not include read. If a key is missing a scope, the error says which one.

ScopeAllows
conversations:readList conversations, read one, read its messages
conversations:writeSend a message, mark a conversation handled
visitors:readList visitors, read a profile, read an activity timeline
visitors:writeUpdate a visitor's name and email, add an internal note
calls:readCall history, one call, recording metadata
analytics:readThe analytics rollup for a time window
availability:readLive agent availability

Reading conversations

List the conversations that still need attention. handled=false filters on the handled marker, since takes a timestamp, and limit goes up to 200.

curl "https://api.glimpze.io/functions/v1/api-v1/public/projects/$PROJECT_ID/conversations?handled=false&limit=20" \
  -H "Authorization: Bearer glz_live_..."
{
  "data": {
    "items": [
      {
        "id": "8cdb2d2e-94dd-4f52-bb09-bb5e5e9e8ec9",
        "projectId": "ad7e6afd-...",
        "visitorId": "e7b01b76-...",
        "status": "open",
        "createdAt": "2026-09-04T09:54:18Z",
        "lastMessageAt": "2026-09-04T09:54:19Z",
        "lastMessageSenderType": "agent",
        "handledAt": null,
        "waitingSince": null,
        "assignedAgentId": null,
        "origin": "visitor_initiated"
      }
    ],
    "hasMore": true
  },
  "requestId": "..."
}

status is always "open". Use handledAt to tell open work from finished work. The list has no message preview, so read the thread separately:

curl "https://api.glimpze.io/functions/v1/api-v1/public/conversations/$CONVERSATION_ID/messages" \
  -H "Authorization: Bearer glz_live_..."
{
  "id": 4288,
  "conversationId": "8cdb2d2e-...",
  "senderType": "agent",
  "kind": "utterance",
  "content": "Hi there! Let me know what I can help you with.",
  "senderDisplayName": "Glimpze AI",
  "createdAt": "2026-09-04T09:54:19Z"
}

Each message has a kind. Only utterance is something a person or the AI said; the rest are system events. Filter on it:

const spoken = messages.items.filter((m) => m.kind === "utterance");

Writing back

Writes take effect immediately and cannot be undone.

Send a message. senderName is required and is the name the visitor sees. Sending counts as a reply and clears handledAt.

curl -X POST "https://api.glimpze.io/functions/v1/api-v1/public/conversations/$CONVERSATION_ID/messages" \
  -H "Authorization: Bearer glz_live_..." \
  -H "Content-Type: application/json" \
  -d '{"content": "Your order shipped this morning.", "senderName": "Acme Support"}'

Mark handled. Send false to reopen.

curl -X POST "https://api.glimpze.io/functions/v1/api-v1/public/conversations/$CONVERSATION_ID/handled" \
  -H "Authorization: Bearer glz_live_..." \
  -H "Content-Type: application/json" \
  -d '{"handled": true}'

Update a visitor. Both fields are required. Send the current value for one you are not changing, or null to clear it.

curl -X PATCH "https://api.glimpze.io/functions/v1/api-v1/public/projects/$PROJECT_ID/visitors/$VISITOR_ID" \
  -H "Authorization: Bearer glz_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "Dana Scully", "email": "dana@example.com"}'

Responses and errors

Success responses are { data, requestId }. Failures use the same envelope with an error object instead of data:

{
  "error": {
    "code": "api_key_scope_missing",
    "message": "This API key is missing the required scope(s): conversations:write.",
    "status": 403,
    "retryable": false
  },
  "requestId": "..."
}
CodeStatusMeaning
api_key_missing401No credential on the request
api_key_invalid401Unknown or revoked key
api_key_wrong_project403The key is for a different project than the path
api_key_scope_missing403Valid key, missing scope; the message names it
VALIDATION_ERROR400Bad body or query; context.issues lists the fields
NOT_FOUND404No such row in your project
rate_limited429Back off; windows are 60 seconds

Timestamps must be RFC 3339, for example 2026-09-03T14:30:00Z.

Pagination and rate limits

Every list takes limit (1 to 200, default 50) and returns items plus hasMore. To page, pass the last timestamp you saw: since on conversations and visitors, from and to on calls and analytics, before on a visitor's activity.

Each key may make 600 requests per minute, 120 of them writes. Over the limit you get 429 rate_limited.

Endpoints

MethodPathScope
GET/public/projects/{projectId}/conversationsconversations:read
GET/public/conversations/{conversationId}conversations:read
GET/public/conversations/{conversationId}/messagesconversations:read
POST/public/conversations/{conversationId}/messagesconversations:write
POST/public/conversations/{conversationId}/handledconversations:write
GET/public/projects/{projectId}/visitorsvisitors:read
GET/public/projects/{projectId}/visitors/{visitorId}visitors:read
PATCH/public/projects/{projectId}/visitors/{visitorId}visitors:write
GET/public/projects/{projectId}/visitors/{visitorId}/activityvisitors:read
POST/public/projects/{projectId}/visitors/{visitorId}/notesvisitors:write
GET/public/projects/{projectId}/callscalls:read
GET/public/calls/{callId}calls:read
GET/public/calls/{callId}/recordingcalls:read
GET/public/projects/{projectId}/analyticsanalytics:read
GET/public/projects/{projectId}/availabilityavailability:read

The recording endpoint returns metadata only, not the media. A call without a recording answers hasRecording: false.

Parameters and response schemas for every endpoint are in the OpenAPI document: openapi.yaml. The same spec renders as a browsable reference at /public/docs.

Managing keys

Settings > API keys shows each key's prefix, scopes, creation date and last use. Revoke stops a key immediately, on this API and the MCP server. Rotate creates the new key before revoking the old one.

Not yet available: webhooks and starting a call from the API. Tell us if you need them.