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

# Set agent access

> Grant or revoke this agent's access to Claudia projects and Eddie workspaces. Administrator only. Each dimension — `claudia_projects` and `eddie_workspaces` — is optional and independently declarative: send it as the full set you want that dimension to hold, drawn from your own `manageable` ceiling (see getAgentAccess) — items you leave out of a dimension you send are revoked, items you add are granted; a dimension you omit from the request entirely is left untouched. You can only grant or revoke within your own ceiling: items the target already holds outside it are preserved, never touched by your request. Naming an item outside your ceiling is refused with 422 (`outside_ceiling`, field names the offending dimension). The target's CloudChat role must be `administrator` or `cx_engineer`, or the whole request is refused with 422 (`ineligible_role`, field `agent`). An all-empty request (revoking everything) is accepted regardless of the target's role — it is the cleanup path for an agent demoted after receiving access. A target that has no hub user yet is provisioned automatically by this operation when the grant is non-empty. A grant only takes effect at the target agent's next login — that is when the new claims are provisioned — so an agent already signed in keeps its old access until it logs in again. This operation never removes the agent from the CloudChat account itself.

export const CloudChatYourValues = () => {
  const STORAGE_KEY = "cloudchat-api-selected-account";
  const CREDENTIALS_HREF = "/api-reference/cloudchat/credentials";
  const [saved, setSaved] = useState(null);
  const [ready, setReady] = useState(false);
  useEffect(() => {
    let value = null;
    try {
      const raw = window.localStorage.getItem(STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        if (parsed && parsed.instance && parsed.account) {
          value = {
            instance: String(parsed.instance),
            account: String(parsed.account),
            name: typeof parsed.name === "string" && parsed.name ? parsed.name : null
          };
        }
      }
    } catch (error) {
      value = null;
    }
    setSaved(value);
    setReady(true);
  }, []);
  const shell = "not-prose rounded-xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/5 px-4 py-3 mb-6";
  if (!ready || !saved) {
    return <div className={shell}>
        <p className="text-sm text-gray-600 dark:text-gray-400">
          Every request below needs your <code>cloudchat-instance</code> header and your account
          id.{" "}
          <a href={CREDENTIALS_HREF} className="underline underline-offset-2">
            Paste your token
          </a>{" "}
          and they will show up here, ready to copy.
        </p>
      </div>;
  }
  return <div className={shell}>
      <div className="flex flex-wrap items-baseline gap-x-6 gap-y-2">
        <div>
          <span className="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">
            cloudchat-instance
          </span>
          <span className="ml-2 font-mono text-sm text-gray-900 dark:text-gray-100">
            {saved.instance}
          </span>
        </div>
        <div>
          <span className="text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400">
            accountId
          </span>
          <span className="ml-2 font-mono text-sm text-gray-900 dark:text-gray-100">
            {saved.account}
          </span>
        </div>
        {saved.name && <span className="text-sm text-gray-600 dark:text-gray-400">{saved.name}</span>}
        <a href={CREDENTIALS_HREF} className="text-sm text-gray-500 dark:text-gray-400 underline underline-offset-2">
          Change
        </a>
      </div>
    </div>;
};

<CloudChatYourValues />


## OpenAPI

````yaml api-reference/specs/cloudchat/v1.json PUT /v1/accounts/{accountId}/agents/{agentId}/access
openapi: 3.0.1
info:
  title: Cloud Chat API
  version: v1
  description: >-
    The curated public surface of Cloud Chat. Every call needs two things: the
    Bearer token from `POST /auth/v1/signin`, and the `cloudchat-instance`
    header that says which Cloud Chat instance your company lives on.


    If you don't know your instance value, the [Find your
    credentials](/api-reference/cloudchat/credentials) page reads it out of your
    own token in the browser.
