> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atako.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Aggregated Agent Floor state (teams, agents, members)

> Single-shot read for the Agent Floor 3D scene: your company's teams (with org-chart positions), non-completed agents (with a derived managerHumanId), and members. Open to any company member — admin and member get the exact same shape. 404 (not 403) when you have no company, so the route is invisible rather than merely blocked. The floor is open to every company.



## OpenAPI

````yaml /api-reference/openapi.json get /floor/state
openapi: 3.1.0
info:
  title: Atako API
  version: 0.1.0
  description: >-
    The Atako customer API — manage AI agents, their files, integrations,
    billing, and your company/team, programmatically.


    ## Authentication


    Every non-public endpoint takes a Bearer token that is either:

    - a **programmatic API key** (`aik_…`) — create one at
    [app.atako.ai](https://app.atako.ai) → Settings → API keys (company-admin
    only), or

    - a **Supabase session JWT** — what the web app itself sends; not practical
    to obtain outside a browser session.


    ```bash

    curl https://api.atako.ai/agents -H "Authorization: Bearer aik_..."

    ```


    An API key acts as its owning user, within the limits of the key:


    - **Scope** — a `read` key can only call GET operations (any other verb:
    `403 API_KEY_READ_ONLY`); a `write` key can call everything its user can,
    except the operations below.

    - **Forbidden to every key** — billing changes (every non-GET
    `/subscriptions/*`), minting agent tokens, listing or managing API keys
    (every `/users/api-keys` operation), deleting the account: `403
    API_KEY_FORBIDDEN`. These need a signed-in user in the app.

    - **Expiry** — optional (30, 90 or 365 days); an expired key gets `401
    API_KEY_EXPIRED`.


    Each operation carries `x-atako-api-key: read | write | forbidden` — the
    minimum key scope it needs, or `forbidden`.


    ## Live events


    `GET /notifications/sse` and `GET /agents/{agentId}/events` are Server-Sent
    Events streams (`text/event-stream`), authenticated with the same Bearer
    header — an API key works.


    ## Uploading a file


    Two steps: `POST /client/files/nodes` then `POST
    /client/files/{nodeId}/upload-url` return a signed storage URL; `PUT` the
    raw bytes to it, then call `POST /client/files/{nodeId}/complete-upload`.
    Grant it to an agent with `POST /agents/{agentId}/file-grants`.


    ## Other Atako HTTP surfaces (not covered by this spec)


    - **Atako MCP server** — `POST /mcp` (auth: same Bearer token as above)
    exposes the same capabilities as Model Context Protocol tools for AI clients
    (Claude Code, Claude Desktop, Cursor, ChatGPT), grouped in toolsets
    (`/mcp?toolsets=projects,agents`); a `read` key only gets read-only tools.
    See
    [docs.atako.ai/developers/mcp/overview](https://docs.atako.ai/developers/mcp/overview).

    - **Content API** (`cak_…` key, `/content/*`) — a separate, more restricted
    key type for headless CMS-style access to blog/news/use-case content. Not
    documented here.


    ## Errors


    Errors use a JSON envelope: `{ "error": string, "code"?: string }`. `error`
    is either a short human-readable message or a SCREAMING_SNAKE_CASE code,
    depending on the route — treat it as an opaque string to match against, not
    a stable enum across the whole API.


    ## Rate limits


    Authenticated routes: 6000 requests/min per user (`authRateLimit`). Public
    GET routes: 60/min per IP. A handful of sensitive public POST routes
    (newsletter signup, email-exists, invitation preview) are limited to 10
    requests / 15 min per IP.


    ## Pagination


    List endpoints use either simple `limit`/`offset` query params (marketing
    content — a plain JSON array response, capped at the documented max) or
    `page`/`limit` (credit transactions). Neither returns a total count today;
    fetch until a page comes back shorter than `limit`.
servers:
  - url: https://api.atako.ai
    description: Production
security: []
tags:
  - name: Agents
  - name: Messages
  - name: Activity
  - name: Agent Options
  - name: API Keys
  - name: Files
  - name: Cron Jobs
  - name: Sub-Agents
  - name: Interagent Messages
  - name: Integrations
  - name: Subscriptions
  - name: Users
  - name: Company
  - name: Teams
  - name: Floor
  - name: Search
  - name: Notices
  - name: Organization
  - name: Projects
  - name: Notifications
  - name: Agent Shared Items
  - name: Agent Email
  - name: Agent Webhooks
  - name: Company Dashboard
  - name: LLM Provider Keys
  - name: Public
  - name: Marketing Content
paths:
  /floor/state:
    get:
      tags:
        - Floor
      summary: Aggregated Agent Floor state (teams, agents, members)
      description: >-
        Single-shot read for the Agent Floor 3D scene: your company's teams
        (with org-chart positions), non-completed agents (with a derived
        managerHumanId), and members. Open to any company member — admin and
        member get the exact same shape. 404 (not 403) when you have no company,
        so the route is invisible rather than merely blocked. The floor is open
        to every company.
      operationId: getFloorState
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FloorState'
        '401':
          description: >-
            Missing, malformed, or invalid bearer token / API key, or revoked
            session (SESSION_REVOKED).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found, or the caller is not authorized to access this resource.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    FloorState:
      type: object
      description: >-
        GET /floor/state — single-shot aggregated read for the Agent Floor 3D
        scene. Nothing stored anew: teams/positions and members come from
        getTeamsByCompanyId/listCompanyMembers, agents from a floor-specific
        minimal query.
      properties:
        teams:
          type: array
          items:
            $ref: '#/components/schemas/FloorTeam'
        agents:
          type: array
          items:
            $ref: '#/components/schemas/FloorAgent'
        members:
          type: array
          items:
            $ref: '#/components/schemas/FloorMember'
        layout:
          allOf:
            - $ref: '#/components/schemas/FloorLayout'
          nullable: true
          description: null = automatic layout (nobody ever moved anything on this floor).
        layoutVersion:
          type: integer
          nullable: true
          description: Optimistic version of the stored layout; null when there is none.
      required:
        - teams
        - agents
        - members
        - layout
        - layoutVersion
    Error:
      type: object
      description: >-
        Atako's standard error envelope. `error` is either a short
        human-readable message or a SCREAMING_SNAKE_CASE code (routes are
        inconsistent about which — treat it as an opaque string and match on it
        exactly if you need to branch on error type). Some routes add extra
        fields alongside `error` (see the operation's own error responses).
      properties:
        error:
          type: string
        code:
          type: string
          description: >-
            Present on some routes; a stable machine-readable code duplicating
            or refining `error`.
      required:
        - error
      additionalProperties: true
    FloorTeam:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        parentId:
          type: string
          format: uuid
          nullable: true
        companyId:
          type: string
          format: uuid
          nullable: true
        lead:
          allOf:
            - $ref: '#/components/schemas/FloorTeamLead'
          nullable: true
          description: >-
            null only when the company has no admin at all — the one case where
            the cascade ends on nobody.
        leadIsDefault:
          type: boolean
          description: >-
            true when the team has no lead of its own and therefore falls back
            on the company's root manager — the same warning the org chart
            shows.
      required:
        - id
        - name
        - parentId
        - companyId
        - lead
        - leadIsDefault
    FloorAgent:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        status:
          type: string
          enum:
            - active
            - completed
            - paused
            - provisioning
            - unresponsive
            - failed
        teamId:
          type: string
          format: uuid
          nullable: true
        avatarSeed:
          type: string
          description: agents.image — mascot filename in apps/web/public/aiygents.
        createdAt:
          type: string
          format: date-time
        lastActivityAt:
          type: string
          format: date-time
          nullable: true
          description: agents.lastHeartbeatAt.
        clientId:
          type: string
          format: uuid
          description: Owner — needed client-side to gate the Retry action to the owner.
        managerHumanId:
          type: string
          format: uuid
          nullable: true
          description: >-
            Unique human holder of the parent teamPositions row of this agent's
            own position; null when the agent holds 0 or several positions, its
            position is a root, or its parent is vacant/agent-held.
        managerSource:
          type: string
          enum:
            - own
            - team
            - company
          nullable: true
          description: >-
            Where managerHumanId comes from: an individual override on the agent
            (own), its team lead or team position (team), or the company root
            manager as a fallback (company).
        engine:
          type: string
          enum:
            - openclaw
            - hermes
            - opencode
          description: >-
            agents.engine — same value GET /agents serves, added here so the web
            no longer needs a parallel GET /agents call just for the floor’s
            harness chip.
      required:
        - id
        - name
        - status
        - teamId
        - avatarSeed
        - createdAt
        - lastActivityAt
        - clientId
        - managerHumanId
        - managerSource
        - engine
    FloorMember:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        title:
          type: string
          nullable: true
        teamId:
          type: string
          format: uuid
          nullable: true
        positions:
          type: array
          items:
            $ref: '#/components/schemas/FloorPosition'
          description: >-
            Every position this member holds (a member may hold several, unlike
            an agent).
        image:
          type: string
          nullable: true
          description: >-
            The member's own photograph (users.photo, a public Supabase Storage
            URL), or null when they never uploaded one — the client then draws
            their monogram.
      required:
        - id
        - name
        - title
        - teamId
        - positions
        - image
    FloorLayout:
      type: object
      description: >-
        Stored floor arrangement (AF-41). Only what the automatic layout cannot
        infer: where each team platform sits, and which desk of its own team an
        occupant stands at. Reconciled at read time — entries whose id is no
        longer on the floor are stripped from the served document (never from
        the stored row).
      properties:
        pods:
          type: array
          items:
            type: object
            properties:
              teamId:
                type: string
                format: uuid
              x:
                type: number
                description: Pod centre, world units.
              z:
                type: number
            required:
              - teamId
              - x
              - z
        agents:
          type: array
          description: >-
            id = agentId, slot = desk index inside the pod of ITS OWN team (slot
            0 of team A and slot 0 of team B are different desks).
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              slot:
                type: integer
            required:
              - id
              - slot
        members:
          type: array
          description: id = userId, same slot semantics as `agents`.
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              slot:
                type: integer
            required:
              - id
              - slot
      required:
        - pods
        - agents
        - members
    FloorTeamLead:
      type: object
      description: >-
        The team's accountable lead, already resolved through the organisation
        cascade (explicit lead, else the company's root admin) and named — never
        the raw lead_user_id/lead_agent_id columns.
      properties:
        kind:
          type: string
          enum:
            - human
            - agent
        id:
          type: string
          format: uuid
        name:
          type: string
      required:
        - kind
        - id
        - name
    FloorPosition:
      type: object
      properties:
        teamId:
          type: string
          format: uuid
        positionId:
          type: string
          format: uuid
        title:
          type: string
      required:
        - teamId
        - positionId
        - title
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An `aik_…` programmatic API key (app.atako.ai → Settings → API keys) or
        a Supabase session JWT.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.