API Reference
Programmatic access to every Stryda surface — workflows, agents, approvals, the MCP
control plane, and the audit ledger. All endpoints accept and return JSON. Base URL:
https://stryda.ai/api/v1.
Authentication
REST endpoints use an API key passed in the x-api-key header. Generate keys
in Settings → API Keys. MCP endpoints use a bearer token in the
Authorization header — see the MCP section below.
curl https://stryda.ai/api/v1/workflows \
-H "x-api-key: sk_live_xxxxxxxxxxxxxxxx" Rate limits
API endpoints: 60 requests per minute per key. Chatbot embed endpoints:
30 per minute per IP. Every response carries X-RateLimit-Limit,
X-RateLimit-Remaining, and X-RateLimit-Reset headers.
/api/auth/me Get the currently authenticated user's profile and plan details.
curl https://stryda.ai/api/auth/me \
-H "Authorization: Bearer YOUR_FIREBASE_TOKEN" {
"id": "user_abc123",
"email": "[email protected]",
"name": "Jane Smith",
"plan": "free",
"has_ai_access": true
} /api/auth/validate-key Validate an API key and return the associated user.
curl https://stryda.ai/api/auth/validate-key \
-H "x-api-key: sk_live_xxxxxxxxxxxxxxxx" {
"valid": true,
"user_id": "user_abc123",
"scopes": ["workflows", "chatbots", "agents", "tables", "forms", "memory"]
} MCP control plane
A single MCP server at /api/mcp exposes every tool, namespaced by surface.
Every tools/call goes through the same pipeline — validate → policy →
approval → adapter → audit — with no bypass. Clients connect with a bearer token
generated under Settings → MCP Clients.
Transport
Streamable HTTP with JSON-RPC 2.0 is the default. SSE is supported at
/api/mcp/sse for legacy clients.
/api/mcp The MCP JSON-RPC endpoint. Call tools/list to discover the catalog, tools/call to invoke a tool.
curl -X POST https://stryda.ai/api/mcp \
-H "Authorization: Bearer whsec_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "comms.send_slack_message",
"arguments": { "channel": "#general", "text": "hello" }
}
}' {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "comms.send_slack_message",
"arguments": { "channel": "#general", "text": "hello" }
}
} {
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "{\"ok\":true,\"ts\":\"1718212...\",\"_cost_usd\":0}" }
]
}
}
When a tool is gated (for example payments.create_refund, which registers
with requires_approval=True), the pipeline forces an escalation regardless
of scope:
{
"ok": false,
"status": "action_required",
"reason": "Tool requires explicit approval.",
"escalation_id": "esc_abc123",
"tool": "payments.create_refund"
} Catalog preview (without MCP transport)
For the onboarding UI and programmatic inspection, a plain REST endpoint returns the tool catalog:
/api/mcp/tools Returns the registered tool catalog — name, namespace, input schema, risk level, and whether approval is required.
curl https://stryda.ai/api/mcp/tools \
-H "x-api-key: YOUR_KEY" {
"tools": [
{
"name": "comms.send_slack_message",
"namespace": "comms",
"description": "Post a message to a Slack channel or DM.",
"input_schema": { "type": "object", "properties": { "channel": { "type": "string" }, "text": { "type": "string" } }, "required": ["channel", "text"] },
"requires_approval": false,
"risk": "low"
},
{
"name": "payments.create_refund",
"namespace": "payments",
"description": "Issue a Stripe refund.",
"requires_approval": true,
"risk": "high"
}
]
} Client registration
/api/mcp/clients Register an MCP client (Claude Desktop, Cursor, or custom). Returns a bearer token shown once.
{
"name": "Zain's laptop — Claude Desktop",
"kind": "claude_desktop"
} {
"client_id": "cli_abc123",
"kind": "claude_desktop",
"bearer": "whsec_xxxxxxxxxxxxxxxx",
"url": "https://mcp.stryda.ai/api/mcp",
"created_at": "2026-04-19T12:00:00Z"
} /api/mcp/clients/{client_id}/rotate Rotate the bearer token. The old token stops working immediately.
{
"client_id": "cli_abc123",
"bearer": "whsec_yyyyyyyyyyyyyyyy",
"rotated_at": "2026-04-19T12:30:00Z"
} /api/mcp/clients/{client_id}/revoke Revoke a client. Sets status to disconnected and nulls the bearer.
{
"client_id": "cli_abc123",
"status": "disconnected",
"revoked_at": "2026-04-19T12:45:00Z"
} Available tools
| Tool | Purpose |
|---|---|
comms.send_slack_message | Post a message to a Slack channel or DM. |
comms.send_email | Send an email via the connected Gmail account. |
crm.create_contact | Create a HubSpot contact. |
payments.create_refund | Issue a Stripe refund. Always requires human approval. |
workflow.zapier_action | Trigger a Zap on a connected Zapier account. |
workflow.n8n_trigger | Trigger an n8n workflow. |
workflow.make_scenario | Run a Make scenario. |
Want the full input schemas? GET /api/mcp/tools returns them. Want to add a
new tool? See Platforms and the MCP architecture
doc in the repo.
Workflows
/api/v1/workflows List all workflows for the authenticated user.
curl https://stryda.ai/api/v1/workflows \
-H "x-api-key: YOUR_KEY" [
{
"id": "wf_abc123",
"name": "Customer Support Triage",
"status": "published",
"node_count": 5,
"created_at": "2026-01-10T09:00:00Z",
"updated_at": "2026-01-14T15:30:00Z"
}
] /api/v1/workflows Create a new workflow.
{
"name": "Lead Scoring Pipeline",
"description": "Score and route inbound leads"
} {
"id": "wf_def456",
"name": "Lead Scoring Pipeline",
"status": "draft",
"created_at": "2026-01-15T12:00:00Z"
} /api/v1/workflows/{workflow_id} Update a workflow's name, description, or status.
{
"name": "Lead Scoring v2",
"status": "published"
} {
"id": "wf_def456",
"name": "Lead Scoring v2",
"status": "published",
"updated_at": "2026-01-15T14:00:00Z"
} /api/v1/workflows/{workflow_id} Delete a workflow and all its execution history.
curl -X DELETE https://stryda.ai/api/v1/workflows/wf_def456 \
-H "x-api-key: YOUR_KEY" { "deleted": true } /api/v1/workflows/{workflow_id}/run Trigger a workflow run. Optional input_data is passed to the Trigger node.
curl -X POST https://stryda.ai/api/v1/workflows/wf_abc123/run \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"input_data": {"prompt": "Analyze this email"}}' {
"input_data": {
"prompt": "Analyze this customer email and suggest a response"
}
} {
"run_id": "run_789",
"workflow_id": "wf_abc123",
"status": "running",
"started_at": "2026-01-15T12:00:00Z"
} Agents
/api/v1/agents List all agents.
[
{
"id": "agent_abc123",
"name": "Research Agent",
"model": "claude-opus-4-7",
"tools": ["web_search", "file_read", "slack_post"],
"status": "active",
"created_at": "2026-01-10T09:00:00Z"
}
] /api/v1/agents Create a new agent with tool access and scope.
{
"name": "Data Analyst",
"model": "claude-sonnet-4-6",
"system_prompt": "You are a data analyst with access to company databases.",
"tools": ["sql_query", "chart_create", "slack_post"],
"max_iterations": 10,
"budget_per_run": 0.50
} {
"id": "agent_def456",
"name": "Data Analyst",
"status": "active",
"created_at": "2026-01-15T12:00:00Z"
} /api/v1/agents/{agent_id}/run Trigger an agent run. The agent executes autonomously through the MCP pipeline using its configured tools.
curl -X POST https://stryda.ai/api/v1/agents/agent_abc123/run \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"input_data": {"task": "Analyze Q4 revenue trends"}}' {
"input_data": {
"task": "Analyze Q4 revenue trends and post a summary to #analytics"
}
} {
"run_id": "run_012",
"agent_id": "agent_abc123",
"status": "running",
"started_at": "2026-01-15T12:00:00Z"
} /api/v1/agents/{agent_id} Delete an agent.
{ "deleted": true } Chatbots
/api/v1/chatbots List all chatbots.
[
{
"id": "cb_abc123",
"name": "Support Bot",
"model": "claude-sonnet-4-6",
"embed_id": "emb_xyz",
"status": "deployed",
"created_at": "2026-01-10T09:00:00Z"
}
] /api/v1/chatbots Create a new chatbot.
{
"name": "Sales Assistant",
"model": "gpt-4.1",
"system_prompt": "You are a helpful sales assistant.",
"knowledge_base": ["kb_doc1", "kb_doc2"]
} {
"id": "cb_def456",
"name": "Sales Assistant",
"embed_id": "emb_abc",
"status": "draft",
"created_at": "2026-01-15T12:00:00Z"
} /api/embed/{embed_id}/chat Public Send a message to a deployed chatbot. No API key required for public chatbots.
curl -X POST https://stryda.ai/api/embed/emb_xyz/chat \
-H "Content-Type: application/json" \
-d '{"message": "How do I reset my password?", "session_id": "sess_user123"}' {
"message": "How do I reset my password?",
"session_id": "sess_user123"
} {
"response": "To reset your password, go to Settings > Security...",
"session_id": "sess_user123",
"tokens": 245,
"cost": 0.0008
} Embed via script tag
Paste into any HTML page to render the chat widget:
<script
src="https://stryda.ai/embed.js"
data-chatbot-id="YOUR_EMBED_ID"
async
></script> Runs
/api/v1/runs List execution runs across all workflows and agents. Supports filtering by status and workflow_id.
curl "https://stryda.ai/api/v1/runs?status=completed&limit=10" \
-H "x-api-key: YOUR_KEY" [
{
"run_id": "run_789",
"workflow_id": "wf_abc123",
"status": "completed",
"total_cost": 0.0847,
"started_at": "2026-01-15T12:00:00Z",
"completed_at": "2026-01-15T12:00:12Z"
}
] /api/v1/workflows/{workflow_id}/runs/{run_id} Get detailed information about a specific run, including per-node cost breakdown and every tool call in the MCP audit log.
{
"run_id": "run_789",
"workflow_id": "wf_abc123",
"status": "completed",
"total_cost": 0.0847,
"total_tokens": 15650,
"nodes": [
{ "node_id": "classify", "model": "gpt-4.1-mini", "status": "completed", "cost": 0.0006 },
{ "node_id": "analyze", "model": "claude-sonnet-4-6", "status": "completed", "cost": 0.0606 },
{ "node_id": "output", "status": "completed", "cost": 0 }
],
"mcp_calls": [
{ "tool": "comms.send_slack_message", "decision": "authorized", "cost": 0, "latency_ms": 184 }
],
"output": { "summary": "Customer reported login issue...", "priority": "high" },
"started_at": "2026-01-15T12:00:00Z",
"completed_at": "2026-01-15T12:00:12Z"
} Approvals
/api/v1/approvals/{id}/approve Approve a pending HITL gate. The same tool call payload re-runs with the approval on file.
curl -X POST https://stryda.ai/api/v1/approvals/appr_abc123/approve \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"comment": "Approved"}' {
"comment": "Looks good, approved for release.",
"edited_output": null
} {
"id": "appr_abc123",
"action": "approved",
"reviewer": "user_abc123",
"comment": "Looks good, approved for release.",
"approved_at": "2026-01-15T14:32:00Z"
} /api/v1/approvals/{id}/reject Reject a pending HITL gate. Execution stops or follows the configured fallback branch.
{
"comment": "Output contains inaccurate pricing. Please revise.",
"reason": "factual_error"
} {
"id": "appr_abc123",
"action": "rejected",
"reviewer": "user_abc123",
"comment": "Output contains inaccurate pricing. Please revise.",
"rejected_at": "2026-01-15T14:32:00Z"
} Budget
/api/v1/budget Get overall budget status and spending summary.
{
"monthly_cap": 200.00,
"monthly_spent": 47.23,
"monthly_remaining": 152.77,
"daily_spent": 3.12,
"alerts": [
{ "threshold_percent": 80, "channels": ["slack", "email"], "triggered": false }
]
} /api/v1/budget Update budget caps and alert thresholds.
{
"monthly_cap": 300.00,
"per_run_cap": 1.00,
"alerts": [
{ "threshold_percent": 75, "channels": ["slack"] },
{ "threshold_percent": 95, "channels": ["slack", "email"] }
]
} {
"monthly_cap": 300.00,
"per_run_cap": 1.00,
"updated_at": "2026-01-15T14:00:00Z"
} Tables
/api/v1/tables List all tables.
[
{
"id": "tbl_abc123",
"name": "Customer Leads",
"columns": ["name", "email", "score", "status"],
"row_count": 1247,
"created_at": "2026-01-10T09:00:00Z"
}
] /api/v1/tables Create a new table with column definitions.
{
"name": "Product Feedback",
"columns": [
{ "name": "customer", "type": "text" },
{ "name": "rating", "type": "number" },
{ "name": "feedback", "type": "text" },
{ "name": "category", "type": "select", "options": ["bug", "feature", "praise"] }
]
} {
"id": "tbl_def456",
"name": "Product Feedback",
"columns": ["customer", "rating", "feedback", "category"],
"row_count": 0,
"created_at": "2026-01-15T12:00:00Z"
} /api/v1/tables/{id}/rows Add a row to a table.
{
"data": {
"customer": "Jane Smith",
"rating": 5,
"feedback": "The workflow builder is incredibly intuitive",
"category": "praise"
}
} {
"id": "row_789",
"table_id": "tbl_def456",
"data": {
"customer": "Jane Smith",
"rating": 5,
"feedback": "The workflow builder is incredibly intuitive",
"category": "praise"
},
"created_at": "2026-01-15T12:30:00Z"
} /api/v1/tables/{id}/rows List rows in a table. Pagination via limit and offset query parameters.
curl "https://stryda.ai/api/v1/tables/tbl_abc123/rows?limit=50&offset=0" \
-H "x-api-key: YOUR_KEY" {
"rows": [
{ "id": "row_001", "data": { "name": "Acme Corp", "score": 85 } },
{ "id": "row_002", "data": { "name": "Globex", "score": 72 } }
],
"total": 1247,
"limit": 50,
"offset": 0
} /api/v1/tables/{id} Delete a table and all its rows.
{ "deleted": true } Forms
/api/v1/forms List all forms.
[
{
"id": "frm_abc123",
"name": "Contact Form",
"slug": "contact",
"submission_count": 342,
"linked_table": "tbl_abc123",
"status": "published",
"created_at": "2026-01-10T09:00:00Z"
}
] /api/v1/forms Create a new form.
{
"name": "Bug Report",
"slug": "bug-report",
"fields": [
{ "name": "title", "type": "text", "required": true },
{ "name": "description", "type": "textarea", "required": true },
{ "name": "severity", "type": "select", "options": ["low", "medium", "high", "critical"] }
],
"linked_table": "tbl_def456",
"trigger_workflow": "wf_abc123"
} {
"id": "frm_def456",
"name": "Bug Report",
"slug": "bug-report",
"public_url": "https://stryda.ai/f/bug-report",
"created_at": "2026-01-15T12:00:00Z"
} /api/v1/forms/{id}/submit Public Submit a form entry. Triggers any linked workflow and populates the linked table.
{
"data": {
"title": "Dashboard loading slowly",
"description": "The analytics dashboard takes 15 seconds to load",
"severity": "medium"
}
} {
"id": "sub_789",
"form_id": "frm_def456",
"status": "received",
"workflow_run_id": "run_012",
"created_at": "2026-01-15T12:30:00Z"
} Memory
/api/v1/memory List all memory entries.
curl https://stryda.ai/api/v1/memory \
-H "x-api-key: YOUR_KEY" [
{
"id": "mem_abc123",
"content": "User prefers concise responses",
"type": "user",
"tags": ["preferences"],
"created_at": "2026-01-10T09:00:00Z"
}
] /api/v1/memory Create a memory entry. Memories are injected into AI prompts for context-aware responses.
{
"content": "Customer Acme Corp renewed their enterprise contract for 3 years",
"type": "business",
"tags": ["customers", "contracts", "acme"]
} {
"id": "mem_def456",
"content": "Customer Acme Corp renewed their enterprise contract for 3 years",
"type": "business",
"tags": ["customers", "contracts", "acme"],
"created_at": "2026-01-15T12:00:00Z"
} /api/v1/memory/search Semantic search across memories using Pinecone.
{
"query": "What is Acme Corp's contract status?",
"top_k": 5
} {
"results": [
{
"id": "mem_def456",
"content": "Customer Acme Corp renewed their enterprise contract for 3 years",
"score": 0.94,
"tags": ["customers", "contracts", "acme"]
}
]
} /api/v1/memory/{id} Delete a memory entry.
{ "deleted": true } Integrations
/api/v1/integrations List all available integrations and their connection status.
curl https://stryda.ai/api/v1/integrations \
-H "x-api-key: YOUR_KEY" {
"total": 228,
"available": 5,
"coming_soon": 223,
"connected": 3,
"integrations": [
{
"id": "int_slack",
"name": "Slack",
"category": "Communication",
"connected": true,
"connected_at": "2026-01-05T10:00:00Z"
},
{
"id": "int_hubspot",
"name": "HubSpot",
"category": "CRM & Sales",
"connected": false
}
]
} Templates
/api/v1/templates List all available workflow templates.
[
{
"id": "tpl_support_triage",
"name": "Customer Support Triage",
"category": "support",
"node_count": 5,
"estimated_cost_per_run": 0.003,
"installs": 1247
}
] /api/v1/templates/{id}/instantiate Create a new workflow from a template. Override any node configuration during instantiation.
curl -X POST https://stryda.ai/api/v1/templates/tpl_support_triage/instantiate \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "My Custom Triage"}' {
"name": "My Custom Triage",
"overrides": {
"nodes": {
"draft_reply": {
"config": { "model": "claude-sonnet-4-6", "temperature": 0.7 }
}
},
"budget": { "per_run_cap": 0.25, "daily_cap": 15.00 }
}
} {
"workflow_id": "wf_new789",
"name": "My Custom Triage",
"template_id": "tpl_support_triage",
"status": "draft",
"created_at": "2026-01-15T12:00:00Z"
} Webhooks
/hooks/{slug} Public Trigger a workflow via webhook. The JSON body is passed as input_data. Supports HMAC-SHA256 signature verification.
curl -X POST https://stryda.ai/hooks/my-webhook-slug \
-H "Content-Type: application/json" \
-H "X-Stryda-Signature: sha256=abc123..." \
-d '{"event": "new_order", "customer": "[email protected]"}' {
"event": "new_order",
"customer": "[email protected]",
"total": 99.99
} { "status": "accepted", "run_id": "run_789" } Error responses
All errors return a consistent JSON shape with a detail field (or an
error object with code, message, and
details). Use the HTTP status code to determine the category.
{
"detail": "Validation error: 'name' is required and must be a non-empty string."
} {
"error": {
"code": "budget_exceeded",
"message": "Monthly budget cap of $200.00 has been reached",
"details": {
"monthly_spent": 200.12,
"monthly_cap": 200.00
}
}
} | Status | Code | Description |
|---|---|---|
400 | invalid_request | Missing or malformed request body |
401 | unauthorized | Missing or invalid API key or bearer token |
403 | forbidden | Key does not have access to this resource, or free plan without AI access |
404 | not_found | Resource does not exist or belongs to another user |
409 | conflict | Resource already exists or state conflict |
422 | validation_error | Request body failed schema validation |
429 | rate_limited | Too many requests — 60/min (API) or 30/min (embed) |
500 | internal_error | Unexpected server error — retry with exponential backoff |
503 | budget_exceeded | Budget cap reached, execution halted |
Common mistakes
SDK examples
No official SDK yet — here are idiomatic patterns for common languages.
import os, requests
API_KEY = os.environ["STRYDA_API_KEY"]
BASE = "https://stryda.ai/api/v1"
res = requests.post(
f"{BASE}/workflows/wf_abc123/run",
headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
json={"input_data": {"prompt": "Analyze this email"}},
)
run = res.json()
print(f"Run {run['run_id']} is {run['status']}") const API_KEY = process.env.STRYDA_API_KEY!;
const BASE = 'https://stryda.ai/api/v1';
const res = await fetch(`${BASE}/workflows/wf_abc123/run`, {
method: 'POST',
headers: {
'x-api-key': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
input_data: { prompt: 'Analyze this email' },
}),
});
const run = await res.json();
console.log(`Run ${run.run_id} is ${run.status}`); curl -sS -X POST https://mcp.stryda.ai/api/mcp \
-H "Authorization: Bearer ${MCP_BEARER}" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'