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

# Add Compliance Scan

> Creates a compliance scan and, unless you create it paused, starts polling immediately.

`cursor_end_time` is where reading starts, so it decides how much history gets pulled — run Test Compliance Connection first and read its `backfill` estimate before committing to a time.

`workspace_id` is the **ChatGPT workspace UUID**, not an OpenAI organization id. An organization id has the right shape, is accepted, and then returns nothing forever with no error to explain it.

`guardrails_name` names one of your saved guardrails; every message read is evaluated against it. It is not verified at creation time, so a typo surfaces later as a scan that flags nothing.

The scan name must be unique within your project — a repeat is a `409`.

The key is stored encrypted and **is never returned by any endpoint**.

Requires the **governance officer** role on the project your API key belongs to. The organization owner is not exempt — an owner without the role gets `403` — and an individual (non-organization) account cannot hold the role at all.



## OpenAPI

````yaml POST /compliance/add-scan
openapi: 3.0.0
info:
  title: Enkrypt AI APIs
  version: 2.0.0
servers:
  - url: https://api.enkryptai.com
security:
  - apiKeyAuth: []
tags:
  - name: Guardrails
  - name: Code of Conduct
  - name: Endpoints
  - name: Redteam
    description: >-
      Red Team API: submit red-team / threat-modeling / playground / eval runs,
      then poll run status, records, results and compliance. Also two-phase
      threat modeling (categories + data), dataset retrieval, model health,
      findings and risk mitigation. The previous task-based Red Team API is
      under **Archived**.
  - name: Deployments
  - name: AI Proxy
  - name: Leaderboard
  - name: Archived
  - name: MCP Hub
    description: >-
      MCP Hub vulnerability scanning APIs. Submitting scans (the POST endpoints)
      is open to all authenticated callers. The scan **retrieval** APIs — Get
      Scan Job Status, Get Complete Scan Results, List Scans, and Get MCP Hub
      Scan Statistics (the GET endpoints) — are an **enterprise data-license
      feature**: they require your organization to have MCP Hub API access
      enabled by Enkrypt, otherwise they return `403`. Contact us at
      support@enkryptai.com to enable access.
  - name: MCP Registry Servers
  - name: MCP Gateways
  - name: MCP Playground
  - name: Skill Scanner
    description: >-
      Skill Scanner APIs: submit an agent skill (a directory inside a git
      repository) for security scanning, then read the verdict, the risk level
      and the full report. Scanning is asynchronous — a scan takes roughly 30–90
      seconds, so `POST /skill-hub/scan` returns a `scan_id` you poll.


      You see your organization's scans and nobody else's. The identity comes
      from your API key, never from your request — sending `user_email` is a
      `400`.


      For an organization or project API key, scans are filed under the
      **organization**, so every member sees every scan the organization has
      run, whichever project or member submitted it. For an individual account
      it is simply your own scans. Either way List Skill Scans needs no
      parameter to say who you are.
  - name: Compliance
    description: >-
      Compliance APIs: connect a ChatGPT Enterprise workspace, then keep reading
      its compliance logs and scanning every message through one of your saved
      guardrails.


      Every endpoint here — reads as well as writes — requires the **governance
      officer** role on the project your API key belongs to. The organization
      owner is **not** exempt: an owner who has not been granted the role gets
      `403` like anyone else. An individual (non-organization) account cannot
      hold the role at all, so compliance is an organization-only feature today.


      A scan is addressed by name in the `X-Enkrypt-Scan` header, within the
      project its API key belongs to. Message text is never stored: Get
      Compliance Message fetches it live from the provider, and only while the
      provider still holds it.
