Skip to main content

Server routes

Server adapters register these routes when you call server.init(). All routes are prefixed with the prefix option if configured.

Agents
Direct link to Agents

MethodPathDescription
GET/api/agentsList all agents
GET/api/agents/:agentIdGet agent by ID (supports version query params)
POST/api/agents/:agentId/generateGenerate agent response
POST/api/agents/:agentId/streamStream agent response
POST/api/agents/:agentId/send-messageSend a user message to an active or idle thread
POST/api/agents/:agentId/queue-messageQueue a user message for the next thread turn
POST/api/agents/:agentId/signalsSend a lower-level signal to an active or idle thread
POST/api/agents/:agentId/threads/subscribeSubscribe to a thread stream
POST/api/agents/:agentId/send-tool-approvalApprove or decline a tool call and resume through a thread subscription
POST/api/agents/:agentId/resume-streamResume a suspended agent stream with custom data
GET/api/agents/:agentId/toolsList agent tools
POST/api/agents/:agentId/tools/:toolId/executeExecute agent tool

Get agent query parameters
Direct link to Get agent query parameters

GET /api/agents/:agentId accepts optional query parameters to control which stored config version is applied as overrides to code-defined agents:

ParameterTypeDefaultDescription
status'draft' | 'published''published'Which stored version to resolve. draft returns the latest version, and published returns the active version.
versionIdstringNoneA specific version ID to resolve. Takes precedence over status.
# Get agent with active published overrides (default)
GET /api/agents/my-agent

# Get agent with latest draft overrides
GET /api/agents/my-agent?status=draft

# Get agent with a specific version's overrides
GET /api/agents/my-agent?versionId=abc123

Generate request body
Direct link to Generate request body

{
messages: CoreMessage[] | string; // Required
instructions?: string; // System instructions
system?: string; // System prompt
context?: CoreMessage[]; // Additional context
memory?: { key: string } | boolean; // Memory config
resourceId?: string; // Resource identifier
threadId?: string; // Thread identifier
runId?: string; // Run identifier
maxSteps?: number; // Max tool steps
activeTools?: string[]; // Tools to enable
toolChoice?: ToolChoice; // Tool selection mode
requestContext?: Record<string, unknown>; // Request context
output?: ZodSchema; // Structured output schema
}

Generate response
Direct link to Generate response

{
text: string;
toolCalls?: ToolCall[];
finishReason: string;
usage?: {
promptTokens: number;
completionTokens: number;
};
}

Agent message routes
Direct link to Agent message routes

Use POST /api/agents/:agentId/send-message to send a user message to the active agent loop or wake an idle thread. Use POST /api/agents/:agentId/queue-message when the active run should finish before Mastra starts a follow-up run.

Both routes accept the same request body:

{
message: string | Array<TextPart | FilePart> | {
contents: string | Array<TextPart | FilePart>;
attributes?: Record<string, JSONValue>;
metadata?: Record<string, unknown>;
providerOptions?: ProviderMetadata;
};
runId?: string;
resourceId?: string;
threadId?: string;
ifActive?: {
behavior?: 'deliver' | 'persist' | 'discard';
attributes?: Record<string, string | number | boolean>;
};
ifIdle?: {
behavior?: 'wake' | 'persist' | 'discard';
streamOptions?: Omit<AgentExecutionOptions, 'messages'>;
attributes?: Record<string, string | number | boolean>;
};
}

When runId is omitted, resourceId and threadId are required. ifIdle only applies to thread-targeted requests, not run-targeted requests.

Send a message
Direct link to Send a message

curl -X POST http://localhost:4111/api/agents/supportAgent/send-message \
-H 'Content-Type: application/json' \
-d '{
"message": {
"contents": "Show the shorter version.",
"attributes": { "sentFrom": "web" }
},
"resourceId": "user_123",
"threadId": "thread_456"
}'

Queue a message
Direct link to Queue a message

curl -X POST http://localhost:4111/api/agents/supportAgent/queue-message \
-H 'Content-Type: application/json' \
-d '{
"message": "Also check whether the tests need updates.",
"resourceId": "user_123",
"threadId": "thread_456"
}'

Both routes return:

{
accepted: true;
runId: string;
signal?: CreatedAgentSignal;
}

Subscription tool approval routes
Direct link to Subscription tool approval routes

