> ## 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.

# Create a Slack channel

> Opens a Slack channel on the CALLING worker's own identity, so only a worker's key can call it. It creates the room, maps the caller, maps then invites each of `workers`, and invites the person who asked — the sender of the caller's running turn, never a body field — then `people`. With no person asking it is a 409 before any room exists. Each of `people` must be a person of the org's own Slack, else a 409 (`person_outside_org`, `person_not_a_person`, `person_lookup_failed`) before any room exists. Anyone who could not be brought in is reported, not failed.

**A `client` mapping brings up that Client's ework for each Worker mapped to the room, and spends one of your organization's daily provisioning slots. An `internal` room mints nothing.**



## OpenAPI

````yaml /openapi.json post /api/v1/channels
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/channels:
    post:
      tags:
        - channels
      summary: Create a Slack channel
      description: >-
        Opens a Slack channel on the CALLING worker's own identity, so only a
        worker's key can call it. It creates the room, maps the caller, maps
        then invites each of `workers`, and invites the person who asked — the
        sender of the caller's running turn, never a body field — then `people`.
        With no person asking it is a 409 before any room exists. Each of
        `people` must be a person of the org's own Slack, else a 409
        (`person_outside_org`, `person_not_a_person`, `person_lookup_failed`)
        before any room exists. Anyone who could not be brought in is reported,
        not failed.


        **A `client` mapping brings up that Client's ework for each Worker
        mapped to the room, and spends one of your organization's daily
        provisioning slots. An `internal` room mints nothing.**
      operationId: createChannel
      parameters:
        - 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.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: >-
                    The room's name: lower-case letters, numbers, `-` and `_`,
                    at most 80. A leading `#` is dropped and spaces become
                    hyphens.
                private:
                  type: boolean
                  description: Defaults to `true`.
                mapping:
                  type: object
                  description: >-
                    What the room is for: `internal`, or `client` with the
                    Client's slug or id.
                  properties:
                    kind:
                      type: string
                      enum:
                        - internal
                        - client
                      description: >-
                        `internal` routes the room to each Worker's core ework.
                        `client` routes it to each Worker's ework for that
                        Client.
                    client:
                      type: string
                      description: >-
                        Required when `kind` is `client`: the Client's slug or
                        id.
                  required:
                    - kind
                  additionalProperties: false
                people:
                  type: array
                  items:
                    type: string
                    description: A Slack user id.
                  description: >-
                    The people to bring in, by Slack user id — the org's own
                    people only.
                workers:
                  type: array
                  items:
                    type: string
                    description: A Worker id.
                  description: The Workers to map and bring in.
              required:
                - name
                - mapping
              additionalProperties: false
            example:
              name: acme-renewal
              mapping:
                kind: client
                client: acme
              people:
                - U0A1B2C3D4E
              workers:
                - 8f1c2d3e-9a4b-4c5d-8e6f-1a2b3c4d5e6f
      responses:
        '201':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/CreatedChannel'
                required:
                  - data
                additionalProperties: false
              example:
                data:
                  slackChannelId: G0A1B2C3D4E
                  name: acme-renewal
                  private: true
                  clientSlug: acme
                  requestedBy: U0A1B2C3D4E
                  caller:
                    workerId: 00000000-0000-4000-8000-0000000000c1
                    kind: internal
                    activation: null
                    mapped: true
                    error: null
                  workers:
                    - workerId: 8f1c2d3e-9a4b-4c5d-8e6f-1a2b3c4d5e6f
                      mapped: true
                      activation: already_active
                      invited: true
                      alreadyInChannel: false
                      method: bot_token
                      error: null
                  people:
                    - slackUserId: U0A1B2C3D4E
                      invited: true
                      alreadyInChannel: false
                      error: null
        '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: '`quota_exceeded`, `rate_limited`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuotaError'
        '502':
          description: '`upstream_error`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - orgApiKey:
            - channels:write
