AEOS
--:--:--

API Gateway

The outbound half of the gateway is the Hub's capability resolver; this is the inbound half. Every request passes ten stages — edge limit, match, authenticate, resolve tenant, authorise, rate limit, validate, invoke, normalise, observe — before it reaches a module, and nothing throws: every refusal is a receipt carrying a status, the stage that refused and a sentence. The edge limit is the only ceiling a refused request meets; every other class is reached after authorisation has already passed. The service key scheme is real; Supabase JWT verification is a declared port with nothing wired behind it.

34
Routes
across every version
11
Permissions
4 roles
6
Rate classes
declared ceilings
13
Error codes
one status each

This is not the Hub’s gateway. lib/integration/gateway.tsresolves a capability to a connector — it is the estate’s outbound router and knows nothing about HTTP. This module is the inbound HTTP door, and it reaches external platforms only by asking that resolver. Neither holds a provider client.

HTTP API Gateway34

Reading
v1
Version
1 published
34
Routes
in this version
11
Permissions
role-granted keys
6
Rate classes
ceilings declared

Reading live figures from /api/v1/health…

Rate limits are counted per server process. A multi-instance deployment multiplies every published ceiling by the instance count. Satisfy the RateLimiter port with a shared store before relying on these numbers across instances.

Published Routes34

MethodPathPermissionRate classReturns
GET/api/v1

Version metadata and the route manifest.

PublicpublicGatewayIndex
GET/api/v1/health

Gateway, route, authentication and integration health. Aggregate figures only.

PublicpublicGatewayHealth
GET/api/v1/openapi

The OpenAPI 3.1 document, generated from this route table.

PublicpublicOpenApiDocument
GET/api/v1/config

The GoTrue project URL and publishable key a browser needs to sign in. Public by design; carries no server credential.

PublicpublicGatewayConfig
GET/api/v1/companies

Companies in the caller's tenant, with derived health and counts.

company:readreadCompanySummary[]
GET/api/v1/companies/{id}

One company by id or slug.

company:readreadCompanyDetail
POST/api/v1/companies

Create a company workspace. The blueprint — executives and departments — is generated server-side by the same function the UI uses; projects, agents, knowledge and reports start empty.

company:writewriteCompany
PATCH/api/v1/companies/{id}

Replace a company's editable fields — name, icon, industry, business model, mission, goals and status. The slug is not editable. Requires the company's current updatedAt and refuses with 409 if it has moved.

company:writewriteCompany
DELETE/api/v1/companies/{id}

Remove a company by id or slug. A hard delete: everything the schema owns from it goes with it by cascade — departments, executive seats, workflows and their approval gates, company-scoped activity, and agent execution history. Memory records survive with their company cleared.

company:writewriteRemovedCompany
GET/api/v1/departments

The department roster and its derived state.

company:readreadDepartmentSummary[]
GET/api/v1/agents

The agent fleet roster.

agent:readreadAgentSummary[]
GET/api/v1/workflows

Workflows with their derived lifecycle state.

workflow:readreadWorkflowSummary[]
GET/api/v1/workflows/{id}

One workflow, with stages, tasks and gates.

workflow:readreadWorkflowDetail
POST/api/v1/workflows

Open a workflow from a template. Structure only — no history, no assignees, no progress.

workflow:writewriteWorkflowDetail
POST/api/v1/workflows/{id}/gates/{gateId}

Approve, reject or waive an approval gate. Records the decision and an activity line.

workflow:writewriteWorkflowDetail
POST/api/v1/workflows/{id}/release

Release a draft workflow into running. A no-op on anything but a draft.

workflow:writewriteWorkflowDetail
GET/api/v1/memory

Memory records. Supports a substring query across title and body.

memory:readreadMemoryRecord[]
GET/api/v1/knowledge-graph

Knowledge Graph rollup. Read model only — the graph has no write API by design.

company:readreadGraphRollup
GET/api/v1/decisions

Decision Engine output: recommendations, alerts and the risk register.

analytics:readreadDecisionDigest
GET/api/v1/analytics

Enterprise Intelligence read models: company health, enterprise metrics, agent and workflow performance.

analytics:readreadIntelligenceDigest
GET/api/v1/integrations

The connector estate as the Integration Hub reports it.

integration:readreadIntegrationDigest
GET/api/v1/integrations/health

Connector health and the Hub's own gateway summary.

integration:readreadIntegrationHealth
GET/api/v1/integrations/installs

This tenant's own connector overrides, undecorated. Empty where no durable estate exists yet.

integration:readreadConnectorOverride[]
POST/api/v1/integrations/{key}/lifecycle

Run one lifecycle operation — install, enable, disable, configure, reconnect, remove, fork or drop a connection, update, rollback — against one connector, durably.

integration:writedispatchLifecycleOutcome
POST/api/v1/integrations/{key}/{capability}

Route a capability call through the Integration Hub. The gateway never names a provider — the Hub resolves which connector serves it.

integration:writedispatchDispatchOutcome
GET/api/v1/marketplace/plugins

The plugin catalogue: every manifest the Plugin Registry holds, plus the declared integration classes that have none.

integration:readreadMarketplaceCatalogue
GET/api/v1/marketplace/plugins/{key}