Use POST /api/agents/:agentId/send-tool-approval when the client already has an active thread subscription. The route resumes the run and returns a JSON acknowledgement. Resumed stream chunks are delivered through POST /api/agents/:agentId/threads/subscribe.

The route accepts this request body:

{
resourceId: string;
threadId: string;
toolCallId: string;
approved: boolean;
requestContext?: Record<string, unknown>;
}

The route returns:

{
accepted: true;
runId: string;
toolCallId?: string;
}

Workflows
Direct link to Workflows

MethodPathDescription
GET/api/workflowsList all workflows
GET/api/workflows/run-countsGet per-workflow counts of running and suspended runs
GET/api/workflows/:workflowIdGet workflow by ID
POST/api/workflows/:workflowId/create-runCreate a new workflow run
POST/api/workflows/:workflowId/start-asyncStart workflow and await result
POST/api/workflows/:workflowId/streamStream workflow execution
POST/api/workflows/:workflowId/resumeResume suspended workflow
POST/api/workflows/:workflowId/resume-asyncResume asynchronously
GET/api/workflows/:workflowId/runsList workflow runs
GET/api/workflows/:workflowId/runs/:runIdGet specific run

Run counts response
Direct link to Run counts response

The /api/workflows/run-counts endpoint returns counts of running and suspended runs for every registered workflow. The record is keyed by the workflow's registry key from the Mastra config, and the server may cache the response for a few seconds:

{
[workflowRegistryKey: string]: {
running: number;
suspended: number;
};
}

Dynamic workflows
Direct link to Dynamic workflows

Dynamic workflow definitions (beta) are workflows expressed as JSON, persisted through the workflowDefinitions storage domain, and live-registered on the running instance. See Dynamic workflows.

MethodPathDescription
GET/api/stored/workflowsList dynamic workflow definitions, filterable by status and authorId
GET/api/stored/workflows/:dynamicWorkflowIdGet a dynamic workflow definition by ID
POST/api/stored/workflowsUpsert a definition (plus optional helper dependencies) and live-register it
DELETE/api/stored/workflows/:dynamicWorkflowIdDelete a dynamic workflow definition and unregister the live workflow

On authenticated servers, the read routes require the stored-workflows:read permission and the write routes require stored-workflows:write. Registered dynamic workflows are executed through the ordinary /api/workflows/:workflowId routes above.

Create run request body
Direct link to Create run request body

{
resourceId?: string; // Associate run with a resource (e.g., user ID)
disableScorers?: boolean; // Disable scorers for this run
}

Request body for /start-async
Direct link to request-body-for-start-async

{
resourceId?: string; // Associate run with a resource (e.g., user ID)
inputData?: unknown;
initialState?: unknown;
requestContext?: Record<string, unknown>;
tracingOptions?: {
spanName?: string;
attributes?: Record<string, unknown>;
};
}

Stream workflow request body
Direct link to Stream workflow request body

{
resourceId?: string; // Associate run with a resource (e.g., user ID)
inputData?: unknown;
initialState?: unknown;
requestContext?: Record<string, unknown>;
closeOnSuspend?: boolean;
}

Resume request body
Direct link to Resume request body

{
step?: string | string[];
resumeData?: unknown;
requestContext?: Record<string, unknown>;
}

Tools
Direct link to Tools

MethodPathDescription
GET/api/toolsList all tools
GET/api/tools/:toolIdGet tool by ID
POST/api/tools/:toolId/executeExecute tool

Execute tool request body
Direct link to Execute tool request body

{
data: unknown; // Tool input data
requestContext?: Record<string, unknown>;
}

Memory
Direct link to Memory

MethodPathDescription
GET/api/memory/threadsList threads
GET/api/memory/threads/:threadIdGet thread
POST/api/memory/threadsCreate thread
DELETE/api/memory/threads/:threadIdDelete thread
POST/api/memory/threads/:threadId/cloneClone thread
GET/api/memory/threads/:threadId/messagesGet thread messages
POST/api/memory/threads/:threadId/messagesAdd message

Create thread request body
Direct link to Create thread request body

{
resourceId: string;
title?: string;
metadata?: Record<string, unknown>;
}

Clone thread request body
Direct link to Clone thread request body

