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

# Create a new API key

> Mints a new opaque API key (`sk-orq-<key_id>-<secret>`) in the workspace. The raw secret is returned ONCE in the response and is never retrievable afterwards. The stored record retains only `token_prefix` and a SHA-256 `token_hash`.



## OpenAPI

````yaml post /v2/api-keys
openapi: 3.1.0
info:
  title: orq.ai API
  version: '2.0'
  description: orq.ai API documentation
servers:
  - url: https://api.orq.ai
security:
  - ApiKey: []
tags:
  - description: List models available through the AI Router.
    name: Models
  - name: Guardrail Rules
  - name: Policies
  - name: Routing Rules
  - name: API keys
    description: >-
      API keys authenticate programmatic access to the workspace. The unified
      key model exposes opaque tokens, per-domain access grants, and budget /
      rate-limit constraints (see ADR 0001 and ADR 0002).
  - name: Budgets
    description: >-
      Budgets govern spend, token usage, and request rate across six scopes:
      workspace, project, identity, api-key, provider, and model. A budget is
      hierarchical and defense-in-depth — every applicable budget is a hard
      gate, and the most restrictive one wins per dimension (see ADR 0007).
  - name: Documentation
    description: >-
      Search the orq.ai documentation. Proxies the workspace's query to the
      hosted docs search index.
  - name: Files
    description: File upload and retrieval operations.
  - name: Identities
    description: >-
      Identities represent end users from your system for usage and engagement
      tracking.
  - name: Projects
    description: Projects organize resources within a workspace
  - name: Skills
    description: >-
      Skills are modular instructions you can use to codify processes and
      conventions
  - name: Responses
  - description: >-
      Run agents on a cadence — cron, interval, or one-off. Minimum firing
      interval is 1 hour.
    name: Agent Schedules
  - name: Embeddings
  - name: Reporting
    description: >-
      GenAI reporting API over canonical analytics rollups. Accepts a metric
      name, time range, grain, group-by, and filters; returns a typed time
      series and optional totals.
externalDocs:
  url: https://docs.orq.ai
  description: orq.ai Documentation
paths:
  /v2/api-keys:
    post:
      tags:
        - API keys
      summary: Create a new API key
      description: >-
        Mints a new opaque API key (`sk-orq-<key_id>-<secret>`) in the
        workspace. The raw secret is returned ONCE in the response and is never
        retrievable afterwards. The stored record retains only `token_prefix`
        and a SHA-256 `token_hash`.
      operationId: ApiKeyCreate
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateApiKeyRequest'
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateApiKeyResponse'
      x-code-samples:
        - lang: curl
          label: Core - Create service account key
          source: |
            curl --request POST \
              --url 'https://api.orq.ai/v2/api-keys' \
              --header 'Authorization: Bearer $ORQ_API_KEY' \
              --header 'Content-Type: application/json' \
              --data '{
                "name": "Production service key",
                "owner": {
                  "service_account": {}
                },
                "project_scope": {
                  "all": {}
                },
                "permission_mode": "PERMISSION_MODE_ALL"
              }'
        - lang: python
          label: Python - Create service account key
          source: |
            import os
            from orq_ai_sdk import Orq

            client = Orq(api_key=os.environ["ORQ_API_KEY"])

            result = client.api_keys.create(
                name="Production service key",
                owner={"service_account": {}},
                project_scope={"all": {}},
                permission_mode="PERMISSION_MODE_ALL",
            )

            # Store the token immediately. It is only returned once.
            print(result.token)
        - lang: typescript
          label: Node.js - Create service account key
          source: |
            import { Orq } from '@orq-ai/node';

            const client = new Orq({
              apiKey: process.env.ORQ_API_KEY,
            });

            const result = await client.apiKeys.create({
              name: 'Production service key',
              owner: {
                serviceAccount: {},
              },
              projectScope: {
                all: {},
              },
              permissionMode: 'PERMISSION_MODE_ALL',
            });

            // Store the token immediately. It is only returned once.
            console.log(result.token);
        - lang: curl
          label: Core - Create restricted project key
          source: |
            curl --request POST \
              --url 'https://api.orq.ai/v2/api-keys' \
              --header 'Authorization: Bearer $ORQ_API_KEY' \
              --header 'Content-Type: application/json' \
              --data '{
                "name": "Support automation key",
                "project_scope": {
                  "single": {
                    "project_id": "proj_01HZXW2K7Y8Q9M0N1P2R3S4T5V"
                  }
                },
                "permission_mode": "PERMISSION_MODE_RESTRICTED",
                "access": {
                  "agents": "ACCESS_LEVEL_WRITE",
                  "deployments": "ACCESS_LEVEL_READ"
                }
              }'
        - lang: python
          label: Python - Create restricted project key
          source: |
            import os
            from orq_ai_sdk import Orq

            client = Orq(api_key=os.environ["ORQ_API_KEY"])

            result = client.api_keys.create(
                name="Support automation key",
                project_scope={
                    "single": {
                        "project_id": "proj_01HZXW2K7Y8Q9M0N1P2R3S4T5V",
                    },
                },
                permission_mode="PERMISSION_MODE_RESTRICTED",
                access={
                    "agents": "ACCESS_LEVEL_WRITE",
                    "deployments": "ACCESS_LEVEL_READ",
                },
            )

            print(result.api_key.api_key_id)
            print(result.token)
        - lang: typescript
          label: Node.js - Create restricted project key
          source: |
            import { Orq } from '@orq-ai/node';

            const client = new Orq({
              apiKey: process.env.ORQ_API_KEY,
            });

            const result = await client.apiKeys.create({
              name: 'Support automation key',
              projectScope: {
                single: {
                  projectId: 'proj_01HZXW2K7Y8Q9M0N1P2R3S4T5V',
                },
              },
              permissionMode: 'PERMISSION_MODE_RESTRICTED',
              access: {
                agents: 'ACCESS_LEVEL_WRITE',
                deployments: 'ACCESS_LEVEL_READ',
              },
            });

            console.log(result.apiKey.apiKeyId);
            console.log(result.token);
