ReferenceAPI Reference

API Reference

The complete Mogplex v1 REST contract, including authentication, request types, payloads, response envelopes, errors, repositories, agents, models, sandboxes, automations, runs, and MCP transport.

This page is the complete reference for the versioned Mogplex API.

Base URL: https://www.mogplex.com/api/v1/mogplex

Only routes under /api/v1/mogplex/* are part of the public API. Unversioned /api/* routes used by the Mogplex web app are internal product surfaces and are not an external compatibility contract.

Quickstart

Create a personal access token in Mogplex → Settings → API Keys, then set:

export MOGPLEX_BASE_URL="https://www.mogplex.com/api/v1/mogplex"
export MOGPLEX_TOKEN="mog_..."

List repositories to obtain the repoId used by runs, sandboxes, and automations:

curl -sS \
  -H "Authorization: Bearer $MOGPLEX_TOKEN" \
  "$MOGPLEX_BASE_URL/repos?limit=20"

Start an agent run with a unique idempotency key:

curl -sS \
  -X POST \
  -H "Authorization: Bearer $MOGPLEX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "repoId": "repo-uuid",
    "prompt": "Inspect the failing tests and implement the smallest safe fix.",
    "harness": "codex",
    "baseBranch": "main",
    "createBranch": true,
    "rootDirectory": "apps/web"
  }' \
  "$MOGPLEX_BASE_URL/runs"

Authentication

Send a bearer token on every request:

Authorization: Bearer mog_...

Personal access tokens use the mog_ prefix. The plaintext token is shown once, then stored by Mogplex as a SHA-256 hash. Revoke or replace a token from Settings → API Keys.

The MCP transport also accepts OAuth 2.1 access tokens issued through the browser consent flow. Use a PAT for direct REST integrations. Use OAuth when installing the Mogplex MCP server in a supported local client.

Scopes

ScopeAccess
readList and inspect repositories, agents, models, sandboxes, automations, runs, events, logs, and external MCP server definitions.
writeCreate sandboxes, create or change automations, publish and trigger automations, start runs, and cancel runs.

A valid token without the required scope returns 403 FORBIDDEN.

Rate limits

PAT requests are limited to 60 requests per 60 seconds. Run starts also use shared user limits: 10 per minute, 30 per hour, and 150 per day. A limited response includes Retry-After.

Request conventions

JSON requests must include:

Content-Type: application/json

POST /runs and POST /automations/{automationId}/trigger also require:

Idempotency-Key: <unique value, at most 200 characters>

Reusing the same key with the same logical request returns the original result. Reusing it with a different request returns 409 IDEMPOTENCY_CONFLICT.

List limits are clamped to the documented range. Automation pagination uses an opaque cursor. Send nextCursor unchanged as the next request's cursor.

Response envelopes

Every REST response uses one of these envelopes:

type MogplexApiSuccess<T> = {
  ok: true;
  data: T;
};

type MogplexApiErrorCode =
  | "BAD_REQUEST"
  | "CONFLICT"
  | "FORBIDDEN"
  | "IDEMPOTENCY_CONFLICT"
  | "INTERNAL_ERROR"
  | "NOT_FOUND"
  | "RATE_LIMITED"
  | "SERVICE_UNAVAILABLE"
  | "UNAUTHORIZED";

type MogplexApiError = {
  ok: false;
  error: {
    code: MogplexApiErrorCode;
    message: string;
  };
};

Endpoint index

MethodPathScopePurpose
GET/reposreadList imported repositories.
GET/agentsreadList owned and preset agents.
GET/modelsreadList enabled, reachable models.
GET/sandboxesreadList sandboxes.
POST/sandboxeswriteCreate or reuse a sandbox.
GET/sandboxes/{sandboxId}/logsreadRead sandbox logs and lifecycle events.
GET/automationsreadList cursor-paginated automation summaries.
POST/automationswriteCreate an automation draft.
GET/automations/{automationId}readRead one automation with complete graphs.
PUT/automations/{automationId}writeUpdate metadata or replace the draft graph.
POST/automations/{automationId}/publishwriteValidate and publish the draft.
PUT/automations/{automationId}/modelwriteSet or clear one agent node's model.
POST/automations/{automationId}/triggerwriteTrigger the published automation.
GET/automations/{automationId}/runsreadList recent automation runs.
GET/automations/{automationId}/runs/{runId}readRead detailed automation run logs.
POST/runswriteStart a Codex or Claude Code run.
GET/runs/{runId}readRead run state.
GET/runs/{runId}/eventsreadRead structured run events.
POST/runs/{runId}/cancelwriteCancel an active run.
GET/mcp/serversreadList configured external MCP servers.
POST/mcpOAuth or PATUse Mogplex through Streamable HTTP MCP.
OPTIONS/mcpNonePerform an allowed CORS preflight.
GET/mcpNoneReturns 405; the transport accepts messages over POST.

Repositories

List repositories

GET /repos

Request query:

type ListReposQuery = {
  q?: string;       // Case-insensitive substring of owner/repo.
  limit?: number;   // 1 to 200. Default: 100.
};

Response payload:

type MogplexApiRepo = {
  id: string;
  full_name: string;
  installation_id: number;
  default_branch: string | null;
  root_directory: string | null;
};

type ListReposData = {
  repos: MogplexApiRepo[];
};

Use id as repoId. Use installation_id when creating an automation.

Agents

List agents

GET /agents

No query or body.

Response payload:

type MogplexApiAgent = {
  id: string;
  name: string;
  slug: string | null;
  model: string;
  description: string | null;
  category: string | null;
  preset: boolean;
};

type ListAgentsData = {
  agents: MogplexApiAgent[];
};

Preset ids use the preset: prefix. Bind an available agent id to an automation agent node before publishing.

Models

List models

GET /models

No query or body.

Response payload:

type MogplexApiModel = {
  id: string;
  provider: string;
  name: string;
  contextLength: number | null;
  capabilities: string[];
  pricing: {
    input: number | null;
    output: number | null;
  };
};

type ListModelsData = {
  models: MogplexApiModel[];
};

The list already applies catalog visibility, the user's enabled-state policy, provider keys, and plan-backed managed access.

Sandboxes

type MogplexApiSandbox = {
  id: string;
  sandbox_id: string | null;
  repo_id: string;
  status: string;
  base_branch: string;
  working_branch: string;
  root_directory: string | null;
  preview_url: string | null;
  created_at: string;
  last_active_at: string;
  error: string | null;
};

Use the Mogplex record id, not the provider sandbox_id, when requesting logs.

List sandboxes

GET /sandboxes

Request query:

type ListSandboxesQuery = {
  repo_id?: string;
  status?: string;
  limit?: number;   // 1 to 200. Default: 100.
};

Response payload: { sandboxes: MogplexApiSandbox[] }.

Create or reuse a sandbox

POST /sandboxes

Request body:

type CreateSandboxRequest = {
  repoId: string;
  baseBranch?: string | null;
  workingBranch?: string | null;
  createBranch?: boolean;
  rootDirectory?: string | null;
  restoreSnapshotId?: string | null;
  restoreSnapshotProjectId?: string | null;
  restoreSnapshotTeamId?: string | null;
};

Example payload:

{
  "repoId": "repo-uuid",
  "baseBranch": "main",
  "workingBranch": "agent/update-api-docs",
  "createBranch": true,
  "rootDirectory": "apps/web"
}

The response is 202 Accepted with { sandbox: MogplexApiSandbox }. Branch names must be valid Git refs. rootDirectory must be a relative path without parent traversal.

Read sandbox logs

GET /sandboxes/{sandboxId}/logs

No query or body.

Response payload:

type SandboxLogsData = {
  sandbox: MogplexApiSandbox & {
    install_log: string | null;
    dev_log: string | null;
  };
  lifecycle_events: Array<{
    id: string;
    event_type: string;
    decision_code: string | null;
    worker_run_id: string | null;
    payload: Record<string, unknown>;
    created_at: string;
  }>;
};

Automations

Automation list responses are bounded and graph-free. The item response owns the complete draft and published graphs.

Graph request type

graph is always a complete replacement, not a patch:

type FlowNodeType =
  | "start"
  | "agent"
  | "condition"
  | "parallel"
  | "join"
  | "delay"
  | "await_event"
  | "set_variable"
  | "end";

type FlowGraphRequest = {
  nodes: Array<{
    id: string;
    type: FlowNodeType;
    position: { x: number; y: number };
    data: Record<string, unknown>;
  }>;
  edges: Array<{
    id: string;
    source: string;
    target: string;
    sourceHandle?: string | null;
    targetHandle?: string | null;
  }>;
  viewport?: {
    x: number;
    y: number;
    zoom: number; // Finite and greater than zero.
  };
};

nodes and edges are required arrays. null, strings, partial objects, and malformed viewports return 400 BAD_REQUEST before an existing draft is changed. Publishing applies stricter executable-graph validation.

Automation response types

type MogplexApiAutomationSummary = {
  id: string;
  installationId: number;
  name: string;
  description: string | null;
  status: "active" | "inactive";
  publishedVersionId: string | null;
  createdAt: string;
  updatedAt: string;
};

type MogplexApiAutomation = {
  id: string;
  installationId: number;
  name: string;
  description: string | null;
  notes: string | null;
  status: "active" | "inactive";
  draftGraph: FlowGraphRequest;
  publishedVersion: {
    id: string;
    versionNumber: number;
    graph: FlowGraphRequest;
    createdAt: string;
  } | null;
  createdAt: string;
  updatedAt: string;
  runSummary: {
    lastRunId: string | null;
    lastRunStatus: string | null;
    runningCount: number;
    pendingCount: number;
    failed24h: number;
  };
};

List automations

GET /automations

Request query:

type ListAutomationsQuery = {
  limit?: number;   // 1 to 100. Default: 50.
  cursor?: string;  // Opaque nextCursor from the previous page.
};

Response payload:

type ListAutomationsData = {
  automations: MogplexApiAutomationSummary[];
  nextCursor: string | null;
};

Create an automation

POST /automations

Request body:

type CreateAutomationRequest = {
  installationId: number; // Required positive safe integer.
  name?: string;
  description?: string | null;
  notes?: string | null;
  graph?: FlowGraphRequest;
  publish?: boolean;
};

Example metadata-first payload:

{
  "installationId": 12345678,
  "name": "Review pull requests",
  "description": "Review new pull requests and report actionable findings.",
  "publish": false
}

The response is 201 Created with { automation: MogplexApiAutomation }. When graph is omitted, Mogplex creates its default draft. Set publish: true only when the draft is ready for full executable validation.

Get an automation

GET /automations/{automationId}

No query or body. Response payload: { automation: MogplexApiAutomation }.

Update an automation

PUT /automations/{automationId}

Request body:

type UpdateAutomationRequest = {
  name?: string;
  description?: string | null;
  notes?: string | null;
  installationId?: number; // Positive safe integer when present.
  graph?: FlowGraphRequest; // Complete draft replacement.
};

Omitted fields remain unchanged. If graph is present, Mogplex validates the entire graph before calling the draft update service. Response payload: { automation: MogplexApiAutomation }.

Publish an automation

POST /automations/{automationId}/publish

No request body. The draft must contain exactly one start node, exactly one end node, at least one bound agent node, valid connections and node configuration, and available explicit model overrides.

Response payload: { automation: MogplexApiAutomation }.

Set an automation model

PUT /automations/{automationId}/model

Request body:

type SetAutomationModelRequest = {
  nodeId: string;
  modelId: string | null; // null clears the override.
  publish?: boolean;
};

Example payload:

{
  "nodeId": "agent-review",
  "modelId": "provider/model-id",
  "publish": false
}

The node must exist and have type agent. A non-null model must appear in GET /models. Response payload: { automation: MogplexApiAutomation }.

Trigger an automation

POST /automations/{automationId}/trigger

Requires Idempotency-Key.

Request body:

type TriggerAutomationRequest = {
  repoId: string;
  input?: Record<string, unknown>;
};

Example payload:

{
  "repoId": "repo-uuid",
  "input": {
    "pull_request_number": 699
  }
}

The automation must be active and published. The repository must belong to the same GitHub installation. The response is 202 Accepted:

type TriggerAutomationData = {
  run: {
    automationId: string;
    jobRunId: string | null;
    outcome: string;
    reason: string | null;
    started: boolean;
    status: string;
    runtime: {
      provider: string | null;
      runId: string | null;
    } | null;
  };
};

List automation runs

GET /automations/{automationId}/runs

Request query:

type ListAutomationRunsQuery = {
  limit?: number; // 1 to 50. Default: 20.
};

Response payload: { runs: AutomationRunSummary[] }. Each record includes the job status, repository and agent summary, token and cost totals, latest dispatch event, and node-run summaries.

Read automation run logs

GET /automations/{automationId}/runs/{runId}

No query or body. Response payload: { run: AutomationRunDetail | null }. The detail includes node runs, dispatch events, AI calls and events, errors, usage, and review findings.

Agent runs

type MogplexApiRunStatus =
  | "pending"
  | "streaming"
  | "success"
  | "failed"
  | "cancelled";

type MogplexApiRunDetail = {
  runId: string;
  aiCallId: string;
  sandboxRecordId: string | null;
  sandboxId: string | null;
  repoId: string;
  harness: "codex" | "claude-code";
  status: MogplexApiRunStatus;
  branch: {
    base: string;
    working: string;
    createBranch: boolean;
  };
  rootDirectory: string | null;
  eventsUrl: string;
  cancelUrl: string;
  createdAt: string;
  updatedAt: string;
  error: string | null;
  runtime: {
    provider: string | null;
    runId: string | null;
  };
};

Start a run

POST /runs

Requires Idempotency-Key.

Request body:

type StartRunRequest = {
  repoId: string;
  prompt: string; // At most 100,000 characters.
  harness?: "codex" | "claude-code"; // Default: codex.
  baseBranch?: string;
  workingBranch?: string;
  createBranch?: boolean;
  rootDirectory?: string | null;
  conversationId?: string;
  workspaceSessionId?: string;
  mode?: string;
};

The response is 202 Accepted with MogplexApiRunDetail & { replayed: boolean } inside data.

When createBranch is true and workingBranch is omitted, Mogplex creates a deterministic branch name from the idempotency key and request. If supplied, the working branch must differ from the base branch.

Get a run

GET /runs/{runId}

No query or body. Response payload: { run: MogplexApiRunDetail }.

List run events

GET /runs/{runId}/events

Request query:

type ListRunEventsQuery = {
  limit?: number; // 1 to 200. Default: 100.
};

Response payload:

type PresentedAiCallEvent = {
  id: string;
  type: string;
  toolName: string | null;
  message: string | null;
  payload: Record<string, unknown>;
  createdAt: string;
};

type RunEventsData = {
  run: MogplexApiRunDetail;
  events: PresentedAiCallEvent[];
};

Event payloads are sanitized, sensitive fields are redacted, and oversized values are truncated. Use this endpoint for explicit inspection. Do not build an interval loop around it; prefer Mogplex's event-driven GitHub, Slack, and automation surfaces when another system needs completion signals.

Cancel a run

POST /runs/{runId}/cancel

No request body. Cancellation is idempotent.

Response payload:

type CancelRunData = {
  run: MogplexApiRunDetail;
  status: MogplexApiRunStatus;
  alreadyTerminal: boolean;
};

External MCP servers

List configured external MCP servers

GET /mcp/servers

No query or body.

Response payload:

type MogplexApiMcpServer = {
  name: string;
  enabled: boolean;
  config: Record<string, unknown>;
};

type ListMcpServersData = {
  servers: MogplexApiMcpServer[];
};

Common config shapes:

type StdioMcpConfig = {
  command: string;
  args?: string[];
  env?: Record<string, string>;
};

type HttpMcpConfig = {
  url: string;
  http_headers?: Record<string, string>;
};

This response can contain vault-resolved environment values and authorization headers. Treat it like a secret file. Do not log it or expose it in CI output.

This endpoint lists third-party MCP servers configured in the caller's Mogplex account. It is different from the Mogplex MCP transport below.

MCP transport

POST /mcp

The Mogplex MCP server uses stateless Streamable HTTP and JSON-RPC 2.0 at:

https://www.mogplex.com/api/v1/mogplex/mcp

Use Install Mogplex MCP for client setup and OAuth. Use MCP tools for all 19 tool argument schemas.

Request envelope:

type JsonRpcRequest = {
  jsonrpc: "2.0";
  id?: string | number | null;
  method:
    | "initialize"
    | "notifications/initialized"
    | "ping"
    | "tools/list"
    | "tools/call";
  params?: Record<string, unknown>;
};

Direct tool-call payload:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "mogplex_list_automations",
    "arguments": {
      "limit": 20
    }
  }
}

Response envelopes:

type JsonRpcId = string | number | null;

type JsonRpcSuccess<T> = {
  jsonrpc: "2.0";
  id: JsonRpcId;
  result: T;
};

type JsonRpcError = {
  jsonrpc: "2.0";
  id?: JsonRpcId;
  error: {
    code: number;
    message: string;
    data?: unknown;
  };
};

type McpToolResult = {
  content: Array<{ type: "text"; text: string }>;
  structuredContent?: Record<string, unknown>;
  isError: boolean;
};

An initialize request returns server capabilities and the negotiated protocol version inside a JSON-RPC success envelope:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": { "tools": { "listChanged": false } },
    "serverInfo": { "name": "mogplex", "version": "0.1.0" }
  }
}

A successful tool call returns human-readable content and structured JSON:

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "content": [
      { "type": "text", "text": "Found 0 Mogplex automation summaries." }
    ],
    "structuredContent": { "automations": [] },
    "isError": false
  }
}

Notifications do not have an id and return HTTP 202 with no response body.

MCP errors

Transport and JSON-RPC failures use the JSON-RPC error envelope, not the REST error envelope documented below:

{
  "jsonrpc": "2.0",
  "id": 42,
  "error": {
    "code": -32602,
    "message": "repoId: Required"
  }
}
JSON-RPC codeHTTPMeaning
-32700400The request body is not valid JSON.
-32600400The body is not a valid JSON-RPC request.
-32601200The requested method or tool does not exist.
-32602200Tool arguments are missing or invalid.
-32001401OAuth or PAT authorization is missing or invalid.
-32002429The authentication rate limit was exceeded.
-32003403A browser request came from a forbidden origin.
-32603200An unexpected MCP message failure occurred.

An underlying Mogplex operation can fail after a valid tools/call. That is a tool result rather than a transport failure, so the HTTP response remains 200 and result.isError is true:

{
  "jsonrpc": "2.0",
  "id": 43,
  "result": {
    "content": [
      { "type": "text", "text": "Run not found. List repos or runs again and pass an id owned by this token." }
    ],
    "structuredContent": {
      "error": {
        "code": "NOT_FOUND",
        "status": 404,
        "message": "Run not found",
        "suggestion": "List repos or runs again and pass an id owned by this token."
      }
    },
    "isError": true
  }
}

Send Accept: application/json, text/event-stream. The endpoint also accepts OPTIONS for CORS preflight. GET returns 405 Method Not Allowed.

Errors

CodeHTTPMeaningAction
BAD_REQUEST400JSON, query, graph, branch, or field validation failed.Correct the request before retrying.
UNAUTHORIZED401Bearer token is missing, invalid, expired, revoked, or has the wrong OAuth audience.Authenticate again or replace the token.
FORBIDDEN403The token lacks the required scope.Issue a token with the required scope.
NOT_FOUND404The user does not own the requested resource, or it does not exist.Verify the id using a list endpoint.
CONFLICT409Current resource state prevents the operation.Read the resource, then decide whether the operation still applies.
IDEMPOTENCY_CONFLICT409The key was already used for a different request.Use the original body or a new key.
RATE_LIMITED429A PAT or run-start limit was exceeded.Honor Retry-After.
INTERNAL_ERROR500An unexpected server error occurred.Preserve the request id and report the failure.
SERVICE_UNAVAILABLE503A required runtime or rate-limit service is unavailable.Honor Retry-After when present.

MCP uses its own JSON-RPC error contract instead of this REST envelope.

Edit on GitHub

On this page