> Discover all available pages from the documentation index: https://mastra.ai/llms.txt

# Server routes

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

## Agents

| Method | Path                                         | Description                                                             |
| ------ | -------------------------------------------- | ----------------------------------------------------------------------- |
| `GET`  | `/api/agents`                                | List all agents                                                         |
| `GET`  | `/api/agents/:agentId`                       | Get agent by ID (supports version query params)                         |
| `POST` | `/api/agents/:agentId/generate`              | Generate agent response                                                 |
| `POST` | `/api/agents/:agentId/stream`                | Stream agent response                                                   |
| `POST` | `/api/agents/:agentId/send-message`          | Send a user message to an active or idle thread                         |
| `POST` | `/api/agents/:agentId/queue-message`         | Queue a user message for the next thread turn                           |
| `POST` | `/api/agents/:agentId/signals`               | Send a lower-level signal to an active or idle thread                   |
| `POST` | `/api/agents/:agentId/threads/subscribe`     | Subscribe to a thread stream                                            |
| `POST` | `/api/agents/:agentId/send-tool-approval`    | Approve or decline a tool call and resume through a thread subscription |
| `POST` | `/api/agents/:agentId/resume-stream`         | Resume a suspended agent stream with custom data                        |
| `GET`  | `/api/agents/:agentId/tools`                 | List agent tools                                                        |
| `POST` | `/api/agents/:agentId/tools/:toolId/execute` | Execute agent tool                                                      |

### 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:

| Parameter   | Type                     | Default       | Description                                                                                                      |
| ----------- | ------------------------ | ------------- | ---------------------------------------------------------------------------------------------------------------- |
| `status`    | `'draft' \| 'published'` | `'published'` | Which stored version to resolve. `draft` returns the latest version, and `published` returns the active version. |
| `versionId` | `string`                 | None          | A specific version ID to resolve. Takes precedence over `status`.                                                |

