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

# Managing spaces, keys and SSO with GraphQL

> Use the Arize GraphQL API to create organizations and spaces, manage membership and roles, issue and revoke API keys, and configure SAML SSO and role mappings.

Admin resources are the account-level building blocks everything else in Arize AX sits on: organizations group spaces, spaces hold the models, projects and prompts you instrument, and space membership and API keys control who and what can reach them. This guide covers scripting those resources directly instead of clicking through the UI, which is useful for onboarding automation, CI pipelines that provision their own service keys, and bulk user or SAML role management. For the product-level concepts, see [Organizations & Spaces](/docs/ax/security-and-settings/organizations-and-spaces), [API and service keys](/docs/ax/security-and-settings/api-keys), [SSO & RBAC](/docs/ax/security-and-settings/sso-and-rbac) and [Space rate limiting](/docs/ax/security-and-settings/space-rate-limiting).

## Find the IDs you need

Most admin mutations take an organization ID, a space ID, or a user ID. Start from `account` to walk down to organizations and their spaces, and from `node` once you already hold a global ID. See [using global node IDs](/docs/ax/graphql-reference/overview/how-to-use-graphql/using-global-node-ids) for how these IDs are encoded.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query FindOrgsAndSpaces {
    account {
      id
      organizations(first: 20) {
        edges {
          node {
            id
            name
            spaces(first: 50) {
              edges {
                node {
                  id
                  uuid
                  name
                }
              }
            }
          }
        }
      }
    }
  }
  ```
</CodeGroup>

To find a user's ID, either look them up within an organization (see the first recipe below) or, if you only have an email, page through `account.users(search: "<email>")`.

## List the spaces in an organization and their members

Before assigning or removing membership, pull the current member list for a space (or the full organization roster) so you know which user IDs and roles you are working with.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query OrgUsersAndSpaceMembers($orgId: ID!, $spaceId: ID!) {
    organization: node(id: $orgId) {
      ... on AccountOrganization {
        name
        accountOrganizationUsers(first: 50) {
          edges {
            node {
              role
              user { id name email }
            }
          }
        }
      }
    }
    space: node(id: $spaceId) {
      ... on Space {
        name
        spaceUsers(first: 50) {
          edges {
            node {
              role
              user { id name email }
            }
          }
        }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "orgId": "QWNjb3VudE9yZ2FuaXphdGlvbjoxMjM=",
    "spaceId": "U3BhY2U6NDU2"
  }
  ```
</CodeGroup>

`Space.spaceUsers` returns every user with access to the space, including account and organization admins who were never explicitly added, not only direct members. For users with custom RBAC roles, `role` on `SpaceUser` is null; check `customRole` instead.

## Create a space in an organization

Spaces are created inside an organization, so you need the organization's ID first (see above).

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateSpace($input: CreateSpaceMutationInput!) {
    createSpace(input: $input) {
      space { id uuid name }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "accountOrganizationId": "QWNjb3VudE9yZ2FuaXphdGlvbjoxMjM=",
      "name": "ml-platform-staging",
      "private": true,
      "description": "Staging space for the ML platform team"
    }
  }
  ```
</CodeGroup>

Reference: [`createSpace`](/docs/ax/graphql-reference/mutations/admin#createspace). To rename a space, change its description, or flip `mlModelsEnabled`, use [`updateSpace`](/docs/ax/graphql-reference/mutations/admin#updatespace) with the same `spaceId`. To delete one, use [`deleteSpace`](/docs/ax/graphql-reference/mutations/admin#deletespace), which takes the space's `uuid`, not its global `id`.

## Bulk-assign users to spaces with roles

`assignSpaceMembership` takes a list, so you can onboard a whole team across multiple spaces in one call. Each entry needs either a legacy `role` or a `customRoleId`, never both.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation AssignSpaceMembership($input: AssignSpaceMembershipMutationInput!) {
    assignSpaceMembership(input: $input) {
      spaceMemberships {
        id
        role
        user { id email }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "spaceMemberships": [
        { "userId": "VXNlcjo3MDE=", "spaceId": "U3BhY2U6NDU2", "role": "member" },
        { "userId": "VXNlcjo3MDI=", "spaceId": "U3BhY2U6NDU2", "role": "readOnly" },
        { "userId": "VXNlcjo3MDE=", "spaceId": "U3BhY2U6Nzg5", "customRoleId": "Um9sZToxMjM=" }
      ]
    }
  }
  ```
</CodeGroup>

