Endpoints
m8tes is the hosted agent platform: agents are API resources with per-user isolation (user_id), memory, scheduling, approvals, and 190+ integrations built in.
Base URL: https://api.m8tes.ai/api/v2
Machine-readable schema: GET https://api.m8tes.ai/api/v2/openapi.json (V2 routes only; no auth).
All requests require an API key in the Authorization header:
Authorization: Bearer m8_your_key_here
Signup
Create an account and get an API key. No authentication required. See the Quick Start for the Python equivalent (m8tes.signup()). Runs are prepaid: a new API account includes $1 test credit on deepseek-v4-1-flash. For other models or more runs, top up or connect a model subscription — a run with no balance fails with TOKEN_BALANCE_DEPLETED and a topup_url. Email verification is separate: once you can run, you can complete up to 25 runs before verifying (not free credit).
Signup
POST /signup
curl \
-X POST \
https://api.m8tes.ai/api/v2/signup \
-H "Content-Type: application/json" \
-d '{"email": "founder@acme.com","first_name": "Sam","product": "platform"}'Token
Mint or rotate your API key. Rotating invalidates the previous key immediately.
Get Token
POST /token
curl \
-X POST \
https://api.m8tes.ai/api/v2/token \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com","password": "your-password"}'Verify
Email verification is separate. Once you can run (test credit, top-up, or own-subscription OAuth), you can complete up to 25 runs before verifying; after that, runs fail with EMAIL_VERIFICATION_REQUIRED until the emailed link is clicked. Poll status to learn when that happened.
Resend Verify
POST /verify/resend
curl \
-X POST \
https://api.m8tes.ai/api/v2/verify/resend \
-H "Authorization: Bearer m8_your_key_here"Verify Status
GET /verify/status
curl \
https://api.m8tes.ai/api/v2/verify/status \
-H "Authorization: Bearer m8_your_key_here"Agents
Agents are reusable personas with instructions and tools. Coding: bind repositories under /agents/{id}/repos after connecting GitHub App.
Create Agent
POST /agents
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support bot","instructions": "Handle tickets","tools": ["gmail"]}'Response 201 Created
{
"id": 1,
"name": "support bot",
"instructions": "Handle tickets",
"tools": [
"gmail"
],
"default_permission_mode": "autonomous",
"inbound_imessage_enabled": false,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}List Agents
GET /agents
curl \
https://api.m8tes.ai/api/v2/agents?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"All list endpoints return a paginated envelope:
{
"data": [...],
"has_more": true
}Use starting_after with the last item's ID to fetch the next page.
Get Agent
GET /agents/{agent_id}
curl \
https://api.m8tes.ai/api/v2/agents/1 \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 1,
"name": "support bot",
"instructions": "Handle tickets",
"tools": [
"gmail"
],
"default_permission_mode": "autonomous",
"inbound_imessage_enabled": false,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Update Agent
PATCH /agents/{agent_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/agents/1 \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "renamed bot","tools": ["gmail","slack"]}'Response 200 OK
{
"id": 1,
"name": "support bot",
"instructions": "Handle tickets",
"tools": [
"gmail"
],
"default_permission_mode": "autonomous",
"inbound_imessage_enabled": false,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Delete Agent
Soft-deletes (archives) the agent. Returns 204 No Content.
DELETE /agents/{agent_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1 \
-H "Authorization: Bearer m8_your_key_here"Disable Agent
POST /agents/{agent_id}/disable
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/disable \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 1,
"name": "support bot",
"instructions": "Handle tickets",
"tools": [
"gmail"
],
"default_permission_mode": "autonomous",
"inbound_imessage_enabled": false,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Enable Email Inbox
POST /agents/{agent_id}/email-inbox
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/email-inbox \
-H "Authorization: Bearer m8_your_key_here"Enable Agent
POST /agents/{agent_id}/enable
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/enable \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 1,
"name": "support bot",
"instructions": "Handle tickets",
"tools": [
"gmail"
],
"default_permission_mode": "autonomous",
"inbound_imessage_enabled": false,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Enable Fetchmail
POST /agents/{agent_id}/fetchmail
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/fetchmail \
-H "Authorization: Bearer m8_your_key_here"Configure Agent Repo
POST /agents/{agent_id}/repos
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/repos \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"repo_full_name": "..."}'Reset Agent Overrides
POST /agents/{agent_id}/reset
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/reset \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"fields": ["instructions"]}'Create Slack Channel
POST /agents/{agent_id}/slack-channel
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/slack-channel \
-H "Authorization: Bearer m8_your_key_here"Unarchive Agent
POST /agents/{agent_id}/unarchive
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/unarchive \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 1,
"name": "support bot",
"status": "disabled",
"created_at": "2026-01-15T10:00:00Z"
}List Agent Documents
GET /agents/{agent_id}/documents
curl \
https://api.m8tes.ai/api/v2/agents/1/documents \
-H "Authorization: Bearer m8_your_key_here"List Agent Repos
GET /agents/{agent_id}/repos
curl \
https://api.m8tes.ai/api/v2/agents/1/repos \
-H "Authorization: Bearer m8_your_key_here"Get Agent System Prompt
GET /agents/{agent_id}/system-prompt
curl \
https://api.m8tes.ai/api/v2/agents/1/system-prompt \
-H "Authorization: Bearer m8_your_key_here"Set Agent Webhook Enabled
PATCH /agents/{agent_id}/webhook
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/agents/1/webhook \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'Disable Email Inbox
DELETE /agents/{agent_id}/email-inbox
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1/email-inbox \
-H "Authorization: Bearer m8_your_key_here"Disable Fetchmail
DELETE /agents/{agent_id}/fetchmail
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1/fetchmail \
-H "Authorization: Bearer m8_your_key_here"Read Agent Document
GET /agents/{agent_id}/documents/{name}
curl \
https://api.m8tes.ai/api/v2/agents/1/documents/{name} \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 3,
"name": "latest-report",
"summary": "Weekly PPC report",
"mime_type": "text/markdown",
"size_bytes": 2048,
"source": "agent",
"source_run_id": 42,
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-01-22T10:00:00Z"
}Remove Agent Repo
DELETE /agents/{agent_id}/repos/{repo_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id} \
-H "Authorization: Bearer m8_your_key_here"Approve Agent Repo Commands
POST /agents/{agent_id}/repos/{repo_id}/approve-commands
curl \
-X POST \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id}/approve-commands \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"commands_digest": "..."}'Get Agent Repo Env
GET /agents/{agent_id}/repos/{repo_id}/env
curl \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id}/env \
-H "Authorization: Bearer m8_your_key_here"Set Agent Repo Env
PUT /agents/{agent_id}/repos/{repo_id}/env
curl \
-X PUT \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id}/env \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"env": {}}'Clear Agent Repo Commands
DELETE /agents/{agent_id}/repos/{repo_id}/commands
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id}/commands \
-H "Authorization: Bearer m8_your_key_here"Delete Agent Repo Env Key
DELETE /agents/{agent_id}/repos/{repo_id}/env/{key}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/agents/1/repos/{repo_id}/env/{key} \
-H "Authorization: Bearer m8_your_key_here"Agent-Templates
Pre-built agent templates (e.g. ppc-manager). Enable one with agents.create(from_template=...); improvements we ship flow through automatically until you customize a field.
List Agent Templates
GET /agent-templates
curl \
https://api.m8tes.ai/api/v2/agent-templatesResponse 200 OK
{
"data": [
{
"slug": "ppc-manager",
"name": "Google Ads",
"description": "Watches your Google Ads every week. Catches wasted spend.",
"logo_ref": "google-ads",
"required_integrations": [
"google_ads"
],
"role": "Paid search",
"goals": "Reduce wasted spend, improve CTR.",
"default_tasks": [],
"bootstrap_tasks": [],
"questions": []
}
],
"has_more": false
}Models
The model catalog: ids, pricing, ZDR coverage, and reasoning-effort caps for every model an agent or run can use. The default: true flag reflects what your account's runs use when no model is set.
List Models
GET /models
curl \
https://api.m8tes.ai/api/v2/models \
-H "Authorization: Bearer m8_your_key_here"Model-Connections
List account-level Claude connection status and manage native OpenAI/Codex, Grok/xAI, or Gemini authorization. Provider credentials are captured automatically, encrypted at rest, and never returned.
List Model Connections
GET /model-connections
curl \
https://api.m8tes.ai/api/v2/model-connections \
-H "Authorization: Bearer m8_your_key_here"Clear Model Connection Default
DELETE /model-connections/preferred-default
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/model-connections/preferred-default \
-H "Authorization: Bearer m8_your_key_here"Disconnect Model Connection
DELETE /model-connections/{provider}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/model-connections/{provider} \
-H "Authorization: Bearer m8_your_key_here"Paste Claude Connection
POST /model-connections/claude/paste
curl \
-X POST \
https://api.m8tes.ai/api/v2/model-connections/claude/paste \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"access_token": "..."}'Apply Model Connection Default
POST /model-connections/{provider}/apply-default
curl \
-X POST \
https://api.m8tes.ai/api/v2/model-connections/{provider}/apply-default \
-H "Authorization: Bearer m8_your_key_here"Start Model Connection Authorization
POST /model-connections/{provider}/authorizations
curl \
-X POST \
https://api.m8tes.ai/api/v2/model-connections/{provider}/authorizations \
-H "Authorization: Bearer m8_your_key_here"Update Provider Default Model
PATCH /model-connections/{provider}/default-model
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/model-connections/{provider}/default-model \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"model": "..."}'Complete Model Connection Authorization
POST /model-connections/{provider}/authorizations/{state}
curl \
-X POST \
https://api.m8tes.ai/api/v2/model-connections/{provider}/authorizations/{state} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"code": "..."}'Poll Model Connection Authorization
GET /model-connections/{provider}/authorizations/{state}
curl \
https://api.m8tes.ai/api/v2/model-connections/{provider}/authorizations/{state} \
-H "Authorization: Bearer m8_your_key_here"Disconnect Model Connection Account
DELETE /model-connections/{provider}/accounts/{account_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/model-connections/{provider}/accounts/{account_id} \
-H "Authorization: Bearer m8_your_key_here"Cancel Model Connection Authorization
DELETE /model-connections/{provider}/authorizations/{state}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/model-connections/{provider}/authorizations/{state} \
-H "Authorization: Bearer m8_your_key_here"Runs
Runs are task executions. They stream Server-Sent Events by default.
Create Run
POST /runs
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"teammate_id": 1,"message": "Close open tickets","stream": false}'Streaming response: Server-Sent Events: raw flat Claude-native frames (the SDK normalizes these into text-delta, tool-call-start, tool-result-end):
data: {"type": "content_block_delta", "id": "block_1", "delta": {"type": "text_delta", "text": "Hello"}}
data: {"type": "tool_use", "id": "tc_1", "name": "gmail_send", "input": {"to": "a@b.com"}}
data: {"type": "tool_result", "tool_use_id": "tc_1", "content": "...", "result": "..."}
data: {"type": "done", "completion_state": "complete", "stop_reason": "end_turn", "message_count": 2}
Non-streaming response 200 OK:
{
"id": 42,
"teammate_id": 1,
"status": "running",
"output": null,
"user_id": "customer_123",
"metadata": null,
"created_at": "2026-01-15T10:05:00Z"
}Polling: Non-streaming runs return immediately with
status: "running". PollGET /runs/{id}every 2 seconds untilstatusiscompleted,failed, orcancelled.
Defaults: If
permission_modeis omitted, the run inherits the agent's saved default. Ifhuman_in_the_loopis omitted, inheritedapprovalandplanruns automatically enable it.
Validation: Explicitly setting
human_in_the_loop=falseis only valid withpermission_mode="autonomous".
Internal tools:
task_setup_tools=trueby default. Set it tofalsewhen you do not want the agent to receive the internal same-scope management tools for agents, tasks, runs, approvals, files, memories, schedules, inboxes, webhooks, and app connections during this run.
End-user scope: when you target an existing scoped agent, the
user_idin the request must match that agent's scope. If omitted, the run inherits the agent's existing scope.
Quick start: omit teammate_id and provide name to auto-create an agent:
with client.runs.create(
message="Draft release notes",
name="Release Bot",
instructions="Write concise release notes"
) as stream:
for event in stream:
if event.type == "text-delta":
print(event.delta, end="", flush=True)
print(stream.text)Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}List Runs
GET /runs
curl \
https://api.m8tes.ai/api/v2/runs?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Create First Session Run
POST /runs/first-session
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/first-session \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"teammate_id": 1}'Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Create Run With Files
Multipart form-data: the payload field carries the exact POST /runs JSON body; files carries the attachments.
curl -X POST https://api.m8tes.ai/api/v2/runs/with-files \\
-H "Authorization: Bearer m8_your_key_here" \\
-F 'payload={"teammate_id": 1, "message": "Summarize this", "stream": false}' \\
-F 'files=@report.pdf'POST /runs/with-files
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/with-files \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Get Run Activity
GET /runs/activity
curl \
https://api.m8tes.ai/api/v2/runs/activity?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Check Run Freshness
GET /runs/check
curl \
https://api.m8tes.ai/api/v2/runs/check?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Needs You
GET /runs/needs-you
curl \
https://api.m8tes.ai/api/v2/runs/needs-you?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Run
GET /runs/{run_id}
curl \
https://api.m8tes.ai/api/v2/runs/42 \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Answer Question
POST /runs/{run_id}/answer
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/answer \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"answers": {"What priority?": "High"},"request_id": "req_abc123"}'Use this for AskUserQuestion responses.
- If the run is
running, the answer is stored and picked up by the active run. - If the run is
awaiting_approval, the answer resumes execution. - If the run is terminal (
completed/failed/cancelled), the API returns409.
Plan mode approvals use this endpoint with {"Plan Approval": "Approve"}.
Approve Permission
POST /runs/{run_id}/approve
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/approve \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"request_id": "req_abc123","decision": "allow","remember": true}'Response status: after approval this returns a resolved status (
allowedordenied), notpending. The response'sresumedandrememberedfields report what actually happened: whether a paused run restarted, and whether an always-allow policy persisted.
Remember behavior:
remember=trueapplies to subsequent matching requests during the current run, and withdecision=allowit also stores a persistent cross-run always-allow policy (the same onePOST /permissionsmanages; use that endpoint to pre-configure or revoke). Checkrememberedin the response: the backend refuses to store a policy it would never consult (e.g. strict human-decision tools).
Response 200 OK
{
"request_id": "req_abc123",
"tool_name": "gmail_send",
"tool_input": {
"to": "user@example.com"
},
"status": "allowed",
"created_at": "2026-01-15T10:05:30Z",
"resolved_at": "2026-01-15T10:05:45Z"
}Archive Run
POST /runs/{run_id}/archive
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/archive \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Cancel Run
Cancel an active run. Returns 409 if the run is already completed, failed, or cancelled.
POST /runs/{run_id}/cancel
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/cancel \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Desktop Ticket
POST /runs/{run_id}/desktop-ticket
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/desktop-ticket \
-H "Authorization: Bearer m8_your_key_here"Reply To Run
Send a follow-up message on an existing run to continue the conversation.
Behavior note:
runs.reply()inherits the run's settings: the permission mode (approval/plangates keep applying) and whether the agent may ask questions (human_in_the_loop, as persisted at run creation). Passhuman_in_the_loop: falseon the reply to pin the legacy always-non-interactive behavior. Runs created before this setting existed stay non-interactive.
Internal tools: replies inherit the previous run's
task_setup_toolssetting unless you override it in the request body. Tools are automatically inherited from the previous run; to use different tools, start a new run.
POST /runs/{run_id}/reply
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/reply \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"message": "What about VIP tickets?","stream": false}'Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Retry Run
POST /runs/{run_id}/retry
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/retry \
-H "Authorization: Bearer m8_your_key_here"Response 201 Created
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Share Run
POST /runs/{run_id}/share
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/share \
-H "Authorization: Bearer m8_your_key_here"Unarchive Run
POST /runs/{run_id}/unarchive
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/unarchive \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Mark Run Viewed
POST /runs/{run_id}/view
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/view \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Read Desktop
GET /runs/{run_id}/desktop
curl \
https://api.m8tes.ai/api/v2/runs/42/desktop \
-H "Authorization: Bearer m8_your_key_here"List Run Messages
GET /runs/{run_id}/messages
curl \
https://api.m8tes.ai/api/v2/runs/42/messages \
-H "Authorization: Bearer m8_your_key_here"Get Run Outcome
GET /runs/{run_id}/outcome
curl \
https://api.m8tes.ai/api/v2/runs/42/outcome \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"run_id": 42,
"status": "completed",
"summary": "Audit done: paused 3 wasteful keywords, saving ~$120/mo.",
"headline": "wasted spend cut",
"needs_reply": false,
"delivery_channel": "email",
"message_count": 14,
"input_tokens": 48210,
"output_tokens": 3120,
"total_tokens": 51330,
"cost_usd": "0.4831"
}List Run Permissions
Returns pending and resolved tool permission requests for runs using approval or plan mode. This list can include tool_name="AskUserQuestion" entries.
GET /runs/{run_id}/permissions
curl \
https://api.m8tes.ai/api/v2/runs/42/permissions \
-H "Authorization: Bearer m8_your_key_here"Join Run Stream
GET /runs/{run_id}/stream
curl \
https://api.m8tes.ai/api/v2/runs/42/stream \
-H "Authorization: Bearer m8_your_key_here"Update Permission Mode
PATCH /runs/{run_id}/permission-mode
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/runs/42/permission-mode \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"permission_mode": "autonomous"}'Mid-run behavior: Call this while the run is
runningorawaiting_approval.
Autonomous switch: changing to
autonomousauto-approves pending tool approval requests and resumes a paused tool approval run.
Questions still wait:
AskUserQuestionand plan approvals are not auto-answered. UsePOST /runs/{id}/answerfor those pauses.
Unshare Run
DELETE /runs/{run_id}/share
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/runs/42/share \
-H "Authorization: Bearer m8_your_key_here"Reply To Run With Files
POST /runs/{run_id}/reply/with-files
curl \
-X POST \
https://api.m8tes.ai/api/v2/runs/42/reply/with-files \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Audit-Logs
Audit logs provide account-scoped request history for the v2 API.
List Audit Logs
GET /audit-logs
curl \
https://api.m8tes.ai/api/v2/audit-logs \
-H "Authorization: Bearer m8_your_key_here"Tasks
Tasks are reusable job definitions. Create a task, then attach triggers via tasks.triggers.create().
Create Task
POST /tasks
curl \
-X POST \
https://api.m8tes.ai/api/v2/tasks \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"teammate_id": 1,"name": "Ticket Closer","instructions": "Close open support tickets"}'Response 201 Created
{
"id": 10,
"teammate_id": 1,
"name": "Ticket Closer",
"instructions": "Close open support tickets",
"tools": [],
"app_trigger_count": 0,
"email_notifications": true,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}List Tasks
GET /tasks
curl \
https://api.m8tes.ai/api/v2/tasks?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Task
GET /tasks/{task_id}
curl \
https://api.m8tes.ai/api/v2/tasks/10 \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 10,
"teammate_id": 1,
"name": "Ticket Closer",
"instructions": "Close open support tickets",
"tools": [],
"app_trigger_count": 0,
"email_notifications": true,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Update Task
PATCH /tasks/{task_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/tasks/10 \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"instructions": "Updated instructions"}'Response 200 OK
{
"id": 10,
"teammate_id": 1,
"name": "Ticket Closer",
"instructions": "Close open support tickets",
"tools": [],
"app_trigger_count": 0,
"email_notifications": true,
"status": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}Delete Task
DELETE /tasks/{task_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/tasks/10 \
-H "Authorization: Bearer m8_your_key_here"Run Task
POST /tasks/{task_id}/runs
curl \
-X POST \
https://api.m8tes.ai/api/v2/tasks/10/runs \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"stream": false}'Defaults: If
permission_modeis omitted, the run inherits the saved task's permission mode. Ifhuman_in_the_loopis omitted, inheritedapprovalandplanruns automatically enable it.
Validation: Explicitly setting
human_in_the_loop=falseis only valid withpermission_mode="autonomous".
Internal tools:
task_setup_tools=trueby default. Set it tofalseto run a saved task without the internal same-scope management tools.
End-user scope: when the saved task is already scoped, the
user_idin the request must match that scope. If omitted, the run inherits the task's existing scope.
Response 200 OK
{
"id": 42,
"teammate_id": 1,
"task_id": 10,
"status": "running",
"user_id": "customer_123",
"permission_mode": "autonomous",
"created_at": "2026-01-15T10:05:00Z"
}Create Trigger
POST /tasks/{task_id}/triggers
curl \
-X POST \
https://api.m8tes.ai/api/v2/tasks/10/triggers \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"type": "schedule","cron": "0 9 * * 1","timezone": "America/New_York"}'Response 201 Created
{
"id": "schedule_5",
"type": "schedule",
"enabled": true,
"cron": "0 9 * * 1",
"timezone": "America/New_York"
}Enable Task Webhook
POST /tasks/{task_id}/webhook
curl \
-X POST \
https://api.m8tes.ai/api/v2/tasks/10/webhook \
-H "Authorization: Bearer m8_your_key_here"List Triggers
GET /tasks/{task_id}/triggers
curl \
https://api.m8tes.ai/api/v2/tasks/10/triggers \
-H "Authorization: Bearer m8_your_key_here"Set Task Webhook Enabled
PATCH /tasks/{task_id}/webhook
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/tasks/10/webhook \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'Disable Task Webhook
DELETE /tasks/{task_id}/webhook
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/tasks/10/webhook \
-H "Authorization: Bearer m8_your_key_here"Update Trigger
PATCH /tasks/{task_id}/triggers/{trigger_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/tasks/10/triggers/schedule_5 \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'Response 200 OK
{
"id": "schedule_5",
"type": "schedule",
"enabled": true,
"cron": "0 9 * * 1",
"timezone": "America/New_York"
}Delete Trigger
DELETE /tasks/{task_id}/triggers/{trigger_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/tasks/10/triggers/schedule_5 \
-H "Authorization: Bearer m8_your_key_here"Triggers
List schedule, webhook, email, and app triggers across the account without fetching each task separately.
List Triggers
GET /triggers
curl \
https://api.m8tes.ai/api/v2/triggers?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Lessons
Self-improvement lessons a task's agent writes for itself across runs. The agent authors them during runs; via the API you can list or clear them per task.
Clear Lessons
POST /tasks/{task_id}/lessons:clear
curl \
-X POST \
https://api.m8tes.ai/api/v2/tasks/10/lessons:clear \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"capacity_limit": 20,
"capacity_used": 0,
"data": []
}List Lessons
GET /tasks/{task_id}/lessons
curl \
https://api.m8tes.ai/api/v2/tasks/10/lessons \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"capacity_limit": 20,
"capacity_used": 0,
"data": []
}Delete Lesson
DELETE /tasks/{task_id}/lessons/{lesson_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/tasks/10/lessons/{lesson_id} \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"capacity_limit": 20,
"capacity_used": 0,
"data": []
}Apps
List available tools, connect integrations via OAuth, and manage end-user connections.
List Apps
Pass user_id to check connection status for a specific end-user.
GET /apps
curl \
https://api.m8tes.ai/api/v2/apps?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Connections
GET /apps/connections
curl \
https://api.m8tes.ai/api/v2/apps/connections?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Claim Slack Install
POST /apps/{app_name}/claim
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/claim \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"ticket": "..."}'Connect App
POST /apps/{app_name}/connect
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/connect \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"redirect_uri": "https://yourapp.com/callback","user_id": "cust_123"}'Response 200 OK
{
"authorization_url": "https://accounts.google.com/o/oauth2/auth?...",
"connection_id": "conn_abc123"
}Start Slack Install
POST /apps/{app_name}/install
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/install \
-H "Authorization: Bearer m8_your_key_here"Provision App
For apps with auth_type: "platform_provisioned" (e.g. twilio), the platform allocates a dedicated resource (a phone number) rather than you supplying credentials. Pass user_id to provision a per-end-user resource (strictly isolated at run time); omit it for an account-level resource. Release it with DELETE /apps/{app_name}/connections (client.apps.release(...)).
POST /apps/{app_name}/provision
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/twilio/provision \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"user_id": "cust_123"}'Response 200 OK
{
"status": "provisioned",
"app": "twilio",
"phone_number": "+15551234567"
}List Slack Channels
GET /apps/{app_name}/channels
curl \
https://api.m8tes.ai/api/v2/apps/slack:messaging/channels \
-H "Authorization: Bearer m8_your_key_here"List App Connections
GET /apps/{app_name}/connections
curl \
https://api.m8tes.ai/api/v2/apps/gmail/connections \
-H "Authorization: Bearer m8_your_key_here"List Google Ads Customers
GET /apps/{app_name}/customers
curl \
https://api.m8tes.ai/api/v2/apps/gmail/customers \
-H "Authorization: Bearer m8_your_key_here"List Slack Members
GET /apps/{app_name}/members
curl \
https://api.m8tes.ai/api/v2/apps/gmail/members \
-H "Authorization: Bearer m8_your_key_here"List Google Search Console Sites
GET /apps/{app_name}/sites
curl \
https://api.m8tes.ai/api/v2/apps/gmail/sites \
-H "Authorization: Bearer m8_your_key_here"List App Tools
GET /apps/{app_name}/tools
curl \
https://api.m8tes.ai/api/v2/apps/gmail/tools \
-H "Authorization: Bearer m8_your_key_here"List App Trigger Types
GET /apps/{app_name}/triggers
curl \
https://api.m8tes.ai/api/v2/apps/gmail/triggers \
-H "Authorization: Bearer m8_your_key_here"List Slack Workspaces
GET /apps/{app_name}/workspaces
curl \
https://api.m8tes.ai/api/v2/apps/gmail/workspaces \
-H "Authorization: Bearer m8_your_key_here"Update App Connection
PATCH /apps/connections/{connection_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/apps/connections/{connection_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"label": "ops@acme.com","notes": "Customer support replies only"}'Response 200 OK
{
"connection_id": "ca_abc123",
"status": "active",
"account_label": "ops@example.com",
"scopes": [
"https://mail.google.com/"
],
"updated_at": "2026-08-18T12:00:00Z"
}Select Google Ads Customer
PUT /apps/{app_name}/customer
curl \
-X PUT \
https://api.m8tes.ai/api/v2/apps/gmail/customer \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"account_id": "..."}'Select Google Search Console Site
PUT /apps/{app_name}/site
curl \
-X PUT \
https://api.m8tes.ai/api/v2/apps/gmail/site \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"account_id": "..."}'Delete App Connection
DELETE /apps/connections/{connection_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/apps/connections/{connection_id} \
-H "Authorization: Bearer m8_your_key_here"Disconnect App
DELETE /apps/{app_name}/connections
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/apps/gmail/connections \
-H "Authorization: Bearer m8_your_key_here"Connect App Api Key
POST /apps/{app_name}/connect/api-key
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/connect/api-key \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"api_key": "sk-...","user_id": "cust_123"}'Response 200 OK
{
"status": "connected",
"app": "gmail"
}Connect App Complete
After the user completes OAuth and is redirected back:
POST /apps/{app_name}/connect/complete
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/connect/complete \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"connection_id": "conn_abc123","user_id": "cust_123"}'Response 200 OK
{
"status": "connected",
"app": "gmail"
}Connect External Oauth
POST /apps/{app_name}/connect/external-oauth
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/connect/external-oauth \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"redirect_uri": "..."}'Disconnect Slack Workspace
DELETE /apps/{app_name}/workspaces/{team_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/apps/gmail/workspaces/{team_id} \
-H "Authorization: Bearer m8_your_key_here"Complete External Oauth
POST /apps/{app_name}/connect/external-oauth/complete
curl \
-X POST \
https://api.m8tes.ai/api/v2/apps/gmail/connect/external-oauth/complete \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"redirect_uri": "...","code": "...","state": "..."}'Response 200 OK
{
"status": "connected",
"app": "gmail"
}Built-In-Tools
Discover the platform's built-in tools (memory, task history, task setup, feedback, and more). These are not passed in the tools array; the four configurable ones are toggled via the enable_* fields on agents, tasks, and runs.
List Built In Tools
GET /built-in-tools
curl \
https://api.m8tes.ai/api/v2/built-in-tools?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Judgments
Advisory Jev judgments over supplied state or evidence. Platform-funded by default; connect a write-only TypeSafe key once for customer-funded account workloads. Neither mode debits your m8tes balance; customer funding is billed by TypeSafe. Invalid customer credentials never fall back to platform funding. Request-count limits apply to both modes. Results do not grant action permissions or certify source authenticity. Optional Idempotency-Key protects a request for 24 hours; successful results can be retrieved for 30 days. Evidence can reference scoped platform documents or stored tool results with content provenance. See built-in tools.
Create Judgment
Choose mode=decide with state and questions (Choice, Score, Noul), or mode=verify with claims and evidence. Each claim has id, text, and evidence_ids. Evidence requires either text or source (type: document|tool_result, positive record id), not both. References resolve stored content within the same account/end-user scope; tool-result IDs identify persisted conversation messages containing tool-result blocks. Optional user_id sets the end-user scope; run_id attributes a same-scope run. Inputs are limited to 32 questions/claims, 16,384 characters per source, and 128 KiB after source resolution. Oversized evidence is rejected. Results include typed answers, model, usage, latency_ms, and estimated provider cost_usd and funding_source (platform or customer). m8tes does not debit your balance; customer-funded requests are billed by TypeSafe. Verification includes rubric_version, claim/evidence coverage, and content provenance; independently_authenticated is always false. Missing evidence produces insufficient_evidence; if no provider call is needed, model is not_called. Pass the optional Idempotency-Key header (SDK idempotency_key) to protect an exact request for 24 hours. Success replays return the same ID and original cost without another provider charge. Conflicting, pending, or failed attempts return 409. Metadata-only scopes do not retain answers and return 410 on replay. SDK automatic POST retries require a key.
POST /judgments
curl \
-X POST \
https://api.m8tes.ai/api/v2/judgments \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"mode": "verify","claims": [{"id": "c1","text": "Tests passed","evidence_ids": ["e1"]}],"evidence": [{"id": "e1","text": "pytest: 12 passed"}]}'Get Connection
Read account-level TypeSafe metadata only: connected, enabled, funding_source, model, and nullable updated_at. The key is never returned. connected means a key is stored, not validated by the provider. No user_id is accepted: one connection covers all end-user and agent workloads.
GET /judgments/connection
curl \
https://api.m8tes.ai/api/v2/judgments/connection \
-H "Authorization: Bearer m8_your_key_here"Get Judgment
Retrieve a saved successful judgment for 30 days without another provider call. Use the original user_id; missing or foreign IDs return 404. Pending/failed attempts return 409. Expired results and metadata-only retention return 410 result_not_retained. Returned cost_usd is the original estimate, not another charge. Settled known-cost metadata is retained for 90 days; unresolved or unknown-cost reservations remain for reconciliation.
GET /judgments/{judgment_id}
curl \
https://api.m8tes.ai/api/v2/judgments/{judgment_id} \
-H "Authorization: Bearer m8_your_key_here"Put Connection
Configure once per account from a trusted server, or replace the key to rotate it. Read api_key from a server environment variable or secret manager; never pass it in prompts or agent tool arguments. It is write-only and encrypted at rest. No paid validation occurs when storing the key. Invalid customer credentials never fall back to platform funding. The service kill switch and request-count limits still apply; platform dollar caps do not apply to customer funding. Returns the same metadata as GET.
PUT /judgments/connection
curl \
-X PUT \
https://api.m8tes.ai/api/v2/judgments/connection \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"api_key": "..."}'Delete Connection
Remove the account's TypeSafe key. Returns HTTP 204 without a body. Future judgments return to platform funding if available; deletion does not enable a service disabled by the platform.
DELETE /judgments/connection
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/judgments/connection \
-H "Authorization: Bearer m8_your_key_here"Mcp-Servers
Register your own REST, remote MCP, or Python script tools. kind=script takes script_source (write-only; reads return script_sha256) and cannot take user_id; strict API accounts can still create one. See the Custom tools guide.
Create Mcp Server
kind is rest_api (default; typed tool_defs with method/path), mcp_http/mcp_sse (remote MCP; empty tool_defs), or script (Python script_source; tool_defs are name-only; user_id is forbidden). script_source is write-only; the response carries script_sha256.
POST /mcp-servers
curl \
-X POST \
https://api.m8tes.ai/api/v2/mcp-servers \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "acme billing","url": "https://api.acme.com/v1","auth_type": "bearer","secret": "sk-...","tool_defs": [{"method": "GET","name": "get_invoice","path": "/invoices/{id}"}]}'Create Mcp Server
kind is rest_api (default; typed tool_defs with method/path), mcp_http/mcp_sse (remote MCP; empty tool_defs), or script (Python script_source; tool_defs are name-only; user_id is forbidden). script_source is write-only; the response carries script_sha256.
POST /mcp-servers
curl \
-X POST \
https://api.m8tes.ai/api/v2/mcp-servers \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "acme billing","url": "https://api.acme.com/v1","auth_type": "bearer","secret": "sk-...","tool_defs": [{"method": "GET","name": "get_invoice","path": "/invoices/{id}"}]}'List Mcp Servers
GET /mcp-servers
curl \
https://api.m8tes.ai/api/v2/mcp-servers?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Mcp Servers
GET /mcp-servers
curl \
https://api.m8tes.ai/api/v2/mcp-servers?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Mcp Server
GET /mcp-servers/{server_id}
curl \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id} \
-H "Authorization: Bearer m8_your_key_here"Update Mcp Server
PATCH /mcp-servers/{server_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Delete Mcp Server
DELETE /mcp-servers/{server_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id} \
-H "Authorization: Bearer m8_your_key_here"Approve Mcp Server
POST /mcp-servers/{server_id}/approve
curl \
-X POST \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id}/approve \
-H "Authorization: Bearer m8_your_key_here"Complete Mcp Server Oauth
POST /mcp-servers/{server_id}/oauth/complete
curl \
-X POST \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id}/oauth/complete \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"code": "...","state": "..."}'Start Mcp Server Oauth
POST /mcp-servers/{server_id}/oauth/start
curl \
-X POST \
https://api.m8tes.ai/api/v2/mcp-servers/{server_id}/oauth/start \
-H "Authorization: Bearer m8_your_key_here"Skills
Reusable SKILL.md playbooks agents load on demand. Create account- or agent-scoped skills; see the Custom Skills guide. Force a skill from chat with /slug or pass skill on create/reply. List picker entries with GET /skills/invokable (platform commands like make-skill / own-task / feedback plus your custom skills — never the baked snapshot catalog).
Create Skill
POST /skills
curl \
-X POST \
https://api.m8tes.ai/api/v2/skills \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "acme refund playbook","description": "How to process an Acme refund end-to-end.","body": "# Steps\n1. Pull the order in Stripe\n2. ...","scope": "account"}'Create Skill
POST /skills
curl \
-X POST \
https://api.m8tes.ai/api/v2/skills \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "acme refund playbook","description": "How to process an Acme refund end-to-end.","body": "# Steps\n1. Pull the order in Stripe\n2. ...","scope": "account"}'List Skills
GET /skills
curl \
https://api.m8tes.ai/api/v2/skills?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Skills
GET /skills
curl \
https://api.m8tes.ai/api/v2/skills?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Invokable Skills
GET /skills/invokable
curl \
https://api.m8tes.ai/api/v2/skills/invokable?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Invokable Skills
GET /skills/invokable
curl \
https://api.m8tes.ai/api/v2/skills/invokable?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Skill
GET /skills/{skill_id}
curl \
https://api.m8tes.ai/api/v2/skills/{skill_id} \
-H "Authorization: Bearer m8_your_key_here"Update Skill
PATCH /skills/{skill_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/skills/{skill_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Delete Skill
DELETE /skills/{skill_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/skills/{skill_id} \
-H "Authorization: Bearer m8_your_key_here"Bridges
Per-account BlueBubbles bridges that connect an agent to iMessage. Register a bridge, then enable inbound iMessage on an agent with bridge_id.
Create Bridge
POST /bridges
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"server_url": "https://bluebubbles.example.com","password": "your-password"}'List Bridges
GET /bridges
curl \
https://api.m8tes.ai/api/v2/bridges \
-H "Authorization: Bearer m8_your_key_here"Provision Bridge
POST /bridges/provision
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges/provision \
-H "Authorization: Bearer m8_your_key_here"Provision Blooio
POST /bridges/provision-blooio
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges/provision-blooio \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"number": "+15551234567"}'Get Bridge
GET /bridges/{bridge_id}
curl \
https://api.m8tes.ai/api/v2/bridges/{bridge_id} \
-H "Authorization: Bearer m8_your_key_here"Update Bridge
PATCH /bridges/{bridge_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/bridges/{bridge_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Delete Bridge
DELETE /bridges/{bridge_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/bridges/{bridge_id} \
-H "Authorization: Bearer m8_your_key_here"Regenerate Bridge Link Code
POST /bridges/{bridge_id}/link-code
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges/{bridge_id}/link-code \
-H "Authorization: Bearer m8_your_key_here"Rotate Bridge Secret
POST /bridges/{bridge_id}/rotate-secret
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges/{bridge_id}/rotate-secret \
-H "Authorization: Bearer m8_your_key_here"Test Bridge Connection
POST /bridges/{bridge_id}/test
curl \
-X POST \
https://api.m8tes.ai/api/v2/bridges/{bridge_id}/test \
-H "Authorization: Bearer m8_your_key_here"List Bridge Handles
GET /bridges/{bridge_id}/handles
curl \
https://api.m8tes.ai/api/v2/bridges/{bridge_id}/handles \
-H "Authorization: Bearer m8_your_key_here"Delete Bridge Handle
DELETE /bridges/{bridge_id}/handles/{handle_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/bridges/{bridge_id}/handles/{handle_id} \
-H "Authorization: Bearer m8_your_key_here"Channels
Slack and GitHub channel identity for this account. With no identity the shared @m8tes Slack app / m8tes GitHub App is used; upsert_identity stores your own Slack app or GitHub App credentials (bot/App name and avatar stay in Slack/GitHub dashboards). channel=github requires github_app_id, github_app_slug, and github_private_key. install_links mints Add-to-Slack and GitHub App install URLs; it 503s if Slack is unavailable even when GitHub is configured.
List Channels
GET /channels
curl \
https://api.m8tes.ai/api/v2/channels \
-H "Authorization: Bearer m8_your_key_here"Get Install Links
GET /channels/install-links
curl \
https://api.m8tes.ai/api/v2/channels/install-links?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Upsert Identity
PUT /channels/identities
curl \
-X PUT \
https://api.m8tes.ai/api/v2/channels/identities \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"channel": "slack","client_id": "...","client_secret": "...","signing_secret": "..."}'Github-App
Coding-agent GitHub install. Account-scoped (not per user_id). m8tes GitHub App: open install_url, then claim(ticket) if the redirect returns one. Your GitHub App: open setup_url, then complete_setup(ticket) stores credentials and returns the install URL. Same claim flow after that. clear_identity reverts after disconnect. Per-agent repos: /agents/{id}/repos. See Coding Agents.
Github App Disconnect
DELETE /github-app
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/github-app \
-H "Authorization: Bearer m8_your_key_here"Github App Claim
POST /github-app/claim
curl \
-X POST \
https://api.m8tes.ai/api/v2/github-app/claim \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"ticket": "..."}'Github App Complete Setup
POST /github-app/complete-setup
curl \
-X POST \
https://api.m8tes.ai/api/v2/github-app/complete-setup \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"ticket": "..."}'Github App Install Url
GET /github-app/install-url
curl \
https://api.m8tes.ai/api/v2/github-app/install-url \
-H "Authorization: Bearer m8_your_key_here"Github App Repos
GET /github-app/repos
curl \
https://api.m8tes.ai/api/v2/github-app/repos \
-H "Authorization: Bearer m8_your_key_here"Github App Setup Url
GET /github-app/setup-url
curl \
https://api.m8tes.ai/api/v2/github-app/setup-url?cancel_epoch=... \
-H "Authorization: Bearer m8_your_key_here"Github App Status
GET /github-app/status
curl \
https://api.m8tes.ai/api/v2/github-app/status \
-H "Authorization: Bearer m8_your_key_here"Github App Clear Identity
DELETE /github-app/identity
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/github-app/identity \
-H "Authorization: Bearer m8_your_key_here"Memories
Pre-populate or manage end-user memories. Memories are injected into the agent's context during execution to personalize responses.
Create Memory
POST /memories
curl \
-X POST \
https://api.m8tes.ai/api/v2/memories \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"user_id": "customer_123","content": "Prefers email over Slack"}'Response 201 Created
{
"id": 7,
"user_id": "customer_123",
"content": "Prefers email over Slack",
"source": "api",
"created_at": "2026-01-15T10:00:00Z"
}List Memories
Pass user_id to list one end-user's memories; omit it for account-level memories. The two scopes never mix.
GET /memories
curl \
https://api.m8tes.ai/api/v2/memories?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Update Memory
PATCH /memories/{memory_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/memories/7 \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"content": "prefers a concise Monday summary, no charts"}'Response 200 OK
{
"id": 7,
"user_id": "customer_123",
"content": "Prefers email over Slack",
"source": "api",
"created_at": "2026-01-15T10:00:00Z"
}Delete Memory
Matches exactly the scope you pass: an end-user memory is only reachable with its user_id, an account-level memory only without one.
DELETE /memories/{memory_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/memories/7 \
-H "Authorization: Bearer m8_your_key_here"Documents
Manage persistent company- or agent-scoped context. Agents author document content; API clients can list, read, rename, summarize, and delete it.
List Documents
GET /documents
curl \
https://api.m8tes.ai/api/v2/documents?user_id=customer_123&scope=... \
-H "Authorization: Bearer m8_your_key_here"Get Document
GET /documents/{document_id}
curl \
https://api.m8tes.ai/api/v2/documents/{document_id} \
-H "Authorization: Bearer m8_your_key_here"Update Document
PATCH /documents/{document_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/documents/{document_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Delete Document
DELETE /documents/{document_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/documents/{document_id} \
-H "Authorization: Bearer m8_your_key_here"Artifacts
Durable, shareable copies of what a run produced. Promote a run file (or its latest-report.md) into an artifact that outlives the sandbox, then mint a public link the way you would for a run.
Create Artifact
POST /artifacts
curl \
-X POST \
https://api.m8tes.ai/api/v2/artifacts \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"run_id": 1,"filename": "..."}'List Artifacts
GET /artifacts
curl \
https://api.m8tes.ai/api/v2/artifacts?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Artifact
GET /artifacts/{artifact_id}
curl \
https://api.m8tes.ai/api/v2/artifacts/{artifact_id} \
-H "Authorization: Bearer m8_your_key_here"Delete Artifact
DELETE /artifacts/{artifact_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/artifacts/{artifact_id} \
-H "Authorization: Bearer m8_your_key_here"Share Artifact
POST /artifacts/{artifact_id}/share
curl \
-X POST \
https://api.m8tes.ai/api/v2/artifacts/{artifact_id}/share \
-H "Authorization: Bearer m8_your_key_here"Get Artifact Content
GET /artifacts/{artifact_id}/content
curl \
https://api.m8tes.ai/api/v2/artifacts/{artifact_id}/content \
-H "Authorization: Bearer m8_your_key_here"Unshare Artifact
DELETE /artifacts/{artifact_id}/share
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/artifacts/{artifact_id}/share \
-H "Authorization: Bearer m8_your_key_here"Feedback
Send product feedback to the m8tes team, optionally attaching a run. Same chokepoint as the /feedback slash command and the MCP submit_feedback tool. Pass user_id when attaching an end-user-scoped run.
Submit feedback
POST /feedback
curl \
-X POST \
https://api.m8tes.ai/api/v2/feedback \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"message": "This run stalled on the Google Ads connect step.","run_id": 42,"user_id": "customer_123"}'Response 201 Created
{
"id": 9,
"title": "This run stalled on the Google Ads connect step.",
"run_id": 42,
"created_at": "2026-09-27T12:00:00Z"
}Groups
Flat mate groups for organizing agents (Team axis). Assign via agents.create(group_id=...) or agents.update(group_id=...). Not human Organizations — those stay under Teams. POST /groups/{id}/share bulk-sets mate visibility (selection set); the group organizes which mates flip — it is not a group ACL.
Create Group
POST /groups
curl \
-X POST \
https://api.m8tes.ai/api/v2/groups \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'List Groups
GET /groups
curl \
https://api.m8tes.ai/api/v2/groups?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Group
GET /groups/{group_id}
curl \
https://api.m8tes.ai/api/v2/groups/{group_id} \
-H "Authorization: Bearer m8_your_key_here"Update Group
PATCH /groups/{group_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/groups/{group_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"parent_id": 1}'Delete Group
DELETE /groups/{group_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/groups/{group_id} \
-H "Authorization: Bearer m8_your_key_here"Accept Group Invite
POST /groups/invites/accept
curl \
-X POST \
https://api.m8tes.ai/api/v2/groups/invites/accept \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"token": "..."}'Create Group Invite
POST /groups/{group_id}/invites
curl \
-X POST \
https://api.m8tes.ai/api/v2/groups/{group_id}/invites \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'Share Group
POST /groups/{group_id}/share
curl \
-X POST \
https://api.m8tes.ai/api/v2/groups/{group_id}/share \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"visibility": "personal"}'Preview Group Invite
GET /groups/invites/{token}
curl \
https://api.m8tes.ai/api/v2/groups/invites/{token} \
-H "Authorization: Bearer m8_your_key_here"List Group Invites
GET /groups/{group_id}/invites
curl \
https://api.m8tes.ai/api/v2/groups/{group_id}/invites \
-H "Authorization: Bearer m8_your_key_here"List Group Members
GET /groups/{group_id}/members
curl \
https://api.m8tes.ai/api/v2/groups/{group_id}/members \
-H "Authorization: Bearer m8_your_key_here"Cancel Group Invite
DELETE /groups/invites/{invite_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/groups/invites/{invite_id} \
-H "Authorization: Bearer m8_your_key_here"Update Group Member
PATCH /groups/{group_id}/members/{member_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/groups/{group_id}/members/{member_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"role": "viewer"}'Remove Group Member
DELETE /groups/{group_id}/members/{member_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/groups/{group_id}/members/{member_id} \
-H "Authorization: Bearer m8_your_key_here"Permissions
Pre-configure tool allow-lists for your end-users. Tools added here are auto-approved when runs use approval mode.
Create Permission
Idempotent: re-creating the same permission returns the existing record.
POST /permissions
curl \
-X POST \
https://api.m8tes.ai/api/v2/permissions \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"user_id": "customer_123","tool": "gmail"}'Response 201 Created
{
"id": 3,
"user_id": "customer_123",
"tool_name": "gmail",
"created_at": "2026-01-15T10:00:00Z"
}List Permissions
GET /permissions
curl \
https://api.m8tes.ai/api/v2/permissions?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Delete Permission
DELETE /permissions/{permission_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/permissions/3 \
-H "Authorization: Bearer m8_your_key_here"Users
Manage end-user profiles. Profiles are auto-created when user_id is passed to any endpoint, or created explicitly with profile data.
Create End User
POST /users
curl \
-X POST \
https://api.m8tes.ai/api/v2/users \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"user_id": "cust_123","name": "Alice Smith","email": "alice@acme.com"}'Response 201 Created
{
"id": 1,
"user_id": "cust_123",
"name": "Alice Smith",
"email": "alice@acme.com",
"company": "Acme Corp",
"created_at": "2026-01-15T10:00:00Z"
}List End Users
GET /users
curl \
https://api.m8tes.ai/api/v2/users \
-H "Authorization: Bearer m8_your_key_here"Get End User
GET /users/{user_id}
curl \
https://api.m8tes.ai/api/v2/users/{user_id} \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 1,
"user_id": "cust_123",
"name": "Alice Smith",
"email": "alice@acme.com",
"company": "Acme Corp",
"created_at": "2026-01-15T10:00:00Z"
}Update End User
PATCH /users/{user_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/users/{user_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "Alice Smith-Jones","company": "Acme Corp"}'Response 200 OK
{
"id": 1,
"user_id": "cust_123",
"name": "Alice Smith",
"email": "alice@acme.com",
"company": "Acme Corp",
"created_at": "2026-01-15T10:00:00Z"
}Delete End User
DELETE /users/{user_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/users/{user_id} \
-H "Authorization: Bearer m8_your_key_here"Teams
Organizations the account belongs to, their seats, and email invites. Invite and accept are gated by the Teams beta flag; listing, revoking an invite, and removing a member always work for an existing organization.
List Teams
GET /teams
curl \
https://api.m8tes.ai/api/v2/teams \
-H "Authorization: Bearer m8_your_key_here"Accept Team Invite
POST /teams/invites/accept
curl \
-X POST \
https://api.m8tes.ai/api/v2/teams/invites/accept \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"token": "..."}'Create Team Invite
POST /teams/{org_id}/invites
curl \
-X POST \
https://api.m8tes.ai/api/v2/teams/{org_id}/invites \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'Preview Team Invite
GET /teams/invites/{token}
curl \
https://api.m8tes.ai/api/v2/teams/invites/{token} \
-H "Authorization: Bearer m8_your_key_here"Revoke Team Invite
DELETE /teams/invites/{invite_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/teams/invites/{invite_id} \
-H "Authorization: Bearer m8_your_key_here"Remove Team Member
DELETE /teams/{org_id}/members/{member_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/teams/{org_id}/members/{member_id} \
-H "Authorization: Bearer m8_your_key_here"Settings
Account-level configuration: data retention and per-end-user sub-caps.
Get Settings
GET /settings
curl \
https://api.m8tes.ai/api/v2/settings \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"retention_mode": "standard"
}Update Settings
PATCH /settings
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/settings \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"retention_mode": "metadata_only"}'Response 200 OK
{
"retention_mode": "standard"
}Keys
Create Named Key
POST /keys
curl \
-X POST \
https://api.m8tes.ai/api/v2/keys \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Get Key Info
GET /keys
curl \
https://api.m8tes.ai/api/v2/keys \
-H "Authorization: Bearer m8_your_key_here"Revoke Key
DELETE /keys
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/keys \
-H "Authorization: Bearer m8_your_key_here"Rotate Key
POST /keys/rotate
curl \
-X POST \
https://api.m8tes.ai/api/v2/keys/rotate \
-H "Authorization: Bearer m8_your_key_here"List Named Keys
GET /keys/all
curl \
https://api.m8tes.ai/api/v2/keys/all \
-H "Authorization: Bearer m8_your_key_here"Revoke Named Key
DELETE /keys/{key_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/keys/{key_id} \
-H "Authorization: Bearer m8_your_key_here"Rotate Named Key
POST /keys/{key_id}/rotate
curl \
-X POST \
https://api.m8tes.ai/api/v2/keys/{key_id}/rotate \
-H "Authorization: Bearer m8_your_key_here"Usage
Inspect the current account plan, run usage, cost usage, and billing period.
Get Usage
GET /usage
curl \
https://api.m8tes.ai/api/v2/usage \
-H "Authorization: Bearer m8_your_key_here"client.billing.usage() is an alias for client.auth.get_usage().
Response 200 OK
{
"plan": "trial",
"runs_used": 2,
"runs_limit": 50,
"cost_used": "0.12",
"cost_limit": "20.00",
"period_end": "2026-03-27T10:00:00Z",
"free_path_available": true,
"overage_enabled": false,
"overage_used_cents": 0,
"overage_cap_cents": 0,
"overage_rate_cents": 200,
"trial_ends_at": "2026-04-01T10:00:00Z",
"unlimited_runs": false,
"concurrent_runs": 1,
"concurrent_runs_limit": 10
}List End User Usage
GET /usage/end-users
curl \
https://api.m8tes.ai/api/v2/usage/end-users?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Usage Timeseries
GET /usage/timeseries
curl \
https://api.m8tes.ai/api/v2/usage/timeseries?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"start_date": "2026-06-14",
"end_date": "2026-07-13",
"buckets": [
{
"cache_creation_tokens": 12000,
"cache_read_tokens": 91000,
"cost_usd": "3.41",
"date": "2026-07-13",
"input_tokens": 182000,
"output_tokens": 24500,
"total_tokens": 309500
}
],
"totals": {
"cache_creation_tokens": 12000,
"cache_read_tokens": 91000,
"cost_usd": "3.41",
"input_tokens": 182000,
"output_tokens": 24500,
"total_tokens": 309500
}
}Billing
Inspect the public Hobby and paid-plan catalog, manage opt-in usage overage for eligible team plans (per-run charges past the included runs, capped at a monthly ceiling you set), and top up or read a prepaid token balance (a micro-USD balance plus its ledger).
Activate Hobby Plan
POST /billing/activate-free
curl \
-X POST \
https://api.m8tes.ai/api/v2/billing/activate-free \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"plan": "trial",
"runs_used": 2,
"runs_limit": 50,
"cost_used": "0.12",
"cost_limit": "20.00",
"period_end": "2026-03-27T10:00:00Z",
"free_path_available": true,
"overage_enabled": false,
"overage_used_cents": 0,
"overage_cap_cents": 0,
"overage_rate_cents": 200,
"trial_ends_at": "2026-04-01T10:00:00Z",
"unlimited_runs": false,
"concurrent_runs": 1,
"concurrent_runs_limit": 10
}Create Checkout
POST /billing/checkout
curl \
-X POST \
https://api.m8tes.ai/api/v2/billing/checkout \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"plan_id": "individual"}'Create Portal
POST /billing/portal
curl \
-X POST \
https://api.m8tes.ai/api/v2/billing/portal \
-H "Authorization: Bearer m8_your_key_here"Create Topup
POST /billing/topup
curl \
-X POST \
https://api.m8tes.ai/api/v2/billing/topup \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 5000}'The call returns a Stripe Checkout URL; the balance is credited asynchronously after payment, so balance() won't reflect it until checkout completes.
Response 200 OK
{
"checkout_url": "https://checkout.stripe.com/..."
}Get Balance
GET /billing/balance
curl \
https://api.m8tes.ai/api/v2/billing/balance \
-H "Authorization: Bearer m8_your_key_here"Amounts are in micro-USD (1 micro-USD = 1e-6 USD); balance_usd is a rounded display string. Each transaction type is one of topup, debit, refund, or adjustment.
Response 200 OK
{
"balance_micros": 4992500,
"balance_usd": "4.9925",
"currency": "usd",
"transactions": [
{
"type": "debit",
"amount_micros": -7500,
"balance_after_micros": 4992500,
"run_id": 42,
"description": "run 42 inference",
"created_at": "2026-03-27T10:00:00Z"
}
]
}Get Plans
GET /billing/plans
curl \
https://api.m8tes.ai/api/v2/billing/plans?include_free=trueResponse 200 OK
[
{"slug": "free", "display_name": "Hobby", "included_runs": 150, "monthly_price_cents": 0, "annual_price_cents": 0, "inference_mode": "own_subscription", "overage_available": false, "overage_rate_cents": 200, "fair_use_cost_limit_cents": 50000, "max_concurrent_runs": 10},
{"slug": "individual", "display_name": "Individual", "included_runs": 1000, "monthly_price_cents": 2000, "annual_price_cents": 20000, "inference_mode": "own_subscription", "overage_available": false, "overage_rate_cents": 200, "fair_use_cost_limit_cents": 50000, "max_concurrent_runs": 25},
{"slug": "pro", "display_name": "Teams", "included_runs": 500, "monthly_price_cents": 100000, "annual_price_cents": 1000000, "inference_mode": "platform", "overage_available": true, "overage_rate_cents": 200, "fair_use_cost_limit_cents": 75000, "max_concurrent_runs": 50},
{"slug": "max_5x", "display_name": "Teams", "included_runs": 2000, "monthly_price_cents": 300000, "annual_price_cents": 3000000, "inference_mode": "platform", "overage_available": true, "overage_rate_cents": 200, "fair_use_cost_limit_cents": 300000, "max_concurrent_runs": 75},
{"slug": "max_20x", "display_name": "Teams", "included_runs": 5000, "monthly_price_cents": 500000, "annual_price_cents": 5000000, "inference_mode": "platform", "overage_available": true, "overage_rate_cents": 200, "fair_use_cost_limit_cents": 750000, "max_concurrent_runs": 100}
]List Receipts
GET /billing/receipts
curl \
https://api.m8tes.ai/api/v2/billing/receipts \
-H "Authorization: Bearer m8_your_key_here"Update Alert Settings
PATCH /billing/alert-settings
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/billing/alert-settings \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"low_balance_threshold_cents": 2000}'Update Auto Reload
PATCH /billing/auto-reload
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/billing/auto-reload \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"enabled": true,"threshold_cents": 500,"amount_cents": 2000}'Update Overage Settings
Opt in/out of usage overage and set the monthly spend cap (cents, max $10,000). The response echoes the full usage payload (the same shape as GET /usage).
PATCH /billing/overage
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/billing/overage \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"enabled": true,"monthly_cap_cents": 5000}'Response 200 OK
{
"plan": "trial",
"runs_used": 2,
"runs_limit": 50,
"cost_used": "0.12",
"cost_limit": "20.00",
"period_end": "2026-03-27T10:00:00Z",
"free_path_available": true,
"overage_enabled": false,
"overage_used_cents": 0,
"overage_cap_cents": 0,
"overage_rate_cents": 200,
"trial_ends_at": "2026-04-01T10:00:00Z",
"unlimited_runs": false,
"concurrent_runs": 1,
"concurrent_runs_limit": 10
}Get Receipt Invoice
GET /billing/receipts/{receipt_id}/invoice
curl \
https://api.m8tes.ai/api/v2/billing/receipts/{receipt_id}/invoice \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"receipt_id": 7,
"number": "A1B2C3D4-0001",
"invoice_pdf_url": "https://pay.stripe.com/invoice/acct_\u2026/pdf",
"hosted_invoice_url": "https://invoice.stripe.com/i/acct_\u2026"
}Value
Maintain customer-specific use cases inferred from real agent work, attribute run cost, record sourced outcomes, confirm inferred financial claims, and compare verified value with metered platform cost. Pending and unquantified outcomes stay separate from ROI.
Create Use Case
POST /value/use-cases
curl \
-X POST \
https://api.m8tes.ai/api/v2/value/use-cases \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent","goal": "..."}'Get Value Report
GET /value/report
curl \
https://api.m8tes.ai/api/v2/value/report?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"List Use Cases
GET /value/use-cases
curl \
https://api.m8tes.ai/api/v2/value/use-cases?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Use Case
GET /value/use-cases/{use_case_id}
curl \
https://api.m8tes.ai/api/v2/value/use-cases/{use_case_id} \
-H "Authorization: Bearer m8_your_key_here"Update Use Case
PATCH /value/use-cases/{use_case_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/value/use-cases/{use_case_id} \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "support agent"}'Confirm Observation
POST /value/observations/{observation_id}/confirm
curl \
-X POST \
https://api.m8tes.ai/api/v2/value/observations/{observation_id}/confirm \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"decision": "confirmed"}'Create Observation
POST /value/use-cases/{use_case_id}/observations
curl \
-X POST \
https://api.m8tes.ai/api/v2/value/use-cases/{use_case_id}/observations \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"kind": "revenue_generated","evidence_level": "measured","title": "...","evidence": [{"source": "system-of-record","record_id": "record_123"}],"observed_at": "..."}'Link Runs
POST /value/use-cases/{use_case_id}/runs
curl \
-X POST \
https://api.m8tes.ai/api/v2/value/use-cases/{use_case_id}/runs \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"run_ids": []}'List Observations
GET /value/use-cases/{use_case_id}/observations
curl \
https://api.m8tes.ai/api/v2/value/use-cases/{use_case_id}/observations \
-H "Authorization: Bearer m8_your_key_here"Account
Account-level data controls: export all of your account's data, or delete the account and its data (GDPR/CCPA).
Delete Account
DELETE /account
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/account \
-H "Authorization: Bearer m8_your_key_here"Change Password
POST /account/password
curl \
-X POST \
https://api.m8tes.ai/api/v2/account/password \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"current_password": "...","new_password": "..."}'Export Account
GET /account/export
curl \
https://api.m8tes.ai/api/v2/account/export \
-H "Authorization: Bearer m8_your_key_here"Revoke Sessions
Session-authenticated only. An m8_ API key is refused with HTTP 403 — a credential pasted into CI must not be able to sign the account owner out of their browser. Pass a browser/CLI session access token instead.
POST /account/sessions/revoke
curl \
-X POST \
https://api.m8tes.ai/api/v2/account/sessions/revoke \
-H "Authorization: Bearer your_session_token_here"Webhooks
Register URLs to receive signed event notifications when runs change status.
Create Webhook
POST /webhooks
curl \
-X POST \
https://api.m8tes.ai/api/v2/webhooks \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-app.com/webhooks/m8tes","events": ["run.completed"],"user_id": "customer_123"}'Note: The
secretis only returned on creation. Store it securely.
Response 201 Created
{
"id": 2,
"url": "https://your-app.com/webhooks/m8tes",
"events": [
"run.completed"
],
"secret": "a1b2c3d4e5f6...",
"active": true,
"user_id": "customer_123",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-01-15T10:00:00Z"
}List Webhooks
Secrets are masked in list responses.
GET /webhooks
curl \
https://api.m8tes.ai/api/v2/webhooks?user_id=customer_123 \
-H "Authorization: Bearer m8_your_key_here"Get Webhook
GET /webhooks/{webhook_id}
curl \
https://api.m8tes.ai/api/v2/webhooks/2 \
-H "Authorization: Bearer m8_your_key_here"Response 200 OK
{
"id": 2,
"url": "https://your-app.com/webhooks/m8tes",
"events": [
"run.completed"
],
"secret": "a1b2c3d4e5f6...",
"active": true,
"user_id": "customer_123",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-01-15T10:00:00Z"
}Update Webhook
PATCH /webhooks/{webhook_id}
curl \
-X PATCH \
https://api.m8tes.ai/api/v2/webhooks/2 \
-H "Authorization: Bearer m8_your_key_here" \
-H "Content-Type: application/json" \
-d '{"events": ["run.started","run.completed"]}'Response 200 OK
{
"id": 2,
"url": "https://your-app.com/webhooks/m8tes",
"events": [
"run.completed"
],
"secret": "a1b2c3d4e5f6...",
"active": true,
"user_id": "customer_123",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-01-15T10:00:00Z"
}Delete Webhook
DELETE /webhooks/{webhook_id}
curl \
-X DELETE \
https://api.m8tes.ai/api/v2/webhooks/2 \
-H "Authorization: Bearer m8_your_key_here"List Deliveries
View delivery attempts for a webhook endpoint.
GET /webhooks/{webhook_id}/deliveries
curl \
https://api.m8tes.ai/api/v2/webhooks/2/deliveries \
-H "Authorization: Bearer m8_your_key_here"Errors
All errors follow a standard format:
{
"error": {
"type": "not_found",
"message": "Agent not found",
"code": 404,
"request_id": "req_abc123",
"doc_url": "https://www.m8tes.ai/docs/api-errors#error-types"
}
}doc_url links to the docs page for that error type. Include request_id when you contact support.
code is always the HTTP status. When a semantic app code exists (e.g. RUN_LIMIT_REACHED,
TOKEN_BALANCE_DEPLETED, unknown_query_parameter) it is on error.error_code. Branch on
that, never on the message text. error.details.error_code carries the same value for
backward compatibility, alongside any extra context fields.