{
newThreadId?: string; // Custom ID for cloned thread
resourceId?: string; // Override resource ID
title?: string; // Custom title for clone
metadata?: Record<string, unknown>; // Additional metadata
options?: {
messageLimit?: number; // Max messages to clone
messageFilter?: {
startDate?: Date; // Clone messages after this date
endDate?: Date; // Clone messages before this date
messageIds?: string[]; // Clone specific messages
};
};
}

Clone thread response
Direct link to Clone thread response

{
thread: {
id: string;
resourceId: string;
title: string;
createdAt: Date;
updatedAt: Date;
metadata: {
clone: {
sourceThreadId: string;
clonedAt: Date;
lastMessageId?: string;
};
// ... other metadata
};
};
clonedMessages: MastraDBMessage[];
}

Vectors
Direct link to Vectors

MethodPathDescription
POST/api/vectors/:vectorName/upsertUpsert vectors
POST/api/vectors/:vectorName/queryQuery vectors
POST/api/vectors/:vectorName/deleteDelete vectors

Upsert request body
Direct link to Upsert request body

{
vectors: Array<{
id: string
values: number[]
metadata?: Record<string, unknown>
}>
}

Query request body
Direct link to Query request body

{
vector: number[];
topK?: number;
filter?: Record<string, unknown>;
includeMetadata?: boolean;
}

Datasets and experiments
Direct link to Datasets and experiments

MethodPathDescription
GET/api/datasetsList datasets
POST/api/datasetsCreate a dataset
GET/api/datasets/:datasetIdGet dataset by ID
PATCH/api/datasets/:datasetIdUpdate a dataset
DELETE/api/datasets/:datasetIdDelete a dataset
GET/api/datasets/:datasetId/itemsList dataset items
POST/api/datasets/:datasetId/itemsAdd a dataset item
GET/api/experimentsList experiments across datasets
GET/api/datasets/:datasetId/experimentsList experiments for a dataset
POST/api/datasets/:datasetId/experimentsTrigger an experiment, or create one without starting it (start: false)
POST/api/datasets/:datasetId/experiments/:experimentId/items/:itemId/runExecute one experiment item server-side
POST/api/datasets/:datasetId/experiments/:experimentId/resultsSubmit an externally computed item result
POST/api/datasets/:datasetId/experiments/:experimentId/finalizeFinalize a caller-driven experiment
GET/api/datasets/:datasetId/experiments/:experimentIdGet experiment by ID
GET/api/datasets/:datasetId/experiments/:experimentId/resultsList experiment results
POST/api/datasets/:datasetId/compareCompare two experiments

Caller-driven experiment routes
Direct link to Caller-driven experiment routes

Use these routes when your own orchestrator (for example a Temporal workflow) owns the experiment loop and Mastra acts as the system of record. Item runs, result submission, and finalization are safe to retry. Creation is safe to retry only when the request includes a caller-supplied id; without one, each retry creates a new experiment. Item runs and result submissions upsert on (experimentId, itemId, attempt). Finalize returns the stored record if the experiment is already completed.

Create experiment request body
Direct link to Create experiment request body

Post to /api/datasets/:datasetId/experiments with start: false to create the experiment without running it. Include targetType and targetId when Mastra should execute items via the run-item route. Omit both for pure ingestion via the results route.

{
start?: boolean; // false creates the experiment without running it. Defaults to true.
id?: string; // Caller-supplied experiment id (e.g. a workflow run id) for idempotent creates
targetType?: 'agent' | 'workflow' | 'scorer'; // Provide with targetId, or omit both
targetId?: string;
scorerIds?: string[]; // Run-level scorer ids, resolved server-side. Requires a target when start is false.
name?: string;
description?: string;
metadata?: Record<string, unknown>;
version?: number; // Pin to a specific dataset version (defaults to latest)
provenance?: {
source?: string;
sourceId?: string;
sourceVersion?: string;
metadata?: Record<string, unknown>;
};
grouping?: { // Stable grouping dimensions for comparisons and repeated trials
experimentSetId?: string;
comparisonId?: string;
variantId?: string;
trialIndex?: number;
};
}

Returns { experimentId, status, totalItems, datasetVersion } when start is false.

Run experiment item request body
Direct link to Run experiment item request body

POST /api/datasets/:datasetId/experiments/:experimentId/items/:itemId/run executes the experiment's target against one item and runs the resolved scorers, then upserts the result. Requires an experiment created with a target.

