Org Export API
Pull conversations, usage, and session metadata across every app in your organization with a single API key -- designed for warehouse sync and scheduled scripts
The Org Export API is a read-only REST API scoped to your entire organization rather than a single app. Use it to pull all your chat transcripts, usage data, and session metadata into a warehouse (Snowflake, BigQuery, Postgres) or to run attribution analysis on a schedule.
The Builder API (chipp_ keys) covers one app at a time. The Org Export API (chipp_org_* keys) covers all apps in your org with one key and one pull loop.
Authentication
Mint a key from the Chipp dashboard under Settings (org-level) or ask the Alchemist:
“Create an org read API key with the transcripts and usage scopes.”
Send the key as a Bearer token on every request:
Authorization: Bearer chipp_org_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBase URL: https://dino-mullet.chipp.ai/api/v1/org
Rate limit: 120 requests/minute per key. A 429 response includes Retry-After.
Scopes
Each key carries one or more read scopes. Requests outside a key’s scopes return 403:
| Scope | Grants |
|---|---|
apps:read | List the org’s apps |
transcripts:read | Read chat sessions and messages |
usage:read | Read token usage and cost rows |
Pagination
List endpoints (/sessions, /usage) are cursor-paginated, newest first:
?limit=(default 50, max 100)- Follow
pagination.next_cursoruntilpagination.has_moreisfalse - For incremental syncs, filter by time (
started_after,since) and keep the maxstarted_at/created_atseen as the checkpoint for the next run
"pagination": { "next_cursor": "eyJ...", "has_more": true, "limit": 50 }Endpoints
GET /apps
List the org’s apps (non-deleted, newest first).
curl -s "https://dino-mullet.chipp.ai/api/v1/org/apps" \
-H "Authorization: Bearer $CHIPP_ORG_KEY"{
"data": [
{
"id": "uuid",
"name": "Ask Max!",
"slug": "ask-max-8jw2",
"created_at": "2026-04-19T02:33:55.787Z",
"updated_at": "2026-06-04T23:55:47.228Z"
}
]
}GET /sessions
Chat sessions across all your org’s apps, newest first.
Query params: limit, cursor, app_id (filter to one app), started_after (ISO 8601), started_before (ISO 8601).
curl -s "https://dino-mullet.chipp.ai/api/v1/org/sessions?limit=100&started_after=2026-06-01T00:00:00Z" \
-H "Authorization: Bearer $CHIPP_ORG_KEY"{
"data": [
{
"id": "uuid",
"app_id": "uuid",
"consumer_id": "uuid|null",
"consumer_email": "patient@clinic.com|null",
"title": "Onboarding chat",
"source": "APP",
"external_id": "patient-abc123|null",
"query_params": [
{ "name": "rp_token", "value": "abc123" },
{ "name": "ab_variant", "value": "B" }
],
"started_at": "2026-06-15T14:30:00Z",
"ended_at": "2026-06-15T14:45:00Z",
"last_activity_at": "2026-06-15T14:45:00Z"
}
],
"pagination": { "next_cursor": "...", "has_more": true, "limit": 100 }
}external_id holds the value passed via ?chipp_external_id= (web sessions), or a channel-namespaced key like whatsapp:+15551234567 (channel sessions). null when not set.
query_params is the [{ name, value }] array of URL query params the consumer arrived with. These are captured at session creation and never change. Chipp control params (bt, session, share) are excluded. Use this for A/B arm attribution, referral token analysis, and campaign tracking — with no side-channel joins required.
GET /sessions/{sessionId}/messages
Messages for one session (must belong to your org).
Query params: include (comma-separated, optional).
Include values:
tool_details— adds a compacttoolsarray to each message that invoked a tool or rendered a component.
# Basic
curl -s "https://dino-mullet.chipp.ai/api/v1/org/sessions/<sessionId>/messages" \
-H "Authorization: Bearer $CHIPP_ORG_KEY"
# With tool markers
curl -s "https://dino-mullet.chipp.ai/api/v1/org/sessions/<sessionId>/messages?include=tool_details" \
-H "Authorization: Bearer $CHIPP_ORG_KEY"{
"data": {
"session": {
"id": "uuid",
"app_id": "uuid",
"consumer_id": "uuid|null",
"consumer_email": "patient@clinic.com|null",
"title": "Onboarding chat",
"source": "APP",
"external_id": "patient-abc123",
"query_params": [{ "name": "rp_token", "value": "abc123" }],
"started_at": "2026-06-15T14:30:00Z"
},
"messages": [
{
"id": "msg-001",
"role": "user",
"content": "Hi, I just signed up.",
"created_at": "2026-06-15T14:30:01Z"
},
{
"id": "msg-002",
"role": "assistant",
"content": "Welcome! Let me walk you through the next steps.",
"created_at": "2026-06-15T14:30:05Z",
"tools": [
{
"id": "toolu_01XYZ",
"name": "render_completion_screen",
"type": "custom_component",
"component": "CompletionScreen",
"success": true
}
]
}
],
"zdr": false
}
}Each tools marker has: { id?, name?, type?, component?, success? }. Heavy blobs (code, input, output) are excluded.
Detect completion: messages.some(m => m.tools?.some(t => t.name === "render_completion_screen"))
If an app has Zero Data Retention (ZDR) enabled, message bodies are ephemeral and not stored.
messagesis empty andzdristrue.
GET /usage
Per-call token usage and cost across the org’s apps, newest first.
Query params: limit, cursor, since (ISO 8601).
curl -s "https://dino-mullet.chipp.ai/api/v1/org/usage?since=2026-06-01T00:00:00Z&limit=100" \
-H "Authorization: Bearer $CHIPP_ORG_KEY"{
"data": [
{
"id": 123,
"app_id": "uuid",
"session_id": "uuid|null",
"consumer_id": "uuid|null",
"model": "claude-sonnet-4-6",
"source": "consumer",
"input_tokens": 1200,
"output_tokens": 340,
"cache_read_input_tokens": 800,
"cache_creation_input_tokens": 0,
"cost_usd": "0.012500",
"created_at": "2026-06-05T14:39:07.415Z"
}
],
"pagination": { "next_cursor": "...", "has_more": true, "limit": 100 }
}session_id is null for sessionless usage (Alchemist copilot, heartbeat). consumer_id is null for builder/anonymous sessions. Consumer email is on the /sessions endpoint (behind the transcripts:read scope) to keep this usage:read endpoint PII-free. Join consumer_id / session_id between the two endpoints.
Errors
{ "error": { "code": "...", "message": "..." } }:
| HTTP | When |
|---|---|
| 401 | Missing/invalid/expired key |
| 403 | Key lacks the required scope |
| 404 | Session not found (or not in your org) |
| 429 | Rate limited (see Retry-After) |
Cron / script pull recipe
This loop pulls new transcripts since the last sync and writes them to a local file. Adapt for Snowflake, BigQuery, or any datastore.
const ORG_KEY = process.env.CHIPP_ORG_KEY;
const BASE = "https://dino-mullet.chipp.ai/api/v1/org";
async function pull(sinceIso) {
// 1. List apps once to build the name map.
const { data: apps } = await fetch(`${BASE}/apps`, {
headers: { Authorization: `Bearer ${ORG_KEY}` }
}).then(r => r.json());
const appNames = Object.fromEntries(apps.map(a => [a.id, a.name]));
// 2. Page through sessions.
let cursor, maxStartedAt = sinceIso;
const sessions = [];
do {
const url = new URL(`${BASE}/sessions`);
url.searchParams.set("started_after", sinceIso);
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const { data, pagination } = await fetch(url, {
headers: { Authorization: `Bearer ${ORG_KEY}` }
}).then(r => r.json());
for (const s of data) {
// 3. Fetch messages with compact tool markers.
const msgUrl = `${BASE}/sessions/${s.id}/messages?include=tool_details`;
const { data: { messages } } = await fetch(msgUrl, {
headers: { Authorization: `Bearer ${ORG_KEY}` }
}).then(r => r.json());
sessions.push({
session_id: s.id,
app_name: appNames[s.app_id],
external_id: s.external_id,
query_params: s.query_params, // [{ name, value }] -- self-attributing
completed: messages.some(m =>
m.tools?.some(t => t.name === "render_completion_screen")
),
messages,
});
if (s.started_at > maxStartedAt) maxStartedAt = s.started_at;
}
cursor = pagination.next_cursor;
} while (cursor);
return { sessions, nextSince: maxStartedAt };
}Attribution pattern: Because query_params includes the arrival link’s params (e.g. rp_token, ab_variant), each row in sessions is already attributed — no join to an external mapping table required.
Relationship to the Builder API
Builder API (chipp_) | Org Export API (chipp_org_*) | |
|---|---|---|
| Scope | One app | All apps in org |
| Auth | Per-app key | Org-level key |
| Scripting | Manual per-app loop | Single paginated pull |
| ZDR | Returns empty messages | Returns empty messages |
| Tool markers | Raw tool_calls / tool_results blobs | Compact tools markers (no code) |
For the Builder API’s per-app sessions and messages endpoints, see Sessions.