components:
  schemas:
    CreateApiKeyRequest:
      required:
        - name
      type: object
      properties:
        name:
          type: string
          description: Human-readable name. Required.
        owner:
          allOf:
            - $ref: '#/components/schemas/ApiKeyOwner'
          description: Owner attribution. Defaults to service_account when omitted.
        project_scope:
          allOf:
            - $ref: '#/components/schemas/ProjectScope'
          description: Project authorization scope. Defaults to all-projects when omitted.
        permission_mode:
          $ref: '#/components/schemas/PermissionMode'
          description: Permission preset. Defaults to PERMISSION_MODE_ALL when omitted.
        access:
          type: object
          additionalProperties:
            type: integer
            format: enum
          description: |-
            Per-domain access map. Required when `permission_mode` =
             `PERMISSION_MODE_RESTRICTED`. See `ApiKey.access` for the full
             catalog of valid keys (Domain.id) and AccessLevel string values,
             or fetch the live catalog via the capability catalog endpoint.
        expires_at:
          type: string
          description: |-
            Optional expiration. When set, the authenticate hot-path rejects
             the key once `expires_at` is in the past. Unset means the key
             never expires.
          format: date-time
    CreateApiKeyResponse:
      required:
        - api_key
        - token
      type: object
      properties:
        api_key:
          allOf:
            - $ref: '#/components/schemas/ApiKey'
          description: Newly minted api-key record.
        token:
          type: string
          description: |-
            Raw bearer token in the form `sk-orq-<api_key_id>-<secret>`.
             Returned ONCE; the API never exposes this value again. Clients
             must persist it immediately on receipt.
    ApiKeyOwner:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/UserOwner'
        service_account:
          $ref: '#/components/schemas/ServiceAccountOwner'
      description: |-
        Owner attribution drives lifecycle.

         `service_account` keys are workspace-owned and outlive any individual
         user. `user` keys are bound to `user_id`: when the user is removed,
         disabled, or loses project access, the key is revoked / its scope
         shrinks per the cascade rules in ADR 0001.
    ProjectScope:
      type: object
      properties:
        all:
          $ref: '#/components/schemas/AllProjects'
        single:
          $ref: '#/components/schemas/SingleProject'
      description: |-
        Project authorization scope. Single-project or all-projects.
         Multi-project use cases are served by minting per-project keys or by
         using an all-projects key with `restricted` mode.
    PermissionMode:
      type: string
      enum:
        - PERMISSION_MODE_UNSPECIFIED
        - PERMISSION_MODE_ALL
        - PERMISSION_MODE_RESTRICTED
        - PERMISSION_MODE_READ_ONLY
    ApiKey:
      required:
        - api_key_id
        - name
        - owner
        - project_scope
        - permission_mode
        - token_prefix
        - status
        - created_at
        - updated_at
      type: object
      properties:
        api_key_id:
          type: string
          description: |-
            Canonical key identifier (ULID). Embedded in opaque tokens as
             `sk-orq-<id>-<secret>`.
        name:
          type: string
          description: Human-readable name shown in the dashboard.
        owner:
          allOf:
            - $ref: '#/components/schemas/ApiKeyOwner'
          description: Owner attribution (drives lifecycle).
        project_scope:
          allOf:
            - $ref: '#/components/schemas/ProjectScope'
          description: Project authorization scope.
        permission_mode:
          $ref: '#/components/schemas/PermissionMode'
          description: |-
            Permission preset. `all` and `read_only` resolve at auth time from
             the capability catalog. `restricted` reads the per-domain `access`
             map.
        access:
          type: object
          additionalProperties:
            type: integer
            format: enum
          description: |-
            Per-domain access map. Only populated when `permission_mode` is
             `PERMISSION_MODE_RESTRICTED`. The authoritative list of valid
             keys and the per-domain read / write semantics are exposed at
             runtime via the capability catalog endpoint.

             Valid keys are the Domain.id values in the capability catalog —
             see libs/catalog/orq/apikeys/v1/catalog.textpb for the canonical
             list. The ids are intentionally not duplicated here to avoid drift.

             Values are AccessLevel enum names on the JSON wire:
               "ACCESS_LEVEL_NONE"  — capability not granted
               "ACCESS_LEVEL_READ"  — list / view verbs
               "ACCESS_LEVEL_WRITE" — list / view + mutating / execute verbs
        token_prefix:
          type: string
          description: |-
            Displayable prefix for UI listings (e.g. "sk-orq-01HXY..."). Safe
             to expose.
        status:
          $ref: '#/components/schemas/ApiKeyStatus'
          description: Lifecycle status.
        created_by_id:
          type: string
          description: |-
            Audit: user who created the key. Optional. Distinct from
             `owner.user_id` — created_by is provenance only, while owner
             determines lifecycle binding.
        updated_by_id:
          type: string
          description: 'Audit: user who last updated the key.'
        created_at:
          type: string
          description: Time the key was created.
          format: date-time
        updated_at:
          type: string
          description: Time the key was last updated.
          format: date-time
        last_used_at:
          type: string
          description: Last authenticated use. Updated via NATS debounce + 1% sampler.
          format: date-time
        expires_at:
          type: string
          description: |-
            Optional expiration. The authenticate hot-path rejects keys whose
             `expires_at` is in the past. Unset means the key never expires.
          format: date-time
        legacy_token_family:
          $ref: '#/components/schemas/LegacyTokenFamily'
          description: Token family marker used by the legacy adapter to route validation.
        legacy_key_id:
          type: string
          description: |-
            Legacy MongoDB `_id` from before the canonical ULID was assigned.
             Used by the adapter to resolve a JWT back to this canonical record.
      description: |-
        ApiKey is the canonical record stored in MongoDB `auth.apiKeys`.
         It is the source of truth for scope, permissions, owner, budget,
         expiration, and revocation (see ADR 0001).
    UserOwner:
      required:
        - user_id
      type: object
      properties:
        user_id:
          type: string
          description: User ID that owns the API key.
    ServiceAccountOwner:
      type: object
      properties: {}
    AllProjects:
      type: object
      properties: {}
    SingleProject:
      required:
        - project_id
      type: object
      properties:
        project_id:
          type: string
          description: Project ID this API key is scoped to.
    ApiKeyStatus:
      type: string
      enum:
        - API_KEY_STATUS_UNSPECIFIED
        - API_KEY_STATUS_ACTIVE
        - API_KEY_STATUS_DISABLED
        - API_KEY_STATUS_REVOKED
    LegacyTokenFamily:
      type: string
      enum:
        - LEGACY_TOKEN_FAMILY_UNSPECIFIED
        - LEGACY_TOKEN_FAMILY_ROUTER_JWT
        - LEGACY_TOKEN_FAMILY_PROJECT_JWT
        - LEGACY_TOKEN_FAMILY_WORKSPACE_JWT
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      bearerFormat: JWT

````