Skip to content

Overview

The Glitter AI API reads the guides, teams and members a key may see. It is read-only in v1.

Authentication

Every request carries an API key as a bearer token:

Authorization: Bearer glt_live_…

A team admin creates a key under My Team → API; an organization admin creates one under Organization Settings → API. A key belongs to one team, or to one organization and then reaches every team in it. A key sees every guide of its teams, drafts included, as a team admin does; only a guide whose recording is still processing stays out. The full key is shown once, at creation.

Scopes

A key carries the scopes it was created with: guides:read, teams:read, members:read. A request outside the key’s scopes answers 403 scope_missing.

Pagination

Lists take limit (1 to 100, default 50) and return next_cursor. Pass it back as cursor for the next page; null means the last page. Cursors are opaque.

Errors

Every refusal is one JSON shape (RFC 9457) with a stable code to switch on:

{ "type": "https://www.glitter.io/developers/api-reference#errors", "title": "Not found", "status": 404,
  "detail": "No guide 9c2f… is visible to this key.", "code": "not_found", "request_id": "…" }
Code Status Meaning
invalid_key 401 The bearer is missing, malformed, unknown or revoked.
key_expired 401 The key passed its expiry. Create a new one.
scope_missing 403 The key lacks the scope this endpoint needs.
api_disabled 403 The organization turned API access off.
team_keys_disabled 403 The organization allows organization keys only.
rate_limited 429 600 requests per minute per key. Retry-After says when.
invalid_request 400 A parameter is wrong; detail names it.
not_found 404 Nothing the key may see has that id.
internal_error 500 Our fault. Quote request_id to support.

Every response carries X-Request-Id, RateLimit-Limit and RateLimit-Remaining.

Webhooks

Glitter will POST a JSON envelope to an endpoint URL you add under My Team → API or Organization Settings → API when a guide is created, updated, deleted, finishes processing or fails, and when someone joins, leaves or changes role on a team. Pick the events when you add the endpoint. The Webhooks group below lists every event with its schema and an example; the Webhooks guide covers setup, delivery, retries, verification and troubleshooting.

Every guide in the team sends events, drafts included, which is what a team admin sees in the app; placement.team_guides tells a draft from a guide in Team Guides. The payload carries the guide’s summary and where it lives (placement), never its body: call GET /guides/{guideId} with your key for the content, in markdown_body. changed lists the columns a guide.updated event is about. Edits inside one minute arrive as one event.

Every delivery carries these headers:

Content-Type: application/json
User-Agent: Glitter-Webhooks/1
X-Glitter-Event: guide.updated
X-Glitter-Delivery: 7c1d…
X-Glitter-Signature: sha256=9f2c…

Checking the signature is optional. It is an HMAC-SHA256 of the raw body with the endpoint’s signing key, which you will find behind Reveal on the endpoint’s row. Complete verifiers in seven languages are behind that same button; the Node and Python ones:

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received, before any JSON parsing
export function verifyGlitterWebhook(rawBody, signatureHeader, signingKey) {
  const expected = 'sha256=' + createHmac('sha256', signingKey).update(rawBody).digest('hex');
  const given = signatureHeader ?? '';
  return expected.length === given.length && timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}

// Express
app.post('/glitter', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifyGlitterWebhook(req.body, req.get('X-Glitter-Signature'), process.env.GLITTER_SIGNING_KEY)) return res.sendStatus(401);
  const event = JSON.parse(req.body);
  res.sendStatus(200);
});
import hashlib
import hmac
import os

from flask import Flask, abort, request

app = Flask(__name__)


def verify_glitter_webhook(raw_body: bytes, signature_header: str | None, signing_key: str) -> bool:
    expected = "sha256=" + hmac.new(signing_key.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")


@app.post("/glitter")
def glitter():
    if not verify_glitter_webhook(request.get_data(), request.headers.get("X-Glitter-Signature"), os.environ["GLITTER_SIGNING_KEY"]):
        abort(401)
    event = request.get_json()
    return "", 200

Verify the raw bytes as received, before any JSON parsing. Rotating the key replaces it at once; deliveries that fail while you update your server are retried.

Answer any 2xx within 10 seconds. Glitter will not follow redirects. On any other answer Glitter will retry up to 8 times over about a day. After a day of nothing but failures the endpoint will pause and the admins of its home will get one email; a 410 pauses it at once. Resume from the endpoint’s menu, with the option to redeliver what was missed. Every attempt, with the request and the answer, is under Deliveries, where any one can be sent again. Glitter sends from no fixed IP addresses, so the signature is the way to know a request is Glitter’s.

Information

  • OpenAPI version: 3.1.0

A key created under My Team → API or Organization Settings → API.

Security scheme type: http

Bearer format: Glitter API key