API Reference

API Reference

All REST endpoints are served through the Gateway.

Base URL: https://gateway.apexmcp.ai

Interactive explorer: https://gateway.apexmcp.ai/docs


Authentication

All /api/* endpoints require Authorization: Bearer <token>.

orgId is always derived from the JWT token — never passed in the request body.

Obtain a token via the client credentials grant:

curl -X POST https://gateway.apexmcp.ai/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=<id>&client_secret=<secret>"

Response:

{
  "access_token": "eyJhbGci...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mcp:call"
}

Pass Authorization: Bearer <access_token> on every subsequent request.

Authentication notes

API keys (OAuth2 client credentials) are scoped to an org. The orgId is always derived from the token — never passed in the request. API keys do not have user roles; access is granted at the org level.

User session tokens (Zitadel) carry a role. Role requirements:

Endpoint groupMinimum role
Connectors, tools, approvals, auditcontributor
Webhooksadmin
Billingfinance
MCP protocolany valid token

Connectors

GET /api/connectors

List all active (non-archived) connectors for the authenticated org.

Response:

{
  "connectors": [
    {
      "id": "uuid",
      "name": "production-db",
      "type": "postgresql",
      "status": "active",
      "allow_write": false,
      "allow_ddl": false,
      "created_at": "2024-10-01T09:00:00Z"
    }
  ]
}

GET /api/connectors/{id}

Get a single connector by ID.


PATCH /api/connectors/{id}

Update connector name, config, credentials, or write permissions.

allow_write and allow_ddl are only accepted for DB connector types (postgresql, mysql, mongodb, mssql, oracle). They are silently ignored for other types.

Request body:

{
  "name": "renamed-db",
  "allow_write": true,
  "allow_ddl": false,
  "credential": "new-password"
}

DELETE /api/connectors/{id}

Soft-delete (archive) a connector. Tools are removed from the MCP endpoint on next provision.

Response: { "archived": true, "id": "uuid" }


POST /api/connectors/{id}/revalidate

Re-trigger credential and connectivity validation for an existing connector. Sets status to validating and returns immediately.

Response: { "status": "validating", "id": "uuid" }


MCP Provisioning & Tools

GET /api/mcp/{orgId}/status

Get MCP provisioning status for the org.

Response:

{ "status": "provisioned", "endpoint": "https://mcp.apexmcp.ai/mcp/my-org", "toolCount": 12 }

GET /api/mcp/{orgId}/tools

List all tools exposed on the org’s MCP endpoint, including external MCP tools.

Query params: connector_id — filter to a specific connector.

Response:

{
  "tools": [
    {
      "id": "uuid",
      "tool_name": "query_postgres_orders",
      "enabled": true,
      "requires_approval": false,
      "approval_ttl_seconds": 86400,
      "approval_emails": [],
      "connector_id": "uuid",
      "connector_name": "production-db",
      "connector_type": "postgresql"
    }
  ]
}

PATCH /api/mcp/{orgId}/tools/{toolId}/metadata

Update tool settings: enable/disable, approval gate, TTL, approver emails, name/description overrides.

Request body:

{
  "enabled": true,
  "requires_approval": true,
  "approval_ttl_seconds": 3600,
  "approval_emails": ["alice@example.com", "bob@example.com"],
  "tool_name_override": "get_orders",
  "tool_description_override": "Query orders table",
  "read_only": true
}

Approvals

GET /api/org/approvals

List approval requests for the org. Returns all statuses by default.

Query params:

ParamTypeDescription
statuspending|executing|executed|rejected|failed|expiredFilter by status. Omit for all.
limitintegerDefault: 200, max: 500

Response:

{
  "approvals": [
    {
      "id": "uuid",
      "tool_name": "delete_customer",
      "status": "pending",
      "arguments": { "customer_id": "cus_123" },
      "requested_by": "agent_01abc",
      "decided_by": null,
      "decided_at": null,
      "approver_emails": ["alice@example.com"],
      "created_at": "2024-11-15T14:00:00Z",
      "expires_at": "2024-11-16T14:00:00Z"
    }
  ]
}

POST /api/org/approvals/{id}/approve

Approve a pending tool call and execute it server-side. Records decided_by and decided_at. Writes an approval.approved audit entry.

Authorization: User session tokens must be a listed approver for the tool. API key (client credentials) tokens bypass the email check — org scoping enforced by JWT is sufficient.

Response:

{ "ok": true, "status": "executed", "result": { ... } }

Errors: 403 not an approver · 404 not found · 409 not pending


POST /api/org/approvals/{id}/reject

Reject a pending tool call. Same authorization rules as approve.

Response: { "ok": true, "status": "rejected" }


Audit

GET /api/audit

List audit events for the org.

Query params:

ParamTypeDescription
limitintegerDefault: 50, max: 200
actionstringFilter by action (e.g. connector.updated, approval.approved)
daysintegerLookback window in days

GET /api/audit/export-json

Export full audit log as JSON. Admin only.

Query params: redact (boolean), action, days


Billing

GET /api/billing/subscription

Current plan, status, and trial expiry.

GET /api/billing/usage

API call usage for the current billing period.

GET /api/billing/limits

Tier limits (connector count, API call cap, current usage).


Webhooks

Admin role required for all webhook endpoints.

GET /api/org/webhooks

List all registered outbound webhooks.

POST /api/org/webhooks

Register a new outbound webhook. Returns secret (HMAC signing key) only on creation — store it immediately.

Request body:

{
  "url": "https://example.com/hook",
  "events": ["tool.called", "approval.requested", "approval.decided"]
}

Response: 201 Created

{
  "id": "uuid",
  "url": "https://example.com/hook",
  "events": ["tool.called", "approval.requested", "approval.decided"],
  "enabled": true,
  "secret": "wh_abc123...",
  "created_at": "2024-11-15T14:00:00Z"
}

PATCH /api/org/webhooks/{id}

Update URL, events, or enabled state.

DELETE /api/org/webhooks/{id}

Delete a webhook.

Webhook payload format:

{
  "id": "evt_uuid",
  "type": "tool.called",
  "org_id": "uuid",
  "created_at": "2024-11-15T14:32:01Z",
  "data": { ... }
}

Signature headers:

X-ApexMCP-Signature: sha256=<HMAC-SHA256(secret, "<timestamp>.<raw-body>")>
X-ApexMCP-Timestamp: <unix-seconds>
X-ApexMCP-Event: <event-type>

MCP Protocol

POST /mcp/{orgSlug}

The agent-facing MCP JSON-RPC endpoint. Auth via X-Api-Key or Authorization: Bearer.

Supported methods:

  • tools/list — list all available tools
  • tools/call — execute a tool

If a tool requires human approval, the call is held and returns:

{
  "structuredContent": { "status": "pending_approval", "approvalId": "uuid" }
}

Poll check_approval_status (a synthetic tool in the MCP endpoint) to retrieve the outcome.

See Tool Approvals for the full flow.


Error responses

All errors follow a consistent format:

{
  "error": "connector_not_found",
  "message": "No connector found with id conn_xxxx"
}
HTTP StatusMeaning
400Bad request — validation error
401Unauthenticated
403Forbidden — insufficient role or not an approver
404Resource not found
409Conflict — wrong state for operation
422Unprocessable — semantic validation failed
429Rate limited or monthly quota reached
500Internal server error
502Upstream service unavailable