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

# Use the governance API

> Create frameworks and rules, attach evidence, and pull compliance status and audit-ready exports from Openlayer

Use the REST API to work with the compliance data shown in **Governance**, including frameworks,
requirements, rule results, and evidence. You can use this data in audit reports, internal dashboards,
or governance, risk, and compliance tools, and you can create and activate frameworks
programmatically.

## Authentication

Authenticate each request with a workspace API key:

```bash theme={null}
curl --request GET \
  --url https://api.openlayer.com/v1/projects \
  --header 'Authorization: Bearer <YOUR_API_KEY>'
```

See [Find your API key](/workspace-and-projects/find-your-api-key) if you don't have one. Governance
list endpoints use a workspace ID. Each project returned by
[List projects](/api-reference/rest/projects/list-projects) includes its `workspaceId`.

## Pull your compliance state

<Steps>
  <Step title="List your frameworks">
    Start with the frameworks in your workspace. Pass `enabled=true` to return only active
    frameworks.

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/frameworks?enabled=true' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    Each framework includes an `id` that you use in subsequent requests. Its `projectSelector`
    identifies the projects it covers.

    See [List frameworks](/api-reference/rest/governance/list-frameworks).
  </Step>

  <Step title="Read workspace statistics">
    Retrieve a compliance roll-up instead of counting rule results yourself. Add `frameworkId` to
    limit the response to one framework or `projectId` to limit it to one project.

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/rule-stats?frameworkId=<FRAMEWORK_ID>' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    See [Retrieve workspace compliance statistics](/api-reference/rest/governance/retrieve-rule-stats).
  </Step>

  <Step title="Break down compliance by project">
    Retrieve one row per project for a framework. The example sorts projects by the number of failing
    rule results.

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID>/project-rule-stats?sortColumn=totalFailing&asc=false' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    See [List a framework's per-project compliance](/api-reference/rest/governance/list-project-rule-stats).
  </Step>

  <Step title="Retrieve individual requirements">
    A rule is one requirement. A rule result is that requirement's status for a project, or for the
    workspace when `projectId` is `null`.

    List rule results and filter them by framework, project, rule, or `status`:

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/rule-results?frameworkId=<FRAMEWORK_ID>&status=failing&perPage=100' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    A result's `status` is `running`, `passing`, `failing`, `skipped`, `error`, `pending`, or
    `due_soon`. Its `statusMessage` provides a human-readable explanation, and its `ruleId` identifies
    the associated rule.

    You can also list rules with their results included:

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/rules?frameworkId=<FRAMEWORK_ID>&includeResults=true&perPage=100' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    See [List rule results](/api-reference/rest/governance/list-rule-results) and
    [List rules](/api-reference/rest/governance/list-rules).
  </Step>

  <Step title="Include framework document text">
    A framework document contains the source standard's text, sections, subsections, and mapped rules.
    List the documents first, then retrieve the document you need:

    ```bash theme={null}
    curl --request GET \
      --url https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID>/documents \
      --header 'Authorization: Bearer <YOUR_API_KEY>'

    curl --request GET \
      --url https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID>/documents/<DOCUMENT_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    To retrieve the rules and statuses for a specific part of the document, use its section or
    subsection endpoint with `includeResults=true`.

    See [Retrieve a framework document](/api-reference/rest/governance/retrieve-framework-document),
    [List a section's rules](/api-reference/rest/governance/list-section-rules), and
    [List a subsection's rules](/api-reference/rest/governance/list-subsection-rules).
  </Step>

  <Step title="Collect supporting evidence">
    For an evidence-based rule, retrieve the evidence attached to its rule result:

    ```bash theme={null}
    curl --request GET \
      --url https://api.openlayer.com/v1/rule-results/<RULE_RESULT_ID>/evidence \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    The evidence uses `storageUri` for an uploaded document, `text` for a written statement, or `url`
    for a link, according to the rule's `evidenceType`.

    See [List a rule result's evidence](/api-reference/rest/governance/list-rule-result-evidence).
  </Step>
</Steps>

## Create and activate a framework

Openlayer ships with built-in frameworks such as the EU AI Act and ISO/IEC 42001, and you can add
your own. Both are managed through the API.

<Steps>
  <Step title="Create a custom framework">
    Create a framework to track compliance against an internal policy, or against a standard
    Openlayer does not ship as a built-in framework. Only `name` is required:

    ```bash theme={null}
    curl --request POST \
      --url https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/frameworks \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{
        "name": "Internal AI Policy",
        "description": "Our internal requirements for AI systems in production.",
        "enabled": true,
        "tags": ["internal", "policy"]
      }'
    ```

    The response is the new framework, including the `id` you use in subsequent requests. A new
    framework has no rules — add them from the Openlayer app.

    Use `projectSelector` to scope the framework to a subset of projects. An empty or omitted
    selector applies it to every project in the workspace:

    ```json theme={null}
    {
      "name": "High-risk systems policy",
      "projectSelector": {
        "match": [{ "property": "riskLevel", "value": ["high", "critical"] }]
      }
    }
    ```

    See [Create a framework](/api-reference/rest/governance/create-framework).
  </Step>

  <Step title="Activate or deactivate a framework">
    A framework only counts towards compliance while it is enabled. Rules of a disabled framework
    are not evaluated. Activate one — built-in or custom — by setting `enabled`:

    ```bash theme={null}
    curl --request PUT \
      --url https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{"enabled": true}'
    ```

    Only the fields you send are changed. You can also update `tags`, `projectSelector`, `name`,
    `avatar`, `href`, and `extendedDescription`.

    <Note>
      Frameworks that ship with Openlayer report `immutable: true`. For those, only `enabled`,
      `tags`, and `projectSelector` can be changed — their name and definition are managed by
      Openlayer.
    </Note>

    See [Update a framework](/api-reference/rest/governance/update-framework).
  </Step>
</Steps>

## Manage rules and evidence

A rule is one requirement. A rule result is that requirement's status for a project, or for the
workspace when `projectId` is `null`.

<Steps>
  <Step title="Create a rule">
    A rule's `type` decides how it is satisfied, and the two types accept different fields.

    An **evidence** rule is satisfied by attaching evidence. Set `evidenceType` to the kind of
    evidence that satisfies it, and optionally `renewalCadenceDays` to require periodic renewal:

    ```bash theme={null}
    curl --request POST \
      --url https://api.openlayer.com/v1/workspaces/<WORKSPACE_ID>/rules \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{
        "name": "Annual model risk review",
        "description": "Each high-risk project is reviewed and signed off once a year.",
        "scope": "project",
        "type": "evidence",
        "evidenceType": "document",
        "renewalCadenceDays": 365
      }'
    ```

    A **platform** rule is evaluated automatically from the state of your workspace. Set
    `automationType` to the signal to check. Its `scope` must be `project`, and `evidenceType` and
    `renewalCadenceDays` must be omitted:

    ```json theme={null}
    {
      "name": "Monitoring enabled",
      "scope": "project",
      "type": "platform",
      "automationType": "monitoring_mode_enabled"
    }
    ```

    `name`, `scope`, and `type` are required. A new rule belongs to no framework — map it to one
    from the Openlayer app.

    See [Create a rule](/api-reference/rest/governance/create-rule).
  </Step>

  <Step title="Update or delete a rule">
    Only the fields you send are changed. A rule's `scope`, `type`, `evidenceType`, and automation
    are fixed once it exists.

    ```bash theme={null}
    curl --request PUT \
      --url https://api.openlayer.com/v1/rules/<RULE_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{"deactivated": true, "assigneeId": "<USER_ID>"}'
    ```

    Deleting a rule also deletes its rule results:

    ```bash theme={null}
    curl --request DELETE \
      --url https://api.openlayer.com/v1/rules/<RULE_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    <Note>
      Rules that ship with Openlayer report `immutable: true` and can be neither edited nor
      deleted. To exclude one from compliance, set `deactivated` on its rule result instead.
    </Note>

    See [Update a rule](/api-reference/rest/governance/update-rule) and
    [Delete a rule](/api-reference/rest/governance/delete-rule).
  </Step>

  <Step title="Assign or exclude a rule result">
    Assign an owner, or exclude a single result from compliance without deactivating the rule
    everywhere. `deactivatedReason` is required when deactivating:

    ```bash theme={null}
    curl --request PATCH \
      --url https://api.openlayer.com/v1/rule-results/<RULE_RESULT_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{
        "deactivated": true,
        "deactivatedReason": "Not applicable to this project."
      }'
    ```

    A result's `status` is computed by Openlayer and cannot be set directly.

    See [Update a rule result](/api-reference/rest/governance/update-rule-result).
  </Step>

  <Step title="Attach evidence">
    Send the field that matches the rule's `evidenceType`: `text` for a written statement, `url`
    for a link, or `storageUri` for an uploaded document.

    ```bash theme={null}
    curl --request POST \
      --url https://api.openlayer.com/v1/rule-results/<RULE_RESULT_ID>/evidence \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{
        "name": "2026 model risk review",
        "description": "Signed off by the risk committee.",
        "url": "https://example.com/reviews/2026-model-risk.pdf"
      }'
    ```

    For a document, upload the file first with
    [Create a presigned URL](/api-reference/rest/development/presigned-url) and send the resulting
    storage URI as `storageUri`.

    Attaching evidence re-evaluates the rule result. If the rule sets `renewalCadenceDays`, the
    renewal window restarts from this evidence.

    See [Attach evidence to a rule result](/api-reference/rest/governance/create-rule-result-evidence).
  </Step>
</Steps>

## Export an audit-ready archive

You can export a framework's evidence and progress as a zip archive. The archive contains uploaded
evidence files, a Markdown progress report, and CSV manifests of rules and evidence with SHA-256
checksums.

<Steps>
  <Step title="Queue the export">
    To export the workspace-wide view across every project in the framework, omit the request body:

    ```bash theme={null}
    curl --request POST \
      --url https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID>/export \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    To export one project, include its `projectId`:

    ```bash theme={null}
    curl --request POST \
      --url https://api.openlayer.com/v1/frameworks/<FRAMEWORK_ID>/export \
      --header 'Authorization: Bearer <YOUR_API_KEY>' \
      --header 'Content-Type: application/json' \
      --data '{"projectId": "<PROJECT_ID>"}'
    ```

    The API returns `202` with the path and ID of the background task:

    ```json theme={null}
    {
      "taskResultUrl": "/v1/background-tasks/<TASK_ID>",
      "taskResultId": "<TASK_ID>"
    }
    ```

    Export requests are limited to two per minute for each framework. If an identical export is
    already queued, the API returns that task instead of starting another one.

    See [Export a framework](/api-reference/rest/governance/export-framework).
  </Step>

  <Step title="Wait for the archive">
    Poll the background task using `taskResultId`:

    ```bash theme={null}
    curl --request GET \
      --url https://api.openlayer.com/v1/background-tasks/<TASK_ID> \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    Continue until `complete` is `true`. If `error` is not `null`, it explains why the task failed.
    A completed export returns `outputs.storageUri` and also includes `filename`, `controlCount`,
    `evidenceCount`, and `missingEvidenceCount`.

    See [Retrieve a background task](/api-reference/rest/background-tasks/retrieve-background-task).
  </Step>

  <Step title="Download the archive">
    Exchange `outputs.storageUri` for a short-lived download URL. Use URL encoding because a storage
    URI contains reserved characters:

    ```bash theme={null}
    curl --request GET \
      --get https://api.openlayer.com/v1/storage/presigned-url \
      --data-urlencode 'storageUri=<STORAGE_URI>' \
      --header 'Authorization: Bearer <YOUR_API_KEY>'
    ```

    The response contains a `url`. Download it promptly:

    ```bash theme={null}
    curl --location --output <FILENAME>.zip '<DOWNLOAD_URL>'
    ```

    See [Retrieve a download URL](/api-reference/rest/development/retrieve-download-url).
  </Step>
</Steps>

## Pagination

List endpoints accept `page` and `perPage`, with up to 100 items per page. Request successive pages
until a response contains fewer items than `perPage`.

<Note>
  Mapping a rule to a framework, and editing a framework's document text, are
  not yet part of the public API — do those in the Openlayer app. See [Set up a
  framework](/governance/activate-framework).
</Note>