paths:
  /compliance/add-scan:
    post:
      tags:
        - Compliance
      summary: Add Compliance Scan
      description: >-
        Creates a compliance scan and, unless you create it paused, starts
        polling immediately.


        `cursor_end_time` is where reading starts, so it decides how much
        history gets pulled — run Test Compliance Connection first and read its
        `backfill` estimate before committing to a time.


        `workspace_id` is the **ChatGPT workspace UUID**, not an OpenAI
        organization id. An organization id has the right shape, is accepted,
        and then returns nothing forever with no error to explain it.


        `guardrails_name` names one of your saved guardrails; every message read
        is evaluated against it. It is not verified at creation time, so a typo
        surfaces later as a scan that flags nothing.


        The scan name must be unique within your project — a repeat is a `409`.


        The key is stored encrypted and **is never returned by any endpoint**.


        Requires the **governance officer** role on the project your API key
        belongs to. The organization owner is not exempt — an owner without the
        role gets `403` — and an individual (non-organization) account cannot
        hold the role at all.
      operationId: compliance_add_scan
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ComplianceAddScanRequest'
            examples:
              minimal:
                summary: Create and start a scan
                value:
                  scan_name: ChatGPT Enterprise
                  guardrails_name: My Guardrail
                  provider: openai
                  workspace_id: 00000000-0000-0000-0000-000000000000
                  event_types:
                    - CONVERSATION_MESSAGE
                  cursor_end_time: '2026-09-01T00:00:00Z'
                  compliance_api_key: YOUR_PROVIDER_COMPLIANCE_KEY
              paused-with-tuning:
                summary: Create it paused, with a slower poll
                value:
                  scan_name: ChatGPT Enterprise
                  guardrails_name: My Guardrail
                  provider: openai
                  workspace_id: 00000000-0000-0000-0000-000000000000
                  event_types:
                    - CONVERSATION_MESSAGE
                    - CODEX_LOG
                  cursor_end_time: '2026-09-01T00:00:00Z'
                  compliance_api_key: YOUR_PROVIDER_COMPLIANCE_KEY
                  status: paused
                  list_interval_s: 300
                  pending_cap: 5000
      responses:
        '201':
          description: >-
            Scan created. `warning` is present only when the record was saved
            but the scanning service could not be told to start — the scan is
            picked up on the next reconcile.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceScanResponse'
              examples:
                created:
                  summary: Created and started
                  value:
                    scan:
                      scan_id: 11111111-2222-3333-4444-555555555555
                      id: 00000000-1111-2222-3333-444444444444
                      project_name: default
                      scan_name: ChatGPT Enterprise
                      created_by: 00000000-1111-2222-3333-444444444444
                      updated_by: 00000000-1111-2222-3333-444444444444
                      provider: openai
                      workspace_id: 00000000-0000-0000-0000-000000000000
                      event_types:
                        - CONVERSATION_MESSAGE
                      guardrails_name: My Guardrail
                      cursor_end_time: '2026-09-01T00:00:00Z'
                      cursor_file_id: null
                      last_polled_at: '2026-09-23T10:00:00Z'
                      list_interval_s: 60
                      pending_cap: 5000
                      status: active
                      created_at: '2026-09-01T09:00:00Z'
                      updated_at: '2026-09-01T09:00:00Z'
        '400':
          $ref: '#/components/responses/ComplianceBadRequest'
        '401':
          $ref: '#/components/responses/ComplianceUnauthorized'
        '403':
          $ref: '#/components/responses/ComplianceForbidden'
        '409':
          $ref: '#/components/responses/ComplianceConflict'
        '500':
          $ref: '#/components/responses/ComplianceServerError'