```bash
# 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

```typescript
{
  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

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

### 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:

```typescript
{
  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

```bash
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

```bash
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:

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

### 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:

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

The route returns:

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

## Workflows

| Method | Path                                      | Description                                           |
| ------ | ----------------------------------------- | ----------------------------------------------------- |
| `GET`  | `/api/workflows`                          | List all workflows                                    |
| `GET`  | `/api/workflows/run-counts`               | Get per-workflow counts of running and suspended runs |
| `GET`  | `/api/workflows/:workflowId`              | Get workflow by ID                                    |
| `POST` | `/api/workflows/:workflowId/create-run`   | Create a new workflow run                             |
| `POST` | `/api/workflows/:workflowId/start-async`  | Start workflow and await result                       |
| `POST` | `/api/workflows/:workflowId/stream`       | Stream workflow execution                             |
| `POST` | `/api/workflows/:workflowId/resume`       | Resume suspended workflow                             |
| `POST` | `/api/workflows/:workflowId/resume-async` | Resume asynchronously                                 |
| `GET`  | `/api/workflows/:workflowId/runs`         | List workflow runs                                    |
| `GET`  | `/api/workflows/:workflowId/runs/:runId`  | Get specific run                                      |

### Run counts response

The `/api/workflows/run-counts` endpoint returns counts of `running` and [`suspended`](https://mastra.ai/docs/workflows/suspend-and-resume) 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:

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

### 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](https://mastra.ai/docs/workflows/dynamic-workflows).

| Method   | Path                                       | Description                                                                    |
| -------- | ------------------------------------------ | ------------------------------------------------------------------------------ |
| `GET`    | `/api/stored/workflows`                    | List dynamic workflow definitions, filterable by `status` and `authorId`       |
| `GET`    | `/api/stored/workflows/:dynamicWorkflowId` | Get a dynamic workflow definition by ID                                        |
| `POST`   | `/api/stored/workflows`                    | Upsert a definition (plus optional helper `dependencies`) and live-register it |
| `DELETE` | `/api/stored/workflows/:dynamicWorkflowId` | Delete 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

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

### Request body for `/start-async`

```typescript
{
  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

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

### Resume request body

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

## Tools

| Method | Path                         | Description    |
| ------ | ---------------------------- | -------------- |
| `GET`  | `/api/tools`                 | List all tools |
| `GET`  | `/api/tools/:toolId`         | Get tool by ID |
| `POST` | `/api/tools/:toolId/execute` | Execute tool   |

### Execute tool request body

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

## Memory

| Method   | Path                                     | Description         |
| -------- | ---------------------------------------- | ------------------- |
| `GET`    | `/api/memory/threads`                    | List threads        |
| `GET`    | `/api/memory/threads/:threadId`          | Get thread          |
| `POST`   | `/api/memory/threads`                    | Create thread       |
| `DELETE` | `/api/memory/threads/:threadId`          | Delete thread       |
| `POST`   | `/api/memory/threads/:threadId/clone`    | Clone thread        |
| `GET`    | `/api/memory/threads/:threadId/messages` | Get thread messages |
| `POST`   | `/api/memory/threads/:threadId/messages` | Add message         |

### Create thread request body

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

### Clone thread request body

```typescript
{
  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

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

## Vectors

| Method | Path                              | Description    |
| ------ | --------------------------------- | -------------- |
| `POST` | `/api/vectors/:vectorName/upsert` | Upsert vectors |
| `POST` | `/api/vectors/:vectorName/query`  | Query vectors  |
| `POST` | `/api/vectors/:vectorName/delete` | Delete vectors |

### Upsert request body

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

### Query request body

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

## Datasets and experiments

| Method   | Path                                                                   | Description                                                               |
| -------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `GET`    | `/api/datasets`                                                        | List datasets                                                             |
| `POST`   | `/api/datasets`                                                        | Create a dataset                                                          |
| `GET`    | `/api/datasets/:datasetId`                                             | Get dataset by ID                                                         |
| `PATCH`  | `/api/datasets/:datasetId`                                             | Update a dataset                                                          |
| `DELETE` | `/api/datasets/:datasetId`                                             | Delete a dataset                                                          |
| `GET`    | `/api/datasets/:datasetId/items`                                       | List dataset items                                                        |
| `POST`   | `/api/datasets/:datasetId/items`                                       | Add a dataset item                                                        |
| `GET`    | `/api/experiments`                                                     | List experiments across datasets                                          |
| `GET`    | `/api/datasets/:datasetId/experiments`                                 | List experiments for a dataset                                            |
| `POST`   | `/api/datasets/:datasetId/experiments`                                 | Trigger an experiment, or create one without starting it (`start: false`) |
| `POST`   | `/api/datasets/:datasetId/experiments/:experimentId/items/:itemId/run` | Execute one experiment item server-side                                   |
| `POST`   | `/api/datasets/:datasetId/experiments/:experimentId/results`           | Submit an externally computed item result                                 |
| `POST`   | `/api/datasets/:datasetId/experiments/:experimentId/finalize`          | Finalize a caller-driven experiment                                       |
| `GET`    | `/api/datasets/:datasetId/experiments/:experimentId`                   | Get experiment by ID                                                      |
| `GET`    | `/api/datasets/:datasetId/experiments/:experimentId/results`           | List experiment results                                                   |
| `POST`   | `/api/datasets/:datasetId/compare`                                     | Compare two experiments                                                   |

### 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

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.

```typescript
{
  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

`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.

```typescript
{
  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

```typescript
{
  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

`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

| Status | Condition                                                                                                                                                                                                                                                                                                                  |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Result 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`) |
| `404`  | Dataset, experiment, dataset item, or target not found (`EXPERIMENT_TARGET_NOT_FOUND`)                                                                                                                                                                                                                                     |
| `409`  | Caller-supplied experiment `id` already exists for a different dataset or target (`EXPERIMENT_ID_CONFLICT`), or a call arrived after finalization (`EXPERIMENT_ALREADY_FINALIZED`)                                                                                                                                         |

## MCP

| Method | Path                               | Description        |
| ------ | ---------------------------------- | ------------------ |
| `GET`  | `/api/mcp/servers`                 | List MCP servers   |
| `GET`  | `/api/mcp/servers/:serverId/tools` | List server tools  |
| `POST` | `/api/mcp/:serverId`               | MCP HTTP transport |
| `GET`  | `/api/mcp/:serverId/sse`           | MCP SSE transport  |

## Responses API

| Method   | Path                            | Description                                                         |
| -------- | ------------------------------- | ------------------------------------------------------------------- |
| `POST`   | `/api/v1/responses`             | Create a response through the OpenAI-compatible Responses API route |
| `GET`    | `/api/v1/responses/:responseId` | Retrieve a stored response                                          |
| `DELETE` | `/api/v1/responses/:responseId` | Delete a stored response                                            |

For the full request and response contract, see the [Responses API reference](https://mastra.ai/reference/client-js/responses).

## Conversations API

| Method   | Path                                          | Description                          |
| -------- | --------------------------------------------- | ------------------------------------ |
| `POST`   | `/api/v1/conversations`                       | Create a conversation                |
| `GET`    | `/api/v1/conversations/:conversationId`       | Retrieve a conversation              |
| `DELETE` | `/api/v1/conversations/:conversationId`       | Delete a conversation                |
| `GET`    | `/api/v1/conversations/:conversationId/items` | List stored items for a conversation |

For the full request and response contract, see the [Conversations API reference](https://mastra.ai/reference/client-js/conversations).

## Logs

| Method | Path               | Description        |
| ------ | ------------------ | ------------------ |
| `GET`  | `/api/logs`        | List logs          |
| `GET`  | `/api/logs/:runId` | Get logs by run ID |

### Query parameters

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

## Telemetry

| Method | Path                                   | Description     |
| ------ | -------------------------------------- | --------------- |
| `GET`  | `/api/telemetry/traces`                | List traces     |
| `GET`  | `/api/telemetry/traces/:traceId`       | Get trace       |
| `GET`  | `/api/telemetry/traces/:traceId/spans` | Get trace spans |

## Common query parameters

### Pagination

Most list endpoints support:

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

### Filtering

Workflow runs support:

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

## Error responses

All routes return errors in this format:

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

Common status codes:

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

## Related

- [createRoute()](https://mastra.ai/reference/server/create-route): Creating custom routes
- [Server Adapters](https://mastra.ai/docs/server/server-adapters): Using adapters