{
attempt?: number; // Zero-based repetition index. Defaults to 0.
requestContext?: Record<string, unknown>; // Merged with the item's own request context (item wins)
}

Returns { result, scores } with the persisted result row and the scores produced for the item.

Submit experiment result request body
Direct link to Submit experiment result request body

{
itemId: string; // Dataset item this result belongs to
attempt?: number; // Zero-based repetition index. Defaults to 0.
input?: unknown; // Defaults to the dataset item input
output?: unknown; // Output produced by the external runner
groundTruth?: unknown; // Defaults to the dataset item groundTruth
error?: { // Failure info when the item run failed
message: string;
stack?: string;
code?: string;
} | null;
startedAt?: string; // ISO date
completedAt?: string; // ISO date
traceId?: string;
scores?: Array<{ // Externally computed scores, persisted keyed by runId = experimentId
scorerId: string;
scorerName?: string;
score: number;
reason?: string;
metadata?: Record<string, unknown>;
}>;
}

Returns the persisted experiment result row.

Finalize experiment
Direct link to Finalize experiment

POST /api/datasets/:datasetId/experiments/:experimentId/finalize takes no body. The server computes per-item counts from the persisted result rows and marks the experiment completed: succeededCount (at least one attempt without an error), failedCount (every attempt errored), and skippedCount (never submitted). Returns the updated experiment record.

Caller-driven experiment error responses
Direct link to Caller-driven experiment error responses

StatusCondition
400Result submitted to an experiment that has a target (EXPERIMENT_HAS_TARGET), item run requested on a target-less experiment (EXPERIMENT_HAS_NO_TARGET), targetType and targetId weren't provided together (EXPERIMENT_INVALID_TARGET), or the dataset has no items at the pinned version (EXPERIMENT_NO_ITEMS)
404Dataset, experiment, dataset item, or target not found (EXPERIMENT_TARGET_NOT_FOUND)
409Caller-supplied experiment id already exists for a different dataset or target (EXPERIMENT_ID_CONFLICT), or a call arrived after finalization (EXPERIMENT_ALREADY_FINALIZED)

MCP
Direct link to MCP

MethodPathDescription
GET/api/mcp/serversList MCP servers
GET/api/mcp/servers/:serverId/toolsList server tools
POST/api/mcp/:serverIdMCP HTTP transport
GET/api/mcp/:serverId/sseMCP SSE transport

Responses API
Direct link to Responses API

MethodPathDescription
POST/api/v1/responsesCreate a response through the OpenAI-compatible Responses API route
GET/api/v1/responses/:responseIdRetrieve a stored response
DELETE/api/v1/responses/:responseIdDelete a stored response

For the full request and response contract, see the Responses API reference.

Conversations API
Direct link to Conversations API

MethodPathDescription
POST/api/v1/conversationsCreate a conversation
GET/api/v1/conversations/:conversationIdRetrieve a conversation
DELETE/api/v1/conversations/:conversationIdDelete a conversation
GET/api/v1/conversations/:conversationId/itemsList stored items for a conversation

For the full request and response contract, see the Conversations API reference.

Logs
Direct link to Logs

MethodPathDescription
GET/api/logsList logs
GET/api/logs/:runIdGet logs by run ID

Query parameters
Direct link to Query parameters

{
page?: number;
perPage?: number;
transportId?: string;
}

Telemetry
Direct link to Telemetry

MethodPathDescription
GET/api/telemetry/tracesList traces
GET/api/telemetry/traces/:traceIdGet trace
GET/api/telemetry/traces/:traceId/spansGet trace spans

Common query parameters
Direct link to Common query parameters

Pagination
Direct link to Pagination

Most list endpoints support:

{
page?: number; // Page number (0-indexed)
perPage?: number; // Items per page (default: 10)
}

Filtering
Direct link to Filtering

Workflow runs support:

{
fromDate?: string; // ISO date string
toDate?: string; // ISO date string
status?: string; // Run status filter
resourceId?: string; // Filter by resource
}

Error responses
Direct link to Error responses

All routes return errors in this format:

{
error: string; // Error message
details?: unknown; // Additional details
}

Common status codes:

CodeMeaning
400Bad Request - Invalid parameters
401Unauthorized - Missing/invalid auth
403Forbidden - Insufficient permissions
404Not Found - Resource doesn't exist
500Internal Server Error