components:
  schemas:
    CreatedChannel:
      type: object
      properties:
        slackChannelId:
          type: string
          description: The new room's id.
        name:
          type: string
          description: The name Slack gave it.
        private:
          type: boolean
          description: Whether the room is private.
        clientSlug:
          type:
            - string
            - 'null'
          description: The Client the room's work belongs to; null for an internal room.
        requestedBy:
          type: string
          description: >-
            The Slack id of the person who asked: the sender of the calling
            Worker's running turn, read on control and never a body field.
            Always among `people` — they are brought in first. A call no person
            made (a scheduled run, a webhook) is refused before the room exists
            (409, `reason` `no_human_requester` or `requester_unclear`).
        caller:
          type: object
          description: The calling Worker, which created the room and is in it.
          properties:
            workerId:
              type: string
              description: The calling Worker.
            kind:
              type: string
              enum:
                - internal
                - client
              description: >-
                How the calling Worker is mapped. Always `internal` for an
                internal-only Worker.
            activation:
              type:
                - string
                - 'null'
              description: >-
                For a `client` mapping, whether that Client's ework is serving
                yet.
            mapped:
              type: boolean
              description: Did its mapping land?
            error:
              type:
                - object
                - 'null'
              description: >-
                Why this Worker is not mapped or not in the room. Null when it
                is.
              properties:
                code:
                  type: string
                  description: >-
                    A machine code: a mapping refusal (`internal_only_worker`,
                    `requires_confirmation`, …) or an invite refusal
                    (`invite_refused` — Slack refused, carrying its code, …).
                message:
                  type: string
                  description: What happened, in words to pass on.
              required:
                - code
                - message
              additionalProperties: false
          required:
            - workerId
            - kind
            - activation
            - mapped
            - error
          additionalProperties: false
        workers:
          type: array
          items:
            type: object
            properties:
              workerId:
                type: string
                description: The Worker.
              mapped:
                type: boolean
                description: >-
                  Did its mapping land? A Worker that is not mapped is not
                  invited.
              activation:
                type:
                  - string
                  - 'null'
                description: >-
                  For a `client` mapping, whether that Client's ework is serving
                  yet.
              invited:
                type: boolean
                description: Did this call add its bot?
              alreadyInChannel:
                type: boolean
                description: It was already there.
              method:
                type:
                  - string
                  - 'null'
                description: How the calling Worker's own bot did it — `bot_token`.
              error:
                type:
                  - object
                  - 'null'
                description: >-
                  Why this Worker is not mapped or not in the room. Null when it
                  is.
                properties:
                  code:
                    type: string
                    description: >-
                      A machine code: a mapping refusal (`internal_only_worker`,
                      `requires_confirmation`, …) or an invite refusal
                      (`invite_refused` — Slack refused, carrying its code, …).
                  message:
                    type: string
                    description: What happened, in words to pass on.
                required:
                  - code
                  - message
                additionalProperties: false
            required:
              - workerId
              - mapped
              - activation
              - invited
              - alreadyInChannel
              - method
              - error
            additionalProperties: false
          description: One entry per Worker named in `workers`.
        people:
          type: array
          items:
            type: object
            properties:
              slackUserId:
                type: string
                description: The person.
              invited:
                type: boolean
                description: Did this call add them?
              alreadyInChannel:
                type: boolean
                description: They were already there.
              error:
                type:
                  - string
                  - 'null'
                description: Slack's code when the invite was refused.
            required:
              - slackUserId
              - invited
              - alreadyInChannel
              - error
            additionalProperties: false
          description: >-
            One entry per person brought in: the person who asked, first, then
            each named in `people`.
      required:
        - slackChannelId
        - name
        - private
        - clientSlug
        - requestedBy
        - caller
        - workers
        - people
      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
    QuotaError:
      type: object
      description: >-
        A `quota_exceeded` body. `Retry-After` carries the same wait as a
        header.
      properties:
        error:
          type: object
          description: The refusal, with the numbers a caller needs to back off correctly.
          properties:
            code:
              type: string
              enum:
                - quota_exceeded
              description: Always `quota_exceeded`.
            message:
              type: string
              description: Prose for a human reading a terminal.
            limit:
              type: integer
              description: The ceiling that was hit, in provisioning runs per rolling day.
            resetsAt:
              type: string
              format: date-time
              description: >-
                When the oldest counted run falls out of the window. A lower
                bound — retry then and you may get a fresher answer.
          required:
            - code
            - message
            - limit
            - resetsAt
          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.