components:
  schemas:
    ComplianceAddScanRequest:
      title: ComplianceAddScanRequest
      type: object
      required:
        - scan_name
        - guardrails_name
        - provider
        - workspace_id
        - event_types
        - cursor_end_time
        - compliance_api_key
      description: >-
        Body of Add Compliance Scan. `scan_id` is generated for you — sending
        one is a `400`.
      properties:
        scan_name:
          type: string
          maxLength: 64
          description: >-
            A name unique within your project, and the value `X-Enkrypt-Scan`
            carries afterwards. Letters, numbers, spaces and `_ & - . /`; must
            start and end with a letter or a number.
          example: ChatGPT Enterprise
        guardrails_name:
          type: string
          description: >-
            The saved guardrail every message is evaluated against. Not verified
            at creation time, so a typo shows up later as a scan that flags
            nothing.
          example: My Guardrail
        provider:
          type: string
          enum:
            - openai
            - anthropic
          description: >-
            The provider the workspace lives on. Immutable after creation. Only
            `openai` is served today.
          example: openai
        workspace_id:
          type: string
          format: uuid
          description: >-
            The **ChatGPT workspace UUID**, not an OpenAI organization id — an
            organization id is accepted and then returns nothing forever.
            Immutable after creation.
        event_types:
          type: array
          minItems: 1
          items:
            type: string
            enum:
              - CONVERSATION_MESSAGE
              - CODEX_LOG
              - APP_LOG
              - CUSTOM_AGENTS_LOG
              - CHATGPT_PLUGIN_SPREADSHEET
          description: >-
            Which provider services to read. Must be non-empty, and every value
            must be one the workspace actually serves — Test Compliance
            Connection reports which do.
        cursor_end_time:
          type: string
          format: date-time
          description: >-
            Where reading starts, as an ISO 8601 timestamp. This decides how
            much history gets pulled.
        compliance_api_key:
          type: string
          format: password
          writeOnly: true
          description: >-
            The provider's compliance API key for that workspace. Stored
            encrypted and never returned.
        status:
          type: string
          enum:
            - active
            - paused
            - disabled
          default: active
          description: '`needs_reconnect` is not accepted here — only the scanner writes it.'
        list_interval_s:
          type: integer
          minimum: 1
          default: 60
          description: Seconds between polls.
        pending_cap:
          type: integer
          minimum: 1
          default: 5000
          description: How many events may be queued before the poller backs off.
    ComplianceScanResponse:
      title: ComplianceScanResponse
      type: object
      description: >-
        A write that returns the resulting scan. `warning` appears only when the
        record was saved but the scanning service could not be reached — the
        write stands and the scanner reconciles on its next pass.
      properties:
        scan:
          $ref: '#/components/schemas/ComplianceScan'
        warning:
          type: string
          description: >-
            Present only when the record was written but the scanning service
            did not respond.
    ComplianceScan:
      title: ComplianceScan
      type: object
      description: >-
        One compliance scan. `compliance_api_key` is deliberately absent — no
        endpoint returns the stored key, in plaintext or masked.
      properties:
        scan_id:
          type: string
          format: uuid
          description: >-
            Enkrypt's id for the scan. Returned for reference; you address a
            scan by name in `X-Enkrypt-Scan`, never by this.
        id:
          type: string
          format: uuid
          description: >-
            The owning account (your organization, or your user for an
            individual account).
        project_name:
          type: string
          description: >-
            The project the scan lives in. Taken from your API key, not from the
            request.
        scan_name:
          type: string
          description: >-
            The scan's name, unique within the project. This is the value
            `X-Enkrypt-Scan` carries.
        created_by:
          type: string
          format: uuid
          description: The platform user who created the scan.
        updated_by:
          type: string
          format: uuid
          description: >-
            The platform user who last edited it; the creator until someone else
            does.
        provider:
          type: string
          enum:
            - openai
            - anthropic
          description: >-
            The provider the workspace lives on. Immutable after creation. Only
            `openai` is served today.
        workspace_id:
          type: string
          format: uuid
          description: The ChatGPT workspace UUID being read. Immutable after creation.
        event_types:
          type: array
          items:
            type: string
            enum:
              - CONVERSATION_MESSAGE
              - CODEX_LOG
              - APP_LOG
              - CUSTOM_AGENTS_LOG
              - CHATGPT_PLUGIN_SPREADSHEET
          description: The provider services this scan reads. They share one cursor.
        guardrails_name:
          type: string
          description: The saved guardrail every message is evaluated against.
        cursor_end_time:
          type: string
          format: date-time
          description: >-
            How far through the provider's own timeline the scan has read. Set
            at creation, then advanced by the scan itself.
        cursor_file_id:
          type: string
          nullable: true
          description: The export file the cursor last sat on. For audit only.
        last_polled_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Updated on every successful poll, whether or not anything new came
            back — which is what tells a quiet workspace from a stopped scan.
            Null until the first poll.
        list_interval_s:
          type: integer
          description: Seconds between polls.
          default: 60
        pending_cap:
          type: integer
          description: How many events may be queued before the poller backs off.
          default: 5000
        status:
          type: string
          enum:
            - active
            - paused
            - disabled
            - needs_reconnect
          description: >-
            `active` is the only state that reads anything. `needs_reconnect` is
            written by the scanner when the provider rejects the stored key and
            can never be sent by a caller.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
          description: Moved by a user edit only. Cursor advances do not touch it.
    ComplianceErrorResponse:
      title: ComplianceErrorResponse
      type: object
      description: Error envelope returned by the compliance APIs.
      properties:
        error:
          type: string
          example: Scan not found
    ComplianceGatewayErrorResponse:
      title: ComplianceGatewayErrorResponse
      type: object
      description: >-
        Error envelope returned by the gateway for a request it refuses before
        it reaches the compliance service — an unknown body field, a value
        outside an enum, a malformed scan name, or a failed permission check.
      properties:
        code:
          type: integer
          example: 403
        error:
          type: string
          example: Forbidden
        message:
          type: string
          example: Access Denied
        request_id:
          type: string
        time:
          type: number
  responses:
    ComplianceBadRequest:
      description: >-
        Bad Request — a malformed or non-JSON body, an unknown or unexpected
        field, a value outside an enum, a missing or malformed `X-Enkrypt-Scan`,
        a missing `event_id`, out-of-range paging, an empty update, or an
        attempt to change `provider` / `workspace_id` / `scan_id`.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ComplianceErrorResponse'
              - $ref: '#/components/schemas/ComplianceGatewayErrorResponse'
    ComplianceUnauthorized:
      description: Unauthorized — missing or invalid `apikey` header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ComplianceGatewayErrorResponse'
    ComplianceForbidden:
      description: >-
        Forbidden — the caller does not hold the **governance officer** role on
        this project, or the account is an individual (non-organization)
        account, which cannot hold that role. The organization owner is not
        exempt: an owner without the role is refused here too.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ComplianceErrorResponse'
              - $ref: '#/components/schemas/ComplianceGatewayErrorResponse'
    ComplianceConflict:
      description: Conflict — a scan with that name already exists in this project.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ComplianceErrorResponse'
    ComplianceServerError:
      description: Internal Server Error.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ComplianceErrorResponse'
              - $ref: '#/components/schemas/ComplianceGatewayErrorResponse'
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: apikey

````