Skip to content

Latest commit

 

History

History
2014 lines (1500 loc) · 47.4 KB

api-reference.md

File metadata and controls

2014 lines (1500 loc) · 47.4 KB

API Reference

Base URL: https://agentstate.app/api

Backward-compatible base: https://agentstate.app (routes under /v1/* mirror /api/v1/*).

Version Overview

V2 API (/api/v2/*) — Current Version

The V2 API provides improved performance, consistency, and developer experience:

  • Snake_case field names: All request and response fields use snake_case
  • Timestamps in milliseconds: All timestamps are Unix milliseconds (Date.now() format)
  • Cursor-based pagination: Efficient pagination with next_cursor and total count
  • Conditional includes: Use ?include=messages to fetch messages only when needed
  • HTTP method semantics: PATCH for partial updates, proper status codes
  • Deprecation headers: V1 endpoints return X-API-Deprecated: true warning header

V1 API (/api/v1/*) — Deprecated

V1 endpoints remain functional but are deprecated. All V1 responses include:

X-API-Deprecated: true
X-API-Sunset: 2027-01-01
Deprecation: true
Link: </api/v2/conversations>; rel="successor-version"

Migration guide: See V2 Migration below.


Conventions

  • Field names: snake_case in all request and response bodies.
  • IDs: nanoid, 21 characters (e.g., V1StGXR8_Z5jdHi6B-myT).
  • Timestamps: Unix milliseconds (Date.now() format), stored as integers.
  • Pagination: Cursor-based. Never offset-based. Pass cursor to get the next page; when next_cursor is null, there are no more results. V2 includes total count in pagination metadata.
  • Metadata: Arbitrary JSON object. Stored as serialized TEXT, parsed on read.

Authentication

All /v1/conversations/* and /v1/tags endpoints require a valid API key.

Pass the key as a Bearer token:

Authorization: Bearer as_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key format: as_live_ prefix followed by 40 base62 characters. Only the SHA-256 hash of the key is stored. The raw key is shown once at creation time.

Requests with a missing, malformed, or revoked key receive:

{ "error": { "code": "UNAUTHORIZED", "message": "Invalid API key" } }

Status: 401

Rate Limiting

All authenticated endpoints enforce a fixed-window rate limit per API key.

Parameter Value
Limit 100 requests per minute
Window 60 seconds (UTC-minute boundary)

Every response includes rate-limit headers:

Header Description
X-RateLimit-Limit Max requests per window (100)
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Unix timestamp (seconds) when the window resets
Retry-After Seconds until the window resets (only on 429)

When exceeded:

{ "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Maximum 100 requests per minute. Retry after N seconds." } }

Status: 429

Request Tracing

Every response includes an X-Request-Id header. You can pass your own X-Request-Id on the request (alphanumeric, hyphens, underscores, 1-64 chars); otherwise the server generates one. Use this value when reporting issues.

Error Format

All errors follow a consistent structure:

{
  "error": {
    "code": "MACHINE_CODE",
    "message": "Human-readable description"
  }
}

Error Codes

Code HTTP Status Description
BAD_REQUEST 400 Invalid JSON body or validation failure
UNAUTHORIZED 401 Missing or invalid API key
FORBIDDEN 403 Key valid but not authorized for this resource
NOT_FOUND 404 Resource does not exist
CONFLICT 409 Duplicate resource (e.g., external_id already exists)
RATE_LIMITED 429 Too many requests
INTERNAL_ERROR 500 Unexpected server error

Caching Behavior

Several endpoints use caching to improve performance and reduce database load. Cached responses may be served for a period of time after the initial request.

Auth Cache

API key lookups are cached for 60 seconds. This reduces database load on frequently-used keys while maintaining near-real-time updates when keys are created or revoked.

Analytics Endpoints

Analytics endpoints use aggressive caching with time-based TTLs:

Time Range Cache TTL
1-7 days 60 seconds
8-30 days 180 seconds
30+ days 300 seconds

This applies to:

  • GET /v1/analytics/summary
  • GET /v1/analytics/timeseries
  • GET /v1/analytics/tags
  • GET /v1/conversations/:id/analytics
  • GET /v1/projects/:id/analytics

Data Freshness

Cached responses may reflect data from up to the TTL ago. For most use cases, this delay is acceptable and provides significant performance benefits:

  • Reduced database load: Fewer queries for expensive aggregations
  • Faster responses: Cached data is served directly from memory
  • Lower latency: Especially beneficial for analytics over large time ranges

If you need absolutely real-time data, consider:

  • Using shorter time ranges for analytics queries (lower TTL)
  • Making individual conversation fetches instead of aggregate analytics

Conventions

  • Field names: snake_case in all request and response bodies.
  • IDs: nanoid, 21 characters (e.g., V1StGXR8_Z5jdHi6B-myT).
  • Timestamps: Unix milliseconds (Date.now() format), stored as integers.
  • Pagination: Cursor-based. Never offset-based. Pass cursor to get the next page; when next_cursor is null, there are no more results.
  • Metadata: Arbitrary JSON object. Stored as serialized TEXT, parsed on read.

V2 API Reference

All V2 endpoints require API key authentication and are located at /api/v2/*.

Authentication

Pass the key as a Bearer token:

Authorization: Bearer as_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key format: as_live_ prefix followed by 40 base62 characters. Only the SHA-256 hash of the key is stored. The raw key is shown once at creation time.

Rate Limiting

All V2 endpoints enforce a fixed-window rate limit per API key.

Parameter Value
Limit 100 requests per minute
Window 60 seconds (UTC-minute boundary)

Every response includes rate-limit headers:

Header Description
X-RateLimit-Limit Max requests per window (100)
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Unix timestamp (seconds) when the window resets
Retry-After Seconds until the window resets (only on 429)

Error Format

All errors follow a consistent structure:

{
  "error": {
    "code": "MACHINE_CODE",
    "message": "Human-readable description"
  }
}

Error Codes

Code HTTP Status Description
BAD_REQUEST 400 Invalid JSON body or validation failure
INVALID_CURSOR 400 Invalid cursor parameter
UNAUTHORIZED 401 Missing or invalid API key
FORBIDDEN 403 Key valid but not authorized for this resource
NOT_FOUND 404 Resource does not exist
CONFLICT 409 Duplicate resource (e.g., external_id already exists)
RATE_LIMITED 429 Too many requests
INTERNAL_ERROR 500 Unexpected server error

V2 Conversations API

All conversation endpoints require API key authentication.

Create Conversation

POST /api/v2/conversations

Creates a new conversation, optionally with initial messages.

Request body:

Field Type Required Description
external_id string No Caller-provided identifier. Must be unique within the project.
title string No Conversation title.
metadata object No Arbitrary key-value pairs.
messages array No Initial messages to attach.

Each message object:

Field Type Required Description
role string Yes One of: system, user, assistant, tool.
content string Yes Message content (min 1 character).
metadata object No Arbitrary key-value pairs.
token_count integer No Non-negative integer. Defaults to 0.

Response: 201 Created

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "project_id": "abc123",
  "external_id": null,
  "title": null,
  "metadata": null,
  "message_count": 1,
  "token_count": 0,
  "created_at": 1710000000000,
  "updated_at": 1710000000000
}

V2 Changes:

  • Messages are NOT included in the create response for efficiency
  • Use POST /api/v2/conversations/:id/messages to add messages separately

Errors:

  • 400 BAD_REQUEST -- Invalid body or validation failure.
  • 409 CONFLICT -- A conversation with the given external_id already exists.

List Conversations

GET /api/v2/conversations

Returns conversations for the authenticated project, ordered by updated_at.

Query parameters:

Parameter Type Default Description
limit integer 50 Results per page (1-100).
cursor string -- updated_at timestamp from next_cursor of a previous response.
order string desc Sort direction: asc or desc.
tag string -- Filter to conversations that have this tag.

Response: 200 OK

{
  "data": [
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "project_id": "abc123",
      "external_id": null,
      "title": "My conversation",
      "metadata": null,
      "message_count": 5,
      "token_count": 120,
      "created_at": 1710000000000,
      "updated_at": 1710000000000
    }
  ],
  "pagination": {
    "limit": 50,
    "next_cursor": "1710000000000",
    "total": 150
  }
}

V2 Changes:

  • Includes total count in pagination metadata

next_cursor is null when there are no more pages.

Get Conversation

GET /api/v2/conversations/:id

Returns a single conversation. Messages are NOT included by default.

Query parameters:

Parameter Type Default Description
include string -- Comma-separated resources to include. Use messages to include messages array.

Examples:

# Get conversation metadata only (no messages)
GET /api/v2/conversations/:id

# Include messages
GET /api/v2/conversations/:id?include=messages

Response: 200 OK

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "project_id": "abc123",
  "external_id": null,
  "title": "My conversation",
  "metadata": null,
  "message_count": 2,
  "token_count": 50,
  "created_at": 1710000000000,
  "updated_at": 1710000000000,
  "messages": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 5,
      "created_at": 1710000000000
    }
  ]
}

V2 Changes:

  • Messages NOT included by default (use ?include=messages)
  • Uses include query param instead of fields

Errors:

  • 404 NOT_FOUND -- Conversation not found.

Lookup by External ID

GET /api/v2/conversations/by-external-id/:externalId

Find a conversation by the caller-provided external_id. Messages are NOT included by default.

Response shape is identical to Get Conversation (without ?include=messages).

Errors: 404 NOT_FOUND

Update Conversation

PATCH /api/v2/conversations/:id

Update a conversation's title and/or metadata.

Request body:

Field Type Required Description
title string No New title.
metadata object No Replaces existing metadata entirely.

Response: 200 OK

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "project_id": "abc123",
  "external_id": null,
  "title": "Updated title",
  "metadata": { "key": "value" },
  "message_count": 2,
  "token_count": 50,
  "created_at": 1710000000000,
  "updated_at": 1710000080000
}

V2 Changes:

  • Uses PATCH instead of PUT (HTTP semantic improvement)

Errors: 404 NOT_FOUND

Delete Conversation

DELETE /api/v2/conversations/:id

Deletes a conversation and all its messages.

Response: 204 No Content

Errors: 404 NOT_FOUND


V2 Messages API

Manage messages within an existing conversation. All endpoints require API key authentication.

Append Messages

POST /api/v2/conversations/:id/messages

Add one or more messages to an existing conversation. Automatically updates the conversation's message_count, token_count, and updated_at.

Request body:

Field Type Required Description
messages array Yes At least 1 message. Same schema as Create Conversation messages.

Response: 204 No Content

V2 Changes:

  • Returns 204 No Content instead of 201 Created with message list
  • More efficient for bulk message inserts

Errors: 404 NOT_FOUND -- Conversation does not exist.

List Messages

GET /api/v2/conversations/:id/messages

Paginate through messages in chronological order.

Query parameters:

Parameter Type Default Description
limit integer 100 Results per page (1-500).
after string -- Created-at timestamp (unix ms) to start after (cursor).

Response: 200 OK

{
  "data": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 5,
      "created_at": 1710000000000
    }
  ],
  "pagination": {
    "limit": 100,
    "next_cursor": "1710000005000"
  }
}

next_cursor is the created_at timestamp of the last message in the page. Pass it as the after parameter for the next page. null when there are no more results.

V2 Changes:

  • Cursor is now created_at timestamp instead of message ID

Errors: 404 NOT_FOUND -- Conversation does not exist.


V2 Analytics API

Analytics endpoints for project-wide statistics. All endpoints require API key authentication and use caching for performance.

Usage Summary

GET /api/v2/analytics/summary

Returns summary statistics for a project, including total conversations, messages, tokens, and averages over a specified time period. Supports tag filtering.

Query parameters:

Parameter Type Default Description
start integer — Start timestamp (unix ms, inclusive). Defaults to 30 days ago.
end integer — End timestamp (unix ms, exclusive). Defaults to now.
tag string — Filter to conversations with this tag (can specify multiple times).

Response: 200 OK

{
  "project_id": "proj_abc123",
  "total_conversations": 150,
  "total_messages": 2250,
  "total_tokens": 180000,
  "avg_messages_per_conversation": 15.0,
  "avg_tokens_per_conversation": 1200.0,
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  }
}

V2 Changes:

  • Includes project_id in response
  • No project_id query parameter required (derived from API key)

Caching:

  • 1-7 day ranges: 60 seconds
  • 8-30 day ranges: 180 seconds
  • 30+ day ranges: 300 seconds

Time Series Data

GET /api/v2/analytics/timeseries

Returns time-series data for conversations, messages, or tokens grouped by the specified granularity.

Query parameters:

Parameter Type Default Description
metric string "conversations" Metric to aggregate: conversations, messages, or tokens.
granularity string "day" Time grouping: day, week, or month.
start integer — Start timestamp (unix ms, inclusive). Defaults to 30 days ago.
end integer — End timestamp (unix ms, exclusive). Defaults to now.
tag string — Filter to conversations with this tag (can specify multiple times).

Response: 200 OK

{
  "project_id": "proj_abc123",
  "metric": "conversations",
  "granularity": "day",
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  },
  "data": [
    {"bucket": "2024-01-01", "value": 15},
    {"bucket": "2024-01-02", "value": 18},
    {"bucket": "2024-01-03", "value": 12}
  ]
}

V2 Changes:

  • Includes project_id in response
  • No project_id query parameter required

Caching: Same as summary endpoint.

Tag Statistics

GET /api/v2/analytics/tags

Returns usage statistics for tags within a specified time period.

Query parameters:

Parameter Type Default Description
start integer — Start timestamp (unix ms, inclusive). Defaults to 30 days ago.
end integer — End timestamp (unix ms, exclusive). Defaults to now.
limit integer 50 Maximum number of tags to return (1-200).

Response: 200 OK

{
  "project_id": "proj_abc123",
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  },
  "data": [
    {
      "tag": "support",
      "conversation_count": 45,
      "message_count": 675,
      "token_count": 54000
    },
    {
      "tag": "sales",
      "conversation_count": 32,
      "message_count": 480,
      "token_count": 38400
    }
  ]
}

V2 Changes:

  • Includes project_id in response
  • conversation_count instead of count (clearer naming)

Caching: Same as summary endpoint.


V2 Projects API

Project management endpoints. All endpoints require API key authentication.

Create Project

POST /api/v2/projects

Creates a new project and auto-generates a default API key.

Request body:

Field Type Required Description
name string Yes Project display name.
slug string Yes URL-safe identifier. Lowercase alphanumeric and hyphens only. Must be unique within the organization.
org_id string No Clerk organization ID. Defaults to "default".

Response: 201 Created

{
  "project": {
    "project_id": "proj_abc123",
    "org_id": "org_xyz",
    "name": "My Project",
    "slug": "my-project",
    "created_at": 1710000000000,
    "updated_at": 1710000000000
  },
  "api_key": {
    "id": "key_abc123",
    "name": "Default",
    "key_prefix": "as_live_xxxx",
    "key": "as_live_full_key_shown_only_once",
    "created_at": 1710000000000
  }
}

V2 Changes:

  • Includes updated_at in project response
  • Field names use snake_case (project_id, org_id)

Errors:

  • 400 BAD_REQUEST -- Validation failure.
  • 409 CONFLICT -- Slug already taken in this organization.

List Projects

GET /api/v2/projects

Query parameters:

Parameter Type Default Description
org_id string "default" Clerk organization ID to filter by.
limit integer 50 Results per page (1-100).
cursor string -- created_at timestamp from next_cursor of a previous response.

Response: 200 OK

{
  "data": [
    {
      "project_id": "proj_abc123",
      "org_id": "org_xyz",
      "name": "My Project",
      "slug": "my-project",
      "created_at": 1710000000000,
      "key_count": 2
    }
  ],
  "pagination": {
    "limit": 50,
    "next_cursor": "1710000000000",
    "total": 10
  }
}

V2 Changes:

  • Includes total count in pagination
  • Snake_case field names

Get Project by ID

GET /api/v2/projects/:id

Returns the project with its API keys.

Response: 200 OK

{
  "project_id": "proj_abc123",
  "org_id": "org_xyz",
  "name": "My Project",
  "slug": "my-project",
  "created_at": 1710000000000,
  "api_keys": [
    {
      "id": "key_abc123",
      "name": "Default",
      "key_prefix": "as_live_xxxx",
      "created_at": 1710000000000,
      "last_used_at": 1710000000000,
      "revoked_at": null
    }
  ]
}

V2 Changes:

  • api_keys instead of apiKeys
  • Snake_case field names

Errors: 404 NOT_FOUND

Update Project

PATCH /api/v2/projects/:id

Update a project's name.

Request body:

Field Type Required Description
name string Yes New project name.

Response: 200 OK

{
  "project_id": "proj_abc123",
  "org_id": "org_xyz",
  "name": "Updated Project Name",
  "slug": "my-project",
  "created_at": 1710000000000,
  "updated_at": 1710000080000,
  "api_keys": [...]
}

V2 Changes:

  • Uses PATCH instead of PUT
  • Includes updated_at in response

Errors: 404 NOT_FOUND

Delete Project

DELETE /api/v2/projects/:id

Permanently deletes a project and all associated data, including:

  • All conversations in the project
  • All messages in those conversations
  • All API keys for the project
  • All tags on conversations

Caution: This operation is irreversible. All data will be permanently deleted.

Response: 204 No Content

Errors:

  • 404 NOT_FOUND — Project not found

V2 Keys API

API key management endpoints. All endpoints require API key authentication.

Create API Key

POST /api/v2/keys

Creates a new API key for the authenticated project.

Request body:

Field Type Required Description
name string Yes Key display name (1-255 characters).

Response: 201 Created

{
  "key_id": "key_abc123",
  "project_id": "proj_abc123",
  "name": "Production",
  "key_prefix": "as_live_xxxx",
  "key": "as_live_full_key_shown_only_once",
  "created_at": 1710000000000,
  "last_used_at": null,
  "revoked_at": null
}

The key field contains the full API key and is only returned at creation time. Store it securely.

V2 Changes:

  • key_id instead of id
  • Includes project_id in response

Errors:

  • 400 BAD_REQUEST -- Validation failure.

List API Keys

GET /api/v2/keys

Lists all API keys for the authenticated project (including revoked ones).

Response: 200 OK

{
  "data": [
    {
      "key_id": "key_abc123",
      "project_id": "proj_abc123",
      "name": "Default",
      "key_prefix": "as_live_xxxx",
      "created_at": 1710000000000,
      "last_used_at": 1710000000000,
      "revoked_at": null
    }
  ]
}

The full key is never returned after creation.

V2 Changes:

  • key_id instead of id
  • Includes project_id in each key object

Revoke API Key

DELETE /api/v2/keys/:id

Soft-deletes an API key by setting revoked_at. The key immediately becomes invalid for authentication.

Response: 204 No Content

Errors:

  • 404 NOT_FOUND -- API key not found.

V2 Migration Guide

Key Changes from V1 to V2

  1. Base Path: /api/v1/* → /api/v2/*
  2. Messages in Get Conversation: V1 includes messages by default. V2 requires ?include=messages
  3. Create Conversation Response: V1 returns created messages. V2 returns only conversation metadata
  4. Update Method: V1 uses PUT. V2 uses PATCH
  5. Append Messages Response: V1 returns created messages. V2 returns 204 No Content
  6. Pagination: V2 includes total count in metadata
  7. Analytics: V2 derives project_id from API key, no need to pass it as query parameter
  8. Field Names: V2 consistently uses snake_case (e.g., key_id instead of id)

Migration Steps

  1. Update base URLs: Change /api/v1/ to /api/v2/ in your code
  2. Update conversation fetches: Add ?include=messages when you need messages
  3. Handle create response: V2 create no longer returns messages
  4. Update field name references: Use V2 field names (e.g., key_id, project_id)
  5. Remove project_id from analytics: The API key determines the project automatically
  6. Update pagination handling: Use pagination.total for total counts

Example Migration

V1:

// Create conversation
const response = await fetch('/api/v1/conversations', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer as_live_xxx' },
  body: JSON.stringify({ messages: [{ role: 'user', content: 'Hello' }] })
});
const { messages } = await response.json();
// messages is available in response

V2:

// Create conversation
const response = await fetch('/api/v2/conversations', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer as_live_xxx' },
  body: JSON.stringify({ messages: [{ role: 'user', content: 'Hello' }] })
});
const conversation = await response.json();
// messages NOT in response - conversation created efficiently

// Later, fetch messages when needed
const msgResponse = await fetch(`/api/v2/conversations/${conversation.id}/messages`);
const { data: messages } = await msgResponse.json();

Conversations API (V1 - Deprecated)

⚠️ Deprecated: V1 endpoints are deprecated and will be removed on 2027-01-01. All V1 responses include deprecation headers. Please migrate to V2 API.

All conversation endpoints require API key authentication.

Create Conversation (V1 - Deprecated)

POST /v1/conversations

Creates a new conversation, optionally with initial messages.

Request body:

Field Type Required Description
external_id string No Caller-provided identifier. Must be unique within the project.
title string No Conversation title.
metadata object No Arbitrary key-value pairs.
messages array No Initial messages to attach.

Each message object:

Field Type Required Description
role string Yes One of: system, user, assistant, tool.
content string Yes Message content (min 1 character).
metadata object No Arbitrary key-value pairs.
token_count integer No Non-negative integer. Defaults to 0.

Response: 201 Created

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "project_id": "abc123",
  "external_id": null,
  "title": null,
  "metadata": null,
  "message_count": 1,
  "token_count": 0,
  "created_at": 1710000000000,
  "updated_at": 1710000000000,
  "messages": [
    {
      "id": "xYz789_AbCdEfGhIjKlM",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 0,
      "created_at": 1710000000000
    }
  ]
}

Errors:

  • 400 BAD_REQUEST -- Invalid body or validation failure.
  • 409 CONFLICT -- A conversation with the given external_id already exists.

List Conversations (V1 - Deprecated)

GET /v1/conversations

Returns conversations for the authenticated project, ordered by updated_at.

Query parameters:

Parameter Type Default Description
limit integer 50 Results per page (1-100).
cursor string -- updated_at timestamp from next_cursor of a previous response.
order string desc Sort direction: asc or desc.
tag string -- Filter to conversations that have this tag.

Response: 200 OK

{
  "data": [
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "project_id": "abc123",
      "external_id": null,
      "title": "My conversation",
      "metadata": null,
      "message_count": 5,
      "token_count": 120,
      "created_at": 1710000000000,
      "updated_at": 1710000000000
    }
  ],
  "pagination": {
    "limit": 50,
    "next_cursor": "1710000000000"
  }
}

next_cursor is null when there are no more pages.

Get Conversation (V1 - Deprecated)

GET /v1/conversations/:id

Returns a single conversation with all its messages.

Query parameters:

Parameter Type Default Description
fields string all Comma-separated field names to include. Special: !messages excludes messages array.

Valid fields: id, project_id, external_id, title, metadata, message_count, token_count, created_at, updated_at, messages

Examples:

# Get only conversation metadata (no messages)
GET /v1/conversations/:id?fields=id,title,updated_at

# Exclude messages array
GET /v1/conversations/:id?fields=!messages

# Get all fields (default behavior)
GET /v1/conversations/:id

Performance: When messages is excluded, the database query for messages is skipped entirely, significantly reducing response time and bandwidth for conversations with many messages.

Response: 200 OK

{
  "id": "V1StGXR8_Z5jdHi6B-myT",
  "project_id": "abc123",
  "external_id": null,
  "title": "My conversation",
  "metadata": null,
  "message_count": 2,
  "token_count": 50,
  "created_at": 1710000000000,
  "updated_at": 1710000000000,
  "messages": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 5,
      "created_at": 1710000000000
    }
  ]
}

Errors:

  • 400 BAD_REQUEST -- Invalid field name specified.
  • 404 NOT_FOUND -- Conversation not found.

Lookup by External ID (V1 - Deprecated)

GET /v1/conversations/by-external-id/:externalId

Find a conversation by the caller-provided external_id. Returns the conversation with all messages.

Response shape is identical to Get Conversation.

Errors: 404 NOT_FOUND

Search Conversations (V1 - Deprecated)

GET /v1/conversations/search

Full-text search across message content. Returns matching conversations with a text snippet showing the match context.

Query parameters:

Parameter Type Default Description
q string -- Required. Search query.
limit integer 20 Results per page (1-100).
cursor string -- updated_at timestamp from next_cursor of a previous response.

Response: 200 OK

{
  "data": [
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "title": "My conversation",
      "snippet": "...matching text around the query...",
      "message_count": 5,
      "created_at": 1710000000000,
      "updated_at": 1710000000000
    }
  ],
  "next_cursor": null
}

Errors: 400 BAD_REQUEST -- Missing or empty q parameter.

Conversation Analytics (V1 - Deprecated)

GET /v1/conversations/:id/analytics

Returns analytics data for a specific conversation, including message counts, token counts, role breakdown, tag usage, and duration.

Response: 200 OK

{
  "conversation_id": "V1StGXR8_Z5jdHi6B-myT",
  "title": "My conversation",
  "message_count": 15,
  "token_count": 1250,
  "tags": ["support", "sales"],
  "duration_ms": 1800000,
  "messages_by_role": {
    "user": {
      "count": 10,
      "tokens": 850
    },
    "assistant": {
      "count": 5,
      "tokens": 400
    }
  },
  "created_at": 1710000000000,
  "updated_at": 1710086400000
}

Fields:

Field Type Description
conversation_id string Conversation ID
title string Conversation title
message_count integer Total number of messages
token_count integer Total tokens across all messages
tags array of strings Tags attached to this conversation
duration_ms integer Conversation duration in milliseconds
messages_by_role object Breakdown of messages and tokens by role
created_at integer Creation timestamp (unix ms)
updated_at integer Last update timestamp (unix ms)

Errors:

  • 404 NOT_FOUND — Conversation not found

Update Conversation (V1 - Deprecated)

PUT /v1/conversations/:id

Update a conversation's title and/or metadata.

Request body:

Field Type Required Description
title string No New title.
metadata object No Replaces existing metadata entirely.

Response: 200 OK

Returns the updated conversation object (same shape as list items, without messages).

Errors: 404 NOT_FOUND

Delete Conversation (V1 - Deprecated)

DELETE /v1/conversations/:id

Deletes a conversation and all its messages.

Response: 204 No Content

Errors: 404 NOT_FOUND

Bulk Delete

POST /v1/conversations/bulk-delete

Delete multiple conversations and their messages in a single request.

Request body:

Field Type Required Description
ids string[] Yes Conversation IDs to delete (1-100 items).

Response: 200 OK

{ "deleted": 3 }

The deleted count reflects only conversations that existed and belonged to the authenticated project.

Export Conversations

POST /v1/conversations/export

Export conversations with their full message history.

Request body:

Field Type Required Description
ids string[] No Specific conversation IDs to export (max 100). Omit to export the most recent 100.

Response: 200 OK

{
  "data": [
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "project_id": "abc123",
      "external_id": null,
      "title": "My conversation",
      "metadata": null,
      "message_count": 2,
      "token_count": 50,
      "created_at": 1710000000000,
      "updated_at": 1710000000000,
      "messages": [
        {
          "id": "msg_001",
          "role": "user",
          "content": "Hello",
          "metadata": null,
          "token_count": 5,
          "created_at": 1710000000000
        }
      ]
    }
  ],
  "count": 1
}

Messages are capped at 5000 total across all exported conversations.


Messages API

Manage messages within an existing conversation. All endpoints require API key authentication.

Append Messages

POST /v1/conversations/:id/messages

Add one or more messages to an existing conversation. Automatically updates the conversation's message_count, token_count, and updated_at.

Request body:

Field Type Required Description
messages array Yes At least 1 message. Same schema as Create Conversation messages.

Response: 201 Created

{
  "messages": [
    {
      "id": "xYz789_AbCdEfGhIjKlM",
      "role": "assistant",
      "content": "Hi there!",
      "metadata": null,
      "token_count": 10,
      "created_at": 1710000000000
    }
  ]
}

Errors: 404 NOT_FOUND -- Conversation does not exist.

List Messages

GET /v1/conversations/:id/messages

Paginate through messages in chronological order.

Query parameters:

Parameter Type Default Description
limit integer 100 Results per page (1-500).
after string -- Message ID to start after (cursor).

Response: 200 OK

{
  "data": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 5,
      "created_at": 1710000000000
    }
  ],
  "pagination": {
    "limit": 100,
    "next_cursor": "msg_001"
  }
}

next_cursor is the ID of the last message in the page. Pass it as the after parameter for the next page. null when there are no more results.

Errors: 404 NOT_FOUND -- Conversation does not exist.


Tags API

All tag endpoints require API key authentication.

List Project Tags

GET /v1/tags

Returns all unique tags used across the authenticated project's conversations.

Response: 200 OK

{
  "data": {
    "tags": ["bug", "feature", "support"]
  }
}

Get Conversation Tags

GET /v1/conversations/:id/tags

Returns tags attached to a specific conversation.

Response: 200 OK

{
  "data": {
    "tags": ["bug", "urgent"]
  }
}

Errors: 404 NOT_FOUND

Add Tags

POST /v1/conversations/:id/tags

Add tags to a conversation. Duplicate tags are silently ignored.

Request body:

Field Type Required Description
tags string[] Yes Tag names (1-50 items, each 1-64 characters).

Response: 201 Created

Returns the full list of tags now on the conversation (including previously existing ones):

{
  "data": {
    "tags": ["bug", "feature", "urgent"]
  }
}

Errors: 404 NOT_FOUND

Remove Tag

DELETE /v1/conversations/:id/tags/:tag

Remove a single tag from a conversation. No error if the tag was not present.

Response: 204 No Content

Errors: 404 NOT_FOUND -- Conversation does not exist.


Public Analytics

Public analytics endpoints for project-wide statistics. All endpoints require API key authentication.

Summary Statistics

GET /v1/analytics/summary

Returns summary statistics for a project, including total conversations, messages, tokens, and averages over a specified time period. Supports tag filtering.

Query parameters:

Parameter Type Default Description
project_id string — Required. Project ID (from API key)
start integer — Required. Start timestamp (unix ms, inclusive)
end integer — Required. End timestamp (unix ms, exclusive)
tag string — Filter to conversations with this tag (can specify multiple times)

Response: 200 OK

{
  "total_conversations": 150,
  "total_messages": 2250,
  "total_tokens": 180000,
  "avg_messages_per_conversation": 15.0,
  "avg_tokens_per_conversation": 1200.0,
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  }
}

Time Series Data

GET /v1/analytics/timeseries

Returns time-series data for conversations, messages, or tokens grouped by the specified granularity.

Query parameters:

Parameter Type Default Description
project_id string — Required. Project ID (from API key)
metric string "conversations" Metric to aggregate: conversations, messages, or tokens
granularity string "day" Time grouping: day, week, or month
start integer — Required. Start timestamp (unix ms, inclusive)
end integer — Required. End timestamp (unix ms, exclusive)
tag string — Filter to conversations with this tag (can specify multiple times)

Response: 200 OK

{
  "metric": "conversations",
  "granularity": "day",
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  },
  "data": [
    {"bucket": "2024-01-01", "value": 15},
    {"bucket": "2024-01-02", "value": 18},
    {"bucket": "2024-01-03", "value": 12}
  ]
}

Tag Statistics

GET /v1/analytics/tags

Returns usage statistics for tags within a specified time period.

Query parameters:

Parameter Type Default Description
project_id string — Required. Project ID (from API key)
start integer — Required. Start timestamp (unix ms, inclusive)
end integer — Required. End timestamp (unix ms, exclusive)
limit integer 50 Maximum number of tags to return (1-200)

Response: 200 OK

{
  "period": {
    "start": 1704067200000,
    "end": 1704153600000
  },
  "data": [
    {"tag": "support", "conversation_count": 45, "message_count": 675, "token_count": 54000},
    {"tag": "sales", "conversation_count": 32, "message_count": 480, "token_count": 38400},
    {"tag": "feedback", "conversation_count": 18, "message_count": 270, "token_count": 21600}
  ]
}

Caching

These endpoints use aggressive caching to reduce database load. Cached responses are served for:

  • 1-7 day ranges: 60 seconds
  • 8-30 day ranges: 180 seconds
  • 30+ day ranges: 300 seconds

AI Features

AI-powered endpoints using Cloudflare Workers AI. Require API key authentication.

Generate Title

POST /v1/conversations/:id/generate-title

Generates a title from the conversation's first 20 messages and saves it to the conversation.

Request body: None.

Response: 200 OK

{ "title": "Discussion about API design" }

Errors: 404 NOT_FOUND

Generate Follow-up Questions

POST /v1/conversations/:id/follow-ups

Generates suggested follow-up questions based on the conversation's last 20 messages.

Request body: None.

Response: 200 OK

{ "questions": ["What are the performance implications?", "How does this handle errors?"] }

Errors: 404 NOT_FOUND


Projects API

Dashboard-internal endpoints for project management. These routes do not require API key authentication (they are called from the dashboard frontend, authenticated via Clerk session).

Create Project

POST /v1/projects

Creates a new project and auto-generates a default API key.

Request body:

Field Type Required Description
name string Yes Project display name.
slug string Yes URL-safe identifier. Lowercase alphanumeric and hyphens only. Must be unique within the organization.
org_id string No Clerk organization ID. Defaults to "default".

Response: 201 Created

{
  "project": {
    "id": "proj_abc123",
    "org_id": "org_xyz",
    "name": "My Project",
    "slug": "my-project",
    "created_at": 1710000000000
  },
  "api_key": {
    "id": "key_abc123",
    "name": "Default",
    "key_prefix": "as_live_xxxx",
    "key": "as_live_full_key_shown_only_once",
    "created_at": 1710000000000
  }
}

Errors:

  • 400 BAD_REQUEST -- Validation failure.
  • 409 CONFLICT -- Slug already taken in this organization.

List Projects

GET /v1/projects

Query parameters:

Parameter Type Default Description
org_id string "default" Clerk organization ID to filter by.

Response: 200 OK

{
  "data": [
    {
      "id": "proj_abc123",
      "org_id": "org_xyz",
      "name": "My Project",
      "slug": "my-project",
      "created_at": 1710000000000,
      "key_count": 2
    }
  ]
}

Get Project by ID

GET /v1/projects/:id

Returns the project with its API keys.

Response: 200 OK

{
  "id": "proj_abc123",
  "org_id": "org_xyz",
  "name": "My Project",
  "slug": "my-project",
  "created_at": 1710000000000,
  "api_keys": [
    {
      "id": "key_abc123",
      "name": "Default",
      "key_prefix": "as_live_xxxx",
      "created_at": 1710000000000,
      "last_used_at": 1710000000000,
      "revoked_at": null
    }
  ]
}

Errors: 404 NOT_FOUND

Get Project by Slug

GET /v1/projects/by-slug/:slug

Same response shape as Get Project by ID.

Errors: 404 NOT_FOUND

List Project Conversations (Dashboard)

GET /v1/projects/:id/conversations

Returns conversations for a specific project (for dashboard display).

Query parameters:

Parameter Type Default Description
limit integer 50 Results per page (1-100).

Response: 200 OK

Same shape as List Conversations data array, wrapped in { "data": [...] }.

List Conversation Messages (Dashboard)

GET /v1/projects/:id/conversations/:convId/messages

Returns up to 500 messages for a conversation within a project. Returns an empty array if the conversation is not found (does not 404).

Response: 200 OK

{
  "data": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "Hello",
      "metadata": null,
      "token_count": 5,
      "created_at": 1710000000000
    }
  ]
}

Project Analytics

GET /v1/projects/:id/analytics

Usage analytics for a project.

Query parameters:

Parameter Type Default Description
range string "30d" Time range: 7d, 30d, or 90d.

Response: 200 OK

{
  "summary": {
    "total_conversations": 150,
    "total_messages": 3200,
    "total_tokens": 450000,
    "active_api_keys": 2
  },
  "conversations_per_day": [
    { "date": "2026-03-15", "count": 12 }
  ],
  "messages_per_day": [
    { "date": "2026-03-15", "count": 45 }
  ],
  "tokens_per_day": [
    { "date": "2026-03-15", "total": 6800 }
  ],
  "recent_conversations": [
    {
      "id": "V1StGXR8_Z5jdHi6B-myT",
      "title": "Latest chat",
      "message_count": 10,
      "token_count": 1500,
      "updated_at": 1710000000000
    }
  ]
}

Delete Project

DELETE /v1/projects/:id

Permanently deletes a project and all associated data, including:

  • All conversations in the project
  • All messages in those conversations
  • All API keys for the project
  • All tags on conversations

Caution: This operation is irreversible. All data will be permanently deleted.

Response: 204 No Content

Errors:

  • 404 NOT_FOUND — Project not found

Cascading Deletes:

  • When a project is deleted, all conversations are deleted
  • When conversations are deleted, all their messages are deleted
  • API keys and tags are also deleted
  • Foreign key constraints handle the cleanup automatically

API Key Management

Two sets of key management endpoints exist:

  1. Authenticated (/api/projects/:projectId/keys) -- requires a valid API key. The caller can only manage keys for the project their key belongs to.
  2. Dashboard (/v1/projects/:id/keys) -- used by the dashboard frontend. Authenticated via Clerk session, not API key.

Both sets share the same request/response shapes.

Create API Key

POST /api/projects/:projectId/keys       # Authenticated
POST /v1/projects/:id/keys               # Dashboard

Creates a new API key for the project.

Request body:

Field Type Required Description
name string Yes Key display name (1-255 characters).

Response: 201 Created

{
  "id": "key_abc123",
  "name": "Production",
  "key_prefix": "as_live_xxxx",
  "key": "as_live_full_key_shown_only_once",
  "created_at": 1710000000000,
  "last_used_at": null,
  "revoked_at": null
}

The key field contains the full API key and is only returned at creation time. Store it securely.

Errors:

  • 403 FORBIDDEN -- Attempting to create a key for a different project (authenticated route only).
  • 404 NOT_FOUND -- Project does not exist (dashboard route only).

List API Keys

GET /api/projects/:projectId/keys        # Authenticated

Lists all API keys for the project (including revoked ones).

Response: 200 OK

{
  "data": [
    {
      "id": "key_abc123",
      "name": "Default",
      "key_prefix": "as_live_xxxx",
      "created_at": 1710000000000,
      "last_used_at": 1710000000000,
      "revoked_at": null
    }
  ]
}

The full key is never returned after creation.

Errors:

  • 403 FORBIDDEN -- Attempting to list keys for a different project.

Revoke API Key

DELETE /api/projects/:projectId/keys/:keyId    # Authenticated
DELETE /v1/projects/:id/keys/:keyId            # Dashboard

Soft-deletes an API key by setting revoked_at. The key immediately becomes invalid for authentication.

Response: 204 No Content

Errors:

  • 403 FORBIDDEN -- Attempting to revoke a key for a different project (authenticated route only).

Health Check

GET /api

No authentication required.

Response: 200 OK

{ "name": "agentstate", "version": "0.1.0", "status": "ok" }

Machine-Readable Endpoints

GET /llms.txt        # LLM-readable project summary
GET /agents.md       # Agent-readable documentation
GET /openapi.json    # OpenAPI 3.x specification

No authentication required. These endpoints return plain text, markdown, and JSON respectively.