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

# Invite a worker to a channel

> Mapping a channel decides where its traffic routes; this puts the bot in the room, which is the other half and the one Slack will not do by itself. Only a worker's own key can call it, and the invite is made on that worker's own bot token and nothing else. The Worker being added must already be mapped to the room — map first, then invite; an unmapped room is a 409 `channel_not_mapped`. It acts only for a member: the room must already hold the calling worker's bot AND the person who asked — the sender of the calling worker's running turn, read on control, never named in the request. The calling worker never joins a room. Otherwise the call is a 409 whose `reason` says which: `inviter_not_in_channel`, `requester_not_in_channel`, `no_human_requester` (nobody's request is running — a scheduled run, a webhook) or `requester_unclear` (more than one is). A person in the room can then add the worker themselves: `/invite @worker` in the channel, or the channel's settings, then Integrations, then Add apps. A bot that is already there answers 200 with `invited: false`, so a retry is safe. The call takes no body; a body naming any field is a 400.



## OpenAPI

````yaml /openapi.json post /api/v1/workers/{id}/channels/{channel}/invite
openapi: 3.1.0
info:
  title: Ergoly platform API
  version: 1.0.0
  description: >-
    Read and change one organization's own Ergoly environment. Every route is
    scoped to the organization the presented credential resolves to; there is no
    parameter that widens it. The human-readable reference is served from the
    same namespace at `/api/v1/docs`, behind the same credential.


    The namespace's front door is `GET /api/v1`, and it is deliberately absent
    from `paths` below. It answers without a credential — what this API is, how
    an organization admin mints a key, and where the reference lives — so it is
    the way in to this contract rather than a part of it: it has no scope, takes
    no parameters, and there is nothing about it for a generated client to call.
    Every `unauthorized` refusal carries that same URL as `error.docs`.
servers:
  - url: https://control.ergoly.ai
security:
  - orgApiKey: []
tags:
  - name: auth
    description: How to present a key, what it is scoped to, and what a 401 means.
  - name: organization
    description: Which organization your credential resolves to.
  - name: workers
    description: The Slack apps and bot identities in your organization.
  - name: eworks
    description: The runtime instances under a Worker — one core, one per bound Client.
  - name: clients
    description: The customers a Worker can be scoped to, and how to bind one.
  - name: channels
    description: Which Slack rooms a Worker answers in, and who it answers as.
  - name: tasks
    description: >-
      Tasks handed between Workers and people, scheduled jobs, their targets,
      and their run history.
  - name: jobs
    description: How a provisioning run is going — the other half of every 202.
  - name: memory
    description: Read and write the memory tiers an ework mounts.
  - name: connections
    description: The credentials your agents use, and the hosts they are injected on.
  - name: webhooks
    description: Inbound URLs an outside system can POST to, each of which starts a turn.
  - name: activity
    description: Your organization's audit feed.
  - name: usage
    description: Cost, turn outcomes and a per-day pulse over a window you choose.
  - name: errors
    description: The closed set of refusal codes, and what to do about each.
paths:
  /api/v1/workers/{id}/channels/{channel}/invite:
    post:
      tags:
        - channels
      summary: Invite a worker to a channel
      description: >-
        Mapping a channel decides where its traffic routes; this puts the bot in
        the room, which is the other half and the one Slack will not do by
        itself. Only a worker's own key can call it, and the invite is made on
        that worker's own bot token and nothing else. The Worker being added
        must already be mapped to the room — map first, then invite; an unmapped
        room is a 409 `channel_not_mapped`. It acts only for a member: the room
        must already hold the calling worker's bot AND the person who asked —
        the sender of the calling worker's running turn, read on control, never
        named in the request. The calling worker never joins a room. Otherwise
        the call is a 409 whose `reason` says which: `inviter_not_in_channel`,
        `requester_not_in_channel`, `no_human_requester` (nobody's request is
        running — a scheduled run, a webhook) or `requester_unclear` (more than
        one is). A person in the room can then add the worker themselves:
        `/invite @worker` in the channel, or the channel's settings, then
        Integrations, then Add apps. A bot that is already there answers 200
        with `invited: false`, so a retry is safe. The call takes no body; a
        body naming any field is a 400.
      operationId: inviteWorkerBot
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            The Worker whose bot should be added. A malformed id answers 404,
            exactly as another organization's well-formed id does.
          schema:
            type: string
            description: >-
              The Worker whose bot should be added. A malformed id answers 404,
              exactly as another organization's well-formed id does.
        - name: channel
          in: path
          required: true
          description: >-
            The room to add it to — an id (`C…`/`G…`) or a name (`ops`). See
            *Naming a room* above.
          schema:
            type: string
            description: >-
              The room to add it to — an id (`C…`/`G…`) or a name (`ops`). See
              *Naming a room* above.
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Any unique string. A retry under the same key is answered from the
            first attempt's record, with `X-Idempotent-Replay: true`. The same
            key with a different body is a conflict.
          schema:
            type: string
            description: Any unique string.
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/InvitedBot'
                required:
                  - data
                additionalProperties: false
              example:
                data:
                  workerId: 8f1c2d3e-9a4b-4c5d-8e6f-1a2b3c4d5e6f
                  slackChannelId: C0A1B2C3D4E
                  botUserId: U0B1C2D3E4F
                  invited: true
                  alreadyInChannel: false
                  method: bot_token
                  joined: false
                  requestedBy: U0A1B2C3D4E
        '400':
          description: '`invalid_request`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: '`unauthorized`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: '`not_found`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: '`conflict`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: '`rate_limited`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: '`upstream_error`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - orgApiKey:
            - workers:write
components:
  schemas:
    InvitedBot:
      type: object
      properties:
        workerId:
          type: string
          description: The Worker whose bot was added.
        slackChannelId:
          type: string
          description: The channel it was added to.
        botUserId:
          type: string
          description: That Worker's bot user id, as Slack knows it.
        invited:
          type: boolean
          description: Did this call add it? False when it was a member already.
        alreadyInChannel:
          type: boolean
          description: It was already there, so nothing was done.
        method:
          type:
            - string
            - 'null'
          description: >-
            How the calling Worker's own bot did it — `bot_token` (it invited
            the bot). Null when nothing had to be done.
        joined:
          type: boolean
          description: >-
            Always false: the calling Worker's bot never joins a room. It
            invites only into a room it AND the person who asked are already in,
            and that is already mapped for the Worker being added; otherwise the
            call is refused (409, `reason` `inviter_not_in_channel`,
            `requester_not_in_channel` or `channel_not_mapped`).
        requestedBy:
          type: string
          description: >-
            The Slack id of the person the invite was made for: the sender of
            the calling Worker's running turn, read on control. Never a request
            field — the call takes no body, and a body naming any field is a
            400.
      required:
        - workerId
        - slackChannelId
        - botUserId
        - invited
        - alreadyInChannel
        - method
        - joined
        - requestedBy
      additionalProperties: false
    Error:
      type: object
      description: The one error shape. Every refusal in this namespace has it.
      properties:
        error:
          type: object
          description: The refusal.
          properties:
            code:
              type: string
              enum:
                - unauthorized
                - not_found
                - invalid_request
                - conflict
                - quota_exceeded
                - rate_limited
                - upstream_error
                - gone
              description: The machine-stable half. Branch on this, never on `message`.
            message:
              type: string
              description: Prose for a human reading a terminal.
            docs:
              type: string
              description: >-
                Where to learn how to authenticate. Present on `unauthorized`
                and on nothing else — it is the one refusal a caller can reach
                with no credential at all, so it is the one that has to say
                where the way in is.
          required:
            - code
            - message
          additionalProperties: false
      required:
        - error
      additionalProperties: false
  securitySchemes:
    orgApiKey:
      type: http
      scheme: bearer
      description: >-
        An organization-scoped API key, minted in control under Settings → API
        keys. Every failure to authenticate answers one identical 401: "Provide
        a valid organization-scoped API key or an active session." Each
        operation names the one scope it is filed under,
        `<resource>:<read|write>`, where the resource is the first path segment
        after `/api/v1/`; a key minted today carries all 22 of them. Scopes are
        RECORDED — on the key and on every audit row — and are not yet enforced:
        no request is refused for want of one.

````

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