One plugin in full, with its compatibility, dependency and permission reports and a dry-run install pre-flight.

integration:readreadMarketplacePlugin
GET/api/v1/marketplace/installed

Plugins installed in this tenant's estate.

integration:readreadMarketplaceCatalogue
POST/api/v1/marketplace/install

Run the install pre-flight — manifest, compatibility, dependencies, permissions, visibility — and the lifecycle transition. Returns the outcome; does not persist.

integration:writedispatchMarketplaceOutcome
POST/api/v1/marketplace/uninstall

Remove a plugin from the estate. Its manifest stays in the registry. Returns the outcome; does not persist.

integration:writedispatchMarketplaceOutcome
POST/api/v1/marketplace/update

Take a plugin's published version. Never automatic — this route is the explicit operator action. Returns the outcome; does not persist.

integration:writedispatchMarketplaceOutcome
POST/api/v1/runtime/executions

Execute a registered agent through the AI Runtime. Returns the structured execution result — every admission gate, the lifecycle state reached, and the Hub's own dispatch outcome.

agent:executedispatchExecutionResult
POST/api/v1/orchestrator/runs

Create a Task Orchestrator run. The run is queued as `pending` with the due time you supply; it is not claimed, leased or executed by this call. Attribution is always the calling principal — delegation is not supported.

workflow:writewriteCreatedRun
POST/api/v1/webhooks/{tenant}/{company}/{ref}

Inbound delivery. Authenticated by provider signature inside the Webhook Manager's pipeline, not by a gateway credential.

PublicinboundWebhookReceipt

5 routes are public. Every other route requires both a role that grants its permission and a credential whose scopes do not exclude it — scopes intersect with the role and can only narrow it, so a key can never grant more than its holder has.

Permissions by Role11

Permissionvieweroperatoradminowner
company:read

Companies, departments, executives and the knowledge graph projection.

company:write

Held by `companies.create` and `companies.remove` as of §33 P2. No permission was minted for them: this one already existed and is granted to ADMIN only, so creating a company is an administrator's act.

··
agent:read

The agent roster and its derived state.

agent:execute

Run a registered agent through the AI Runtime. Required by runtime.execute — the reservation this permission was written for, now taken up.

·
workflow:read

Workflows, stages, tasks and approval gates.

workflow:write

Reserved. Start, pause, cancel and retry land here when the engine has a server store.

·
memory:read

Memory records across every scope the caller may see.

memory:write

Reserved.

··
integration:read

The connector estate, its health and its event routing.

integration:write

Route a capability call through the Integration Hub to a connector.

·
analytics:read

Enterprise Intelligence read models and the Decision Engine's outputs.

Rate Classes6

  • edgeEdge (pre-authentication)1,200 per 60s

    Applied per client address before the route is matched or the credential is read. The only ceiling that covers a request the gateway REFUSES — every other class is reached after match, authentication, tenancy and authorisation have all passed, so without this one a caller could send unlimited 401s and 404s. Deliberately well above any per-route ceiling: it bounds abuse, it does not shape traffic.

  • publicPublic120 per 60s

    Unauthenticated routes. Keyed by client address, because there is no principal to key on.

  • readRead600 per 60s

    Read models are computed in-process from static rosters; the ceiling exists to bound a runaway caller, not to protect a database.

  • writeWrite60 per 60s

    Reserved for the write routes v1 does not yet publish.

  • dispatchIntegration dispatch30 per 60s

    Lowest ceiling in the table. A dispatch becomes a real external call the moment the Hub's seam is wired, and every connector has its own rate ceiling behind this one.

  • inboundInbound webhook1,200 per 60s

    High by design. A platform retry storm that gets rate-limited turns into a longer retry storm; the Webhook Manager's own dedupe ledger is the real defence.

Rate limits are counted per server process. A multi-instance deployment multiplies every published ceiling by the instance count. Satisfy the RateLimiter port with a shared store before relying on these numbers across instances.

Error Catalogue13

CodeStatusRetryableMeaning
unsupported_version404finalThat API version does not exist.
not_found404finalNo route matches that path.
method_not_allowed405finalThat method is not allowed on this route.
unauthenticated401finalAuthentication is required.
forbidden403finalThis credential does not hold the permission this route requires.
tenant_mismatch403finalThat resource belongs to another tenant.
unsupported_media_type415finalThe request body must be application/json.
payload_too_large413finalThe request body exceeds the maximum accepted size.
invalid_request400finalThe request failed validation.
conflict409finalThe resource changed since it was read.
rate_limited429retryToo many requests. Retry after the interval given.
upstream_unavailable503retryA module this route depends on could not answer.
internal500retryThe gateway could not complete the request.

The status is a property of the code rather than a choice made at the refusal site, so whether a client retries is decided once in a table a reviewer can read. Nothing in the gateway throws — every refusal is a receipt carrying one of these codes.

Versions1

  • v1v1current34 routes

    The first published surface. Read routes over the platform read models, plus capability dispatch through the Integration Hub.

A version is a field on a route, not a directory tree. Introducing v2 is a second row here plus routes carrying version: "v2" — existing v1 rows are untouched, so v1 cannot break as a side effect of adding v2.