API Overview
HTTP endpoints for interacting with Struere
Struere exposes 30 HTTP endpoints through its Convex backend, including the Chat API (POST /v1/agents/:slug/chat), a full Data API for entity CRUD, WhatsApp template management, CLI sync, and 6 webhook receivers for Clerk, Kapso, Flow, Polar, Resend, and studio relay.
Base URL
Your API base URL is shown in the dashboard under Settings > API Keys.
https://api.struere.dev
Authentication
Chat endpoints authenticate via Bearer token using API keys. API keys are created in the Struere dashboard under API Keys and are scoped to a specific environment (development or production).
Authorization: Bearer sk_dev_abc123...
The environment of the API key determines which environment the request operates in. A development API key accesses development agents, entities, and configurations. A production API key accesses production data. There is no way to cross environments with a single key.
API keys are validated by computing a SHA-256 hash and looking up the hashed value in the database.
Permissions
Each API key has a set of permissions that control which endpoints it can access.
| Permission | Access |
|---|---|
* |
Full access to all endpoints (chat, data, sync) |
chat |
Chat endpoints (/v1/chat, /v1/agents/:slug/chat) |
data |
Data API endpoints (/v1/data/*, /v1/entity-types) |
sync |
CLI sync endpoints (/v1/sync/*) |
Keys created in the dashboard default to * (full access). When creating keys programmatically or through the agent settings page, you can restrict permissions to specific scopes.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/health |
None | Health check |
POST |
/v1/chat |
Bearer token | Chat with an agent by ID or router by slug |
POST |
/v1/agents/:slug/chat |
Bearer token | Chat with an agent by slug |
POST |
/v1/routers/:slug/chat |
Bearer token | Chat via a router by slug |
POST |
/v1/compile-prompt |
Bearer token | Compile an agent's system prompt |
POST |
/v1/run-tool |
Bearer token | Run a tool as it would in a real conversation (agentSlug optional) |
POST |
/v1/fire-trigger |
Bearer token | Manually fire a trigger for testing |
POST |
/v1/sync/state |
Bearer token (sync) | Get current sync state for an environment |
POST |
/v1/sync/pull |
Bearer token (sync) | Pull remote resource state for local sync |
GET |
/v1/entity-types |
Bearer token (data) | List entity types |
GET |
/v1/data/:type |
Bearer token (data) | List entities |
GET |
/v1/data/:type/:id |
Bearer token (data) | Get entity by ID |
POST |
/v1/data/:type |
Bearer token (data) | Create entity |
POST |
/v1/data/:type/query |
Bearer token (data) | Query entities with filters |
POST |
/v1/data/:type/search |
Bearer token (data) | Full-text search entities |
PATCH |
/v1/data/:type/:id |
Bearer token (data) | Update entity |
DELETE |
/v1/data/:type/:id |
Bearer token (data) | Delete entity |
POST |
/webhook/clerk |
None | Clerk user/organization sync webhook |
POST |
/webhook/kapso/project |
HMAC signature | WhatsApp phone number connection events |
POST |
/webhook/kapso/messages |
HMAC signature | WhatsApp inbound messages and status updates |
POST |
/webhook/flow |
None | Flow payment status updates |
POST |
/webhook/polar |
HMAC signature | Polar payment/billing events |
GET /health
Returns the current server status and timestamp.
Request:
curl https://api.struere.dev/health
Response:
{
"status": "ok",
"timestamp": 1710500000000
}
POST /v1/chat
Send a message to an agent identified by its Convex document ID, or route through a router by providing routerSlug instead. See the Chat API documentation for full details.
POST /v1/agents/:slug/chat
Send a message to an agent identified by its slug. This is the preferred endpoint for external integrations as slugs are human-readable and stable across deployments. See the Chat API documentation for full details.
POST /v1/routers/:slug/chat
Send a message through a router identified by its slug. The router evaluates routing rules or classifies the message to determine which agent handles the conversation. See the Chat API documentation for full details.
POST /v1/compile-prompt
Compile an agent's system prompt with template variables resolved. Useful for debugging and testing system prompt templates without sending a real message.
Body:
| Field | Type | Required | Description |
|---|---|---|---|
slug |
string |
Yes | The agent slug |
message |
string |
No | Sample message for context |
channel |
string |
No | Sample channel (api, whatsapp, widget, dashboard) |
threadMetadata |
object |
No | Sample thread metadata for template resolution |
Response: The compiled system prompt text and resolved template variables.
POST /v1/run-tool
Run a tool exactly as it would execute during a real agent conversation. Useful for testing tool behavior without triggering a full agent execution loop.
Body:
| Field | Type | Required | Description |
|---|---|---|---|
agentSlug |
string |
No | The agent slug to run the tool as. If omitted, runs as system actor |
toolName |
string |
Yes | The tool to execute (e.g., entity.query, whatsapp.send) |
args |
object |
No | Arguments to pass to the tool |
Response: The tool execution result, or an error with errorType (not_found, tool_not_found, permission_denied, execution_error).
POST /v1/fire-trigger
Manually fire a trigger by slug. The trigger executes its actions as it would in a real activation, using the system actor. Useful for testing automations without waiting for a real data mutation or cron schedule.
Body:
| Field | Type | Required | Description |
|---|---|---|---|
triggerSlug |
string |
Yes | The trigger slug to fire |
entityId |
string |
No | Entity ID to use as trigger context |
data |
object |
No | Data payload to pass as trigger context (used in template variable resolution) |
Response:
{
"success": true,
"triggerSlug": "notify-on-session",
"result": {
"steps": [
{ "tool": "entity.get", "status": "success", "durationMs": 45 },
{ "tool": "event.emit", "status": "success", "durationMs": 12 }
],
"durationMs": 57
}
}
Error Response: Returns an error with errorType (not_found, permission_denied, execution_error).
Data API
CRUD and query operations for entities in your data layer. Requires an API key with the data permission. See the Data API documentation for full details.
Webhook Endpoints
Webhook endpoints receive events from external services. See the Webhooks documentation for details on each webhook.
Error Responses
All endpoints return JSON error responses with appropriate HTTP status codes:
401 Unauthorized — Missing or invalid API key:
{
"error": "Unauthorized"
}
400 Bad Request — Missing required fields:
{
"error": "agentId and message are required"
}
500 Internal Server Error — Server-side execution failure:
{
"error": "Error description"
}
Rate Limiting
Rate limits are enforced at the Convex platform level. Refer to your Convex plan for specific limits on function calls and bandwidth.
CORS
The Chat API and Data API endpoints set permissive CORS headers (Access-Control-Allow-Origin: *), so they can be called directly from browser-based applications without a proxy.
JavaScript Client
The struere npm package ships a typed JS client under the struere/client subpath. It works in browsers, Node 18+, Bun, and Deno with zero runtime dependencies.
import { StruereClient, StruereApiError } from 'struere/client'
const struere = new StruereClient({
apiKey: process.env.STRUERE_API_KEY!,
baseUrl: 'https://api.struere.dev',
})
const reply = await struere.chat({
agentSlug: 'coach',
message: 'Hi!',
})
const players = await struere.data.list<{ name: string }>('player', { limit: 50 })
const created = await struere.data.create('player', { name: 'Mia' })
const matches = await struere.data.query('player', { filters: { name: { $contains: 'Mia' } } })
try {
await struere.data.get('player', 'missing')
} catch (err) {
if (err instanceof StruereApiError) {
console.error(err.status, err.message, err.requestId)
}
}
The client throws StruereApiError on non-2xx responses with { status, message, code?, requestId?, details? }. Pass a custom fetch implementation via the fetch option for environments that lack a global.