Reference: [`assignSpaceMembership`](/docs/ax/graphql-reference/mutations/admin#assignspacemembership). Legacy `role` accepts `admin`, `member`, `readOnly` or `annotator`. Custom RBAC role IDs (for `customRoleId`) aren't queryable through this API; copy them from **Settings > Roles** in the Arize UI.

Scripting this in bulk is a common CI task, for example syncing space access from an HR system:

```python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import requests

API_KEY = "<YOUR_API_KEY>"
URL = "https://app.arize.com/graphql"

mutation = """
mutation AssignSpaceMembership($input: AssignSpaceMembershipMutationInput!) {
  assignSpaceMembership(input: $input) {
    spaceMemberships { id role user { id email } }
  }
}
"""

memberships = [
    {"userId": "VXNlcjo3MDE=", "spaceId": "U3BhY2U6NDU2", "role": "member"},
    {"userId": "VXNlcjo3MDI=", "spaceId": "U3BhY2U6NDU2", "role": "readOnly"},
]

response = requests.post(
    URL,
    json={"query": mutation, "variables": {"input": {"spaceMemberships": memberships}}},
    headers={"x-api-key": API_KEY},
)
response.raise_for_status()
result = response.json()
if "errors" in result:
    raise RuntimeError(result["errors"])
print(result["data"]["assignSpaceMembership"]["spaceMemberships"])
```

## Remove a member from a space

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation RemoveSpaceMember($input: RemoveSpaceMemberMutationInput!) {
    removeSpaceMember(input: $input) {
      space { id name }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "spaceId": "U3BhY2U6NDU2",
      "userId": "VXNlcjo3MDI="
    }
  }
  ```
</CodeGroup>

Reference: [`removeSpaceMember`](/docs/ax/graphql-reference/mutations/admin#removespacemember). This removes direct space membership only; a user who still has access through an organization or account admin role keeps access to the space.

## Create a service API key for CI

Service keys back a dedicated bot user rather than a human, which is what you want for pipelines. Grant access either to a single space (legacy path) or to multiple organizations and spaces at once with `organizations`; the two approaches are mutually exclusive.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateServiceApiKey($input: CreateServiceApiKeyInput!) {
    createServiceApiKey(input: $input) {
      botUserId
      apiKey
      keyInfo { id name status createdAt expiresAt }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "name": "ci-ingestion-bot",
      "accountRole": "member",
      "organizations": [
        {
          "orgId": "QWNjb3VudE9yZ2FuaXphdGlvbjoxMjM=",
          "orgRole": "member",
          "spaces": [
            { "spaceId": "U3BhY2U6NDU2", "spaceRole": "member" }
          ]
        }
      ],
      "expiresAt": "2026-12-31T00:00:00Z"
    }
  }
  ```
</CodeGroup>

Reference: [`createServiceApiKey`](/docs/ax/graphql-reference/mutations/admin#createserviceapikey). The response's `apiKey` field is the only time the raw key is returned; store it immediately. For a personal key instead of a bot-backed one, use [`createUserApiKey`](/docs/ax/graphql-reference/mutations/admin#createuserapikey), which only takes a `name`, optional `description` and `expiresAt`, and a `type` of `user` or `service`.

## Revoke an API key

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation RevokeApiKey($input: RevokeApiKeyInput!) {
    revokeApiKey(input: $input) {
      status
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "apiKeyId": "QXBpS2V5OjQ0Mg=="
    }
  }
  ```
</CodeGroup>

Reference: [`revokeApiKey`](/docs/ax/graphql-reference/mutations/admin#revokeapikey). `status` only ever returns `ok` on success; a failed revocation (for example, an already-revoked or unknown key) comes back as a GraphQL error rather than a different status value. Find the key ID to revoke on `viewer.apiKeys` for your own keys, or from the `keyInfo.id` returned when the key was created.

## Configure a SAML identity provider and add a role mapping

Create the IdP with its email domains and metadata, then add role mappings one at a time so you don't have to resend the entire configuration for each change.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateSAMLIdP($input: CreateSAMLIdPInput!) {
    createSAMLIdP(input: $input) {
      idp { id enforceSaml allowLoginWithDefaults }
      error
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "emailDomainsList": [{ "domain": "example.com" }],
      "metadataUrl": "https://idp.example.com/saml2/metadata",
      "allowLoginWithDefaults": true,
      "defaultOrgId": "QWNjb3VudE9yZ2FuaXphdGlvbjoxMjM=",
      "defaultOrgRoleId": "member",
      "defaultSpaceId": "U3BhY2U6NDU2",
      "defaultSpaceRoleId": "member"
    }
  }
  ```
</CodeGroup>

Then add a mapping that promotes a SAML attribute to a space role without touching the mappings already configured:

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation AddSAMLRoleMapping($input: AddSAMLRoleMappingInput!) {
    addSAMLRoleMapping(input: $input) {
      idp { id }
      error
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "id": "U0FNTElkUDoxMjM0NTY=",
      "mapping": {
        "attributesMap": [["department", "data-science"]],
        "orgRole": { "orgId": "QWNjb3VudE9yZ2FuaXphdGlvbjoxMjM=", "roleId": "member" },
        "spaceRolesMap": [["U3BhY2U6NDU2", "admin"]]
      }
    }
  }
  ```
</CodeGroup>

Reference: [`createSAMLIdP`](/docs/ax/graphql-reference/mutations/admin#createsamlidp) and [`addSAMLRoleMapping`](/docs/ax/graphql-reference/mutations/admin#addsamlrolemapping). `addSAMLRoleMapping` rejects a mapping whose SAML attributes and organization already match an existing one. To change the metadata, default roles or other top-level settings afterward, use [`updateSAMLIdP`](/docs/ax/graphql-reference/mutations/admin#updatesamlidp), which replaces the full configuration, so include every `roleMappings` entry you want to keep, not just the ones you're changing. `spaceRolesMap` (legacy roles) and `spaceRbacRolesMap` (custom RBAC role IDs) are mutually exclusive on the same mapping, and custom role IDs have to come from the Arize UI since there's no query that lists them.

## Set or clear a space ingestion gate

Ingestion gates cap how much data a space can take in per `TierGate` category. Setting a gate to `0` blocks all ingestion for that category; clearing it removes the limit entirely.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation SetSpaceGateLimit($input: SetSpaceGateLimitMutationInput!) {
    setSpaceGateLimit(input: $input) {
      space { id name gates { gateType limitValue } }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "spaceId": "U3BhY2U6NDU2",
      "gateType": "prodPredictions",
      "limitValue": 0
    }
  }
  ```
</CodeGroup>

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation DeleteSpaceGateLimit($input: DeleteSpaceGateLimitMutationInput!) {
    deleteSpaceGateLimit(input: $input) {
      space { id name }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "spaceId": "U3BhY2U6NDU2",
      "gateType": "prodPredictions"
    }
  }
  ```
</CodeGroup>

Reference: [`setSpaceGateLimit`](/docs/ax/graphql-reference/mutations/admin#setspacegatelimit) and [`deleteSpaceGateLimit`](/docs/ax/graphql-reference/mutations/admin#deletespacegatelimit). `gateType` is one of `workspaces`, `organizations`, `prodPredictions`, `preProdPredictions`, `activeModels`, `features` or `dataSize`; `dataSize` is measured in bytes. See [Space rate limiting](/docs/ax/security-and-settings/space-rate-limiting) for what each gate controls.

## Gotchas and behavior notes

<AccordionGroup>
  <Accordion title="Mutually exclusive inputs, checked at runtime, not by the type system">
    `SpaceMemberInput` requires either `role` or `customRoleId`, never both. `CreateServiceApiKeyInput` requires either the legacy `spaceId`/`spaceRole`/`spaceRoleId`/`accountOrganizationRole` path or `organizations`, never both, and within each space assignment, `spaceRole` and `spaceRoleId` are themselves mutually exclusive. A `RoleMappingInput` can set `spaceRolesMap` or `spaceRbacRolesMap`, but not both. None of this is enforced by the schema's nullability; sending both fields returns a runtime error.
  </Accordion>

  <Accordion title="deleteSpace takes a uuid, not the global id">
    Every other space mutation takes `spaceId` (the global `ID!`). `deleteSpace` instead takes `spaceUuid`, the `Space.uuid` scalar field. Query `uuid` separately before calling it.
  </Accordion>

  <Accordion title="There is no deleteSAMLIdP mutation">
    The admin mutations are limited to `createSAMLIdP`, `updateSAMLIdP` and `addSAMLRoleMapping`; there's no mutation to delete a SAML configuration. `CreateSAMLIdPInput` accepts a `status` of `"active"` or `"deleted"` at creation time, but `UpdateSAMLIdPInput` has no `status` field, so an existing config can't be soft-deleted through the API either.
  </Accordion>

  <Accordion title="updateSAMLIdP replaces the whole configuration">
    Treat every call as a full replacement. Fields you omit may reset rather than stay untouched, and that applies to `roleMappings.mappingsList` too: resend every mapping you want to keep alongside any changes.
  </Accordion>

  <Accordion title="No query lists custom RBAC roles">
    The schema has no `roles` field on `Account` and no connection type for roles; `Role` doesn't implement `Node` either, so you can't fetch one by ID through `node`. Get custom role IDs for `customRoleId`, `spaceRoleId` or `spaceRbacRolesMap` from **Settings > Roles** in the Arize UI.
  </Accordion>

  <Accordion title="developerAccessDefault is deprecated">
    `Account.developerAccessDefault` always returns `true` now; developer access comes from the user's assigned account role. Use `Account.developerAccessLocked` to disable developer access account-wide instead.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Admin mutations reference" icon="book" href="/docs/ax/graphql-reference/mutations/admin">
    Full arguments, return types and minimal examples for every admin mutation.
  </Card>

  <Card title="All mutations" icon="list" href="/docs/ax/graphql-reference/mutations">
    Browse mutations for every other domain: monitors, datasets, prompts and more.
  </Card>

  <Card title="API explorer" icon="terminal" href="/docs/ax/graphql-reference/overview/api-explorer">
    Run queries and mutations interactively against your own space.
  </Card>
</CardGroup>