servers:
  - url: https://api.cloudhumans.com/cloudchat
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Canned Responses
    description: >-
      Canned responses — the shortcuts agents expand while replying. Each one
      belongs to a single account and is identified by its short code.
  - name: Conversations
    description: >-
      Read-only access to the conversations of an account. What you can see
      follows the same rule as the dashboard: an administrator token sees every
      inbox, an agent token only the inboxes it is a member of.
  - name: Help Center
    description: >-
      Portals, categories and articles of the help center — the public FAQ your
      customers read.
  - name: Uploads
    description: Store the images help center articles embed.
  - name: Labels
    description: >-
      Read-only access to the labels an account has defined. A label is a tag
      conversations and contacts carry; this endpoint only lists the label
      definitions themselves.
  - name: Inboxes
    description: >-
      Read-only access to the inboxes a token can see — every inbox of the
      account for an administrator, only its memberships for an agent. Never
      includes the channel's credentials.
  - name: Agents
    description: >-
      Read-only access to the human and AI agents of an account. A hidden admin
      (the platform's own support user) never appears, on the list or by id.
  - name: Teams
    description: >-
      Teams group agents for assignment. Listing and reading are open to any
      member; creating and updating a team, and managing its membership, require
      an administrator token. A system-managed team (provisioned by the
      platform) can be read like any other but never updated.
  - name: Macros
    description: >-
      Macros bundle a sequence of actions an agent runs against a conversation
      from the dashboard. This surface lets you list, read and write macro
      definitions — running one is not part of the v1 contract. A macro is
      either `global` (visible to the whole account) or `personal` (visible only
      to its author); an agent token can only create personal macros.
  - name: Automation Rules
    description: >-
      Read-only access to the account's automation rules — administrator only.
      An agent token gets a 403 on every operation in this group.
  - name: Availability Reasons
    description: >-
      The reasons an agent can go `busy` for, configured per account. Listing is
      open to any member; creating, updating and deleting require an
      administrator token. Deleting is a soft delete — the reason disappears
      from listings but agents' past availability history keeps referencing it.
  - name: Native Attribute Requirements
    description: >-
      Which native conversation attributes (priority, assignee, tag, team) the
      account requires agents to fill before resolving a conversation. Listing
      is open to any member; requiring and un-requiring need an administrator
      token. Deleting a requirement is reversible — require the same key again
      to restore it.
paths:
  /v1/accounts/{accountId}/agents/{agentId}/access:
    parameters:
      - $ref: '#/components/parameters/CloudChatInstance'
      - $ref: '#/components/parameters/AccountId'
      - $ref: '#/components/parameters/AgentId'
    put:
      tags:
        - Agents
      summary: Set an agent's hub access
      description: >-
        Grant or revoke this agent's access to Claudia projects and Eddie
        workspaces. Administrator only. Each dimension — `claudia_projects` and
        `eddie_workspaces` — is optional and independently declarative: send it
        as the full set you want that dimension to hold, drawn from your own
        `manageable` ceiling (see getAgentAccess) — items you leave out of a
        dimension you send are revoked, items you add are granted; a dimension
        you omit from the request entirely is left untouched. You can only grant
        or revoke within your own ceiling: items the target already holds
        outside it are preserved, never touched by your request. Naming an item
        outside your ceiling is refused with 422 (`outside_ceiling`, field names
        the offending dimension). The target's CloudChat role must be
        `administrator` or `cx_engineer`, or the whole request is refused with
        422 (`ineligible_role`, field `agent`). An all-empty request (revoking
        everything) is accepted regardless of the target's role — it is the
        cleanup path for an agent demoted after receiving access. A target that
        has no hub user yet is provisioned automatically by this operation when
        the grant is non-empty. A grant only takes effect at the target agent's
        next login — that is when the new claims are provisioned — so an agent
        already signed in keeps its old access until it logs in again. This
        operation never removes the agent from the CloudChat account itself.
      operationId: setAgentAccess
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentAccessSetRequest'
      responses:
        '200':
          description: >-
            The agent's hub access as stored — `agent_access` reflects every
            dimension you sent, unchanged for any dimension you omitted;
            `manageable` is unchanged, it is your own ceiling and this operation
            never alters it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentAccess'
        '400':
          description: >-
            The request could not be answered as written — the `access` wrapper
            is missing, both dimensions are absent from it, or a dimension
            present in it is not an array of non-empty strings.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: bad_request
                  message: >-
                    Provide `access` with at least one of: claudia_projects,
                    eddie_workspaces.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            The account is suspended, or the caller is not an administrator of
            the account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: forbidden
                  message: You are not allowed to perform this action.
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: >-
            The change was refused. `details[].code` is `outside_ceiling` (field
            names the offending dimension, the message names the refused items)
            when an item falls outside your own `manageable` set, or
            `ineligible_role` (field `agent`) when the target's CloudChat role
            is not `administrator` or `cx_engineer`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
              example:
                error:
                  code: validation_failed
                  message: The request payload is invalid.
                  details:
                    - field: claudia_projects
                      code: outside_ceiling
                      message: >-
                        acme_internal is outside your manageable Claudia
                        projects.
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  parameters:
    CloudChatInstance:
      name: cloudchat-instance
      in: header
      required: true
      description: >-
        Your Cloud Chat instance ID — an integer, fixed for your company, told
        at onboarding. [The API
        overview](/api-reference/cloudchat/overview#two-headers-every-call)
        explains how instances work, how to find yours, and the errors a wrong
        or missing value produces.
      schema:
        type: integer
        example: 1
    AccountId:
      name: accountId
      in: path
      required: true
      description: >-
        Your Cloud Chat account. It has to be an account your token grants
        membership on, and it has to live on the instance in the
        `cloudchat-instance` header — the two travel together. Account numbers
        are only unique **within** an instance, so the same number is a
        different company on another instance. Usually a mismatched pair fails
        closed with a 401, because your user does not exist on the other
        instance — but if your identity happens to exist on both, the call
        succeeds against the other company's data, silently. Read it and you are
        looking at the wrong help center; write it and you have stored into the
        wrong account. Send the two values that were given to you together, and
        never try a number to see what answers.
      schema:
        type: integer
        example: 1
    AgentId:
      name: agentId
      in: path
      required: true
      description: >-
        The agent's user id, as returned when the agent was listed. A hidden
        admin's id answers 404 here, the same as an id that does not exist.
      schema:
        type: integer
        example: 7
  schemas:
    AgentAccessSetRequest:
      type: object
      required:
        - access
      properties:
        access:
          type: object
          properties:
            claudia_projects:
              type: array
              items:
                type: string
                minLength: 1
              description: >-
                Declarative state of your manageable Claudia projects for this
                agent, drawn from your own `manageable.claudia_projects` (see
                getAgentAccess): every project you want it to hold. A project
                you can manage but leave out here is revoked; a project it
                already holds outside your ceiling is preserved untouched. Omit
                this property entirely to leave the agent's Claudia project
                access unchanged.
              example:
                - acme_support
            eddie_workspaces:
              type: array
              items:
                type: string
                minLength: 1
              description: >-
                Declarative state of your manageable Eddie workspaces for this
                agent, drawn from your own `manageable.eddie_workspaces` (see
                getAgentAccess): every workspace you want it to hold. A
                workspace you can manage but leave out here is revoked; a
                workspace it already holds outside your ceiling is preserved
                untouched. Omit this property entirely to leave the agent's
                Eddie workspace access unchanged.
              example:
                - ws_42
          description: >-
            The two dimensions of hub access to change. Each is optional and
            independent — present it to declare that dimension's full desired
            state (grants and revokes, within your own ceiling), or leave it out
            to leave that dimension untouched. At least one of the two must be
            present.
          minProperties: 1
          additionalProperties: false
      description: >-
        Wrapper the endpoint expects — the dimensions to change go under
        `access`.
    AgentAccess:
      type: object
      required:
        - agent_access
        - manageable
      properties:
        agent_access:
          allOf:
            - $ref: '#/components/schemas/AgentAccessLists'
          description: What the agent in the path currently holds.
        manageable:
          allOf:
            - $ref: '#/components/schemas/AgentAccessLists'
          description: >-
            The caller's own ceiling — the exact set this credential can grant
            or revoke.
      description: >-
        An agent's hub access, alongside the caller's own ceiling for granting
        or revoking it.
    Error:
      type: object
      description: The error envelope every Cloud Chat API response uses.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: >-
                The stable, machine-readable reason. Branch on this, never on
                `message`.
              enum:
                - unauthorized
                - forbidden
                - not_found
                - validation_failed
                - bad_request
                - internal_error
              example: not_found
            message:
              type: string
              description: >-
                The reason in words, localized to your account's language
                (English, Spanish or Brazilian Portuguese; English when the
                account is set to anything else). Wording changes with the
                account and between releases, so never match on it.


                Two cases stay in English whatever the account is set to:
                `unauthorized`, decided before any account is known, and the
                account-level `not_found`, which must not reveal the account's
                language.
              example: Resource could not be found.
            details:
              type: array
              description: >-
                Present on some rejections — a 400 for a refused query parameter
                or upload mode, for example. One entry per offending field,
                localized to the account's language like `message` — match on
                `code` and `field`, never on the text.
              items:
                type: object
                required:
                  - field
                  - code
                  - message
                properties:
                  field:
                    type: string
                    description: Which request field the rule was about.
                  code:
                    type: string
                    description: Stable, machine-readable reason.
                  message:
                    type: string
                    description: The rule in words.
    ValidationError:
      type: object
      description: A `validation_failed` error, which carries `details`.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - details
          properties:
            code:
              type: string
              enum:
                - validation_failed
              example: validation_failed
            message:
              type: string
              description: >-
                Localized to the account's language, like every other envelope
                message.
              example: The request payload is invalid.
            details:
              type: array
              description: >-
                One entry per rejected field. Unlike the envelope message above,
                the texts come from the model layer and are in English in
                practice (the model layer ships no translations) — match on code
                and field, never on the text.
              items:
                type: object
                required:
                  - field
                  - code
                  - message
                properties:
                  field:
                    type: string
                    description: >-
                      Which request field the rule was about — `short_code` or
                      `content`. A rule that is not tied to either is reported
                      as `base`, so treat `base` as "the payload as a whole"
                      rather than a field you can highlight.
                    enum:
                      - short_code
                      - content
                      - base
                    example: short_code
                  code:
                    type: string
                    description: >-
                      Which rule it broke — `blank` for a missing or empty
                      value, `taken` for a `short_code` already used on the
                      account.
                    example: taken
                  message:
                    type: string
                    example: has already been taken
    AgentAccessLists:
      type: object
      required:
        - claudia_projects
        - eddie_workspaces
      properties:
        claudia_projects:
          type: array
          items:
            type: string
          description: >-
            Claudia project names — globally unique across all of Claudia, not
            scoped to this account. Always present, even when empty — never
            `null`.
          example:
            - acme_support
        eddie_workspaces:
          type: array
          items:
            type: string
          description: Eddie workspace ids. Always present, even when empty — never `null`.
          example:
            - ws_42
      description: The two dimensions of hub access.
    GatewayError:
      type: object
      description: >-
        Rejected by the gateway before Cloud Chat saw it, so it does not use the
        `error` envelope.
      required:
        - message
      properties:
        message:
          type: string
          example: API rate limit exceeded
        request_id:
          type: string
          description: Gateway request id. Quote it when reporting a problem.
          example: f3f7567638d4b65a8003057d0c77d275
  responses:
    Unauthorized:
      description: >-
        No Bearer token, or one that is expired, malformed, or not a Cognito
        token. Sign in again for a fresh `id_token`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: unauthorized
              message: >-
                Authentication is required. Send a valid Bearer token in the
                Authorization header.
    NotFound:
      description: >-
        The resource is not there for you. Three situations answer with this
        code, and the first two apply to **every** endpoint — the account is
        resolved before anything else runs, so a list or a create fails this way
        too:


        - the account does not exist on this instance,

        - the account exists but your token has no membership on it,

        - on an endpoint that names one, the resource it names (a canned
        response, a portal, an article) does not exist where the path says it
        does.


        The first two are deliberately indistinguishable — same status, same
        body, and the message stays in English in both, since translating it
        would reveal the account's configured language. So you cannot use this
        endpoint to find out which account ids exist. The third case is
        localized like every other error, which is safe because you only reach
        it once membership is established.


        Either way a 404 is not worth retrying. Check the `accountId`, the
        `cloudchat-instance` value, and that your user is a member of the
        account.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: not_found
              message: Resource could not be found.
    TooManyRequests:
      description: >-
        Rate limited per source IP. Note the envelope: this one is `{ "message":
        ... }`, because the request never reached the API.


        Don't hardcode the limit — read it from the response. `Retry-After` says
        how many seconds to wait, and every response (not just this one) carries
        `ratelimit-limit`, `ratelimit-remaining` and `ratelimit-reset`, the last
        in seconds.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          example:
            message: API rate limit exceeded
    InternalError:
      description: >-
        Something failed on our side. The response never carries the underlying
        error, but it is reported to our monitoring automatically — no need to
        file anything for a one-off.


        Retrying is reasonable, with one caveat on `POST`: a 500 does not prove
        the write did not happen, so a retry can come back `422` with
        `short_code` already taken. That 422 means the first attempt succeeded —
        list the account and confirm before treating it as a failure.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: internal_error
              message: An unexpected error occurred. Please try again later.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        The `id_token` from `POST /auth/v1/signin`, sent as `Authorization:
        Bearer <id_token>`. Not the `access_token` — that one does not carry the
        identity Cloud Chat authorizes on.

````