API Reference

Compliance

The compliance register helps you prepare for the EU AI Act. An AI system is an entry in the register: something your organisation builds, buys or uses, with its purpose, the data it processes and its risk tier under the Act. A risk is a finding against an AI system, mapped to an article of the Act (for example Art. 14 or Annex IV), with a severity and a status. An action is a remediation task for a risk. A repository registration links a GitHub repository to an AI system so that it can be scanned for risks.

The register is personal. Every AI system, registration, risk and action belongs to the user who created it, and other users, including colleagues in your organisation, cannot see or change it. List endpoints return every matching record in one response; they are not paginated.

Responses are wrapped in an envelope: {"success": true, "data": …} on success and {"success": false, "error": "…"} on failure. Timestamps set by the API (created_at, updated_at, registered_at, last_scan_at, completed_at) are UTC, in ISO 8601 format without a time zone designator.

The AI system object

An entry in your AI system register, returned in data.

Attributes

  • id string

    Unique identifier for the AI system (UUID).

  • owner_user_id integer

    ID of the user who owns this entry.

  • name string

    Name of the AI system.

  • owner nullable string

    Person or team accountable for the system. Free text.

  • use_case nullable string

    What the system is used for.

  • data_processed nullable string

    The data the system processes.

  • user_count nullable integer

    Number of people who use the system.

  • source string

    How the system entered your organisation: internal (built in-house), vendor (bought from a supplier), shadow (in use without formal approval) or integration (imported from a connected integration).

  • vendor nullable string

    Supplier of the system, for bought-in systems.

  • risk_tier string

    Risk tier under the EU AI Act: unacceptable, high, limited, minimal, or unclassified until the system has been assessed.

  • annex_iii_category nullable string

    The Annex III high-risk area the system falls under, such as 4(a) for recruitment and selection.

  • classification_rationale nullable string

    Why the system was given its risk tier.

  • classified_at nullable string

    When the system was classified.

  • has_documentation boolean

    Whether technical documentation exists for the system.

  • has_oversight boolean

    Whether human oversight measures are in place.

  • integration_source nullable string

    The integration the entry was imported from, such as github, jira, confluence or data_connection.

  • integration_ref object

    Identifiers of the source record in that integration, for example a repository's full_name. An empty object when there is none.

  • created_at string

    When the entry was created.

  • updated_at string

    When the entry was last changed.

The AI system object
{
  "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
  "owner_user_id": 42,
  "name": "Candidate screening assistant",
  "owner": "Talent acquisition",
  "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
  "data_processed": "CVs, cover letters and assessment scores",
  "user_count": 35,
  "source": "vendor",
  "vendor": "Contoso HR",
  "risk_tier": "high",
  "annex_iii_category": "4(a)",
  "classification_rationale": "Evaluates candidates during recruitment, an Annex III point 4(a) use.",
  "classified_at": "2026-09-01T09:30:00",
  "has_documentation": false,
  "has_oversight": true,
  "integration_source": null,
  "integration_ref": {},
  "created_at": "2026-08-28T14:02:11.604218",
  "updated_at": "2026-09-01T09:30:00.412345"
}

List AI systems

GET /agent-hub-api/api/compliance/systems

Returns the AI systems in your register.

Returns every AI system you own, most recently updated first.

Authentication
Bearer token How it works

Parameters

No parameters.

Returns

Returns a list of AI system objects in data.

Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/systems" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": [
    {
      "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
      "owner_user_id": 42,
      "name": "Candidate screening assistant",
      "owner": "Talent acquisition",
      "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
      "data_processed": "CVs, cover letters and assessment scores",
      "user_count": 35,
      "source": "vendor",
      "vendor": "Contoso HR",
      "risk_tier": "high",
      "annex_iii_category": "4(a)",
      "classification_rationale": "Evaluates candidates during recruitment, an Annex III point 4(a) use.",
      "classified_at": "2026-09-01T09:30:00",
      "has_documentation": false,
      "has_oversight": true,
      "integration_source": null,
      "integration_ref": {},
      "created_at": "2026-08-28T14:02:11.604218",
      "updated_at": "2026-09-01T09:30:00.412345"
    }
  ]
}

Create an AI system

POST /agent-hub-api/api/compliance/systems

Adds an AI system to your register.

Creates an AI system owned by you. Only name is required; a new system starts as unclassified unless you send a risk_tier.

Authentication
Bearer token How it works

Body parameters application/json

  • name string Required

    Name of the AI system. At most 200 characters.

  • source string

    How the system entered your organisation. Case-insensitive.

    Defaults to internal.

    Possible values
    • internal
    • vendor
    • shadow
    • integration
  • risk_tier string

    Risk tier under the EU AI Act. Case-insensitive.

    Defaults to unclassified.

    Possible values
    • unacceptable
    • high
    • limited
    • minimal
    • unclassified
  • owner string

    Person or team accountable for the system. At most 200 characters.

  • use_case string

    What the system is used for.

  • data_processed string

    The data the system processes.

  • user_count integer

    Number of people who use the system.

  • vendor string

    Supplier of the system. At most 200 characters.

  • annex_iii_category string

    The Annex III high-risk area, such as 4(a). At most 200 characters.

  • classification_rationale string

    Why the system has its risk tier.

  • classified_at string

    When the system was classified, as an ISO 8601 date or date-time. A value that cannot be parsed is stored as null.

  • has_documentation boolean

    Whether technical documentation exists for the system.

    Defaults to false.

  • has_oversight boolean

    Whether human oversight measures are in place.

    Defaults to false.

  • integration_source string

    The integration the entry comes from, such as github. At most 30 characters.

  • integration_ref object

    Identifiers of the source record in that integration.

    Defaults to {}.

Returns

Returns the new AI system object in data.

Errors

  • 400 name is missing or empty, or source or risk_tier is not one of the allowed values.
Request
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/systems" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Candidate screening assistant",
    "owner": "Talent acquisition",
    "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
    "data_processed": "CVs, cover letters and assessment scores",
    "user_count": 35,
    "source": "vendor",
    "vendor": "Contoso HR",
    "has_oversight": true
  }'
Response 201
{
  "success": true,
  "data": {
    "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
    "owner_user_id": 42,
    "name": "Candidate screening assistant",
    "owner": "Talent acquisition",
    "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
    "data_processed": "CVs, cover letters and assessment scores",
    "user_count": 35,
    "source": "vendor",
    "vendor": "Contoso HR",
    "risk_tier": "unclassified",
    "annex_iii_category": null,
    "classification_rationale": null,
    "classified_at": null,
    "has_documentation": false,
    "has_oversight": true,
    "integration_source": null,
    "integration_ref": {},
    "created_at": "2026-08-28T14:02:11.604218",
    "updated_at": "2026-08-28T14:02:11.604218"
  }
}

Retrieve an AI system

GET /agent-hub-api/api/compliance/systems/{system_id}

Returns one AI system from your register.

Authentication
Bearer token How it works

Path parameters

  • system_id string Required

    ID of the AI system (UUID).

Returns

Returns the AI system object in data.

Errors

  • 404 You have no AI system with this ID.
Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": {
    "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
    "owner_user_id": 42,
    "name": "Candidate screening assistant",
    "owner": "Talent acquisition",
    "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
    "data_processed": "CVs, cover letters and assessment scores",
    "user_count": 35,
    "source": "vendor",
    "vendor": "Contoso HR",
    "risk_tier": "high",
    "annex_iii_category": "4(a)",
    "classification_rationale": "Evaluates candidates during recruitment, an Annex III point 4(a) use.",
    "classified_at": "2026-09-01T09:30:00",
    "has_documentation": false,
    "has_oversight": true,
    "integration_source": null,
    "integration_ref": {},
    "created_at": "2026-08-28T14:02:11.604218",
    "updated_at": "2026-09-01T09:30:00.412345"
  }
}

Update an AI system

PATCH /agent-hub-api/api/compliance/systems/{system_id}

Updates fields of one of your AI systems.

Changes only the fields you send. Sending null clears an optional field. An empty or null source or risk_tier leaves the current value in place. To record a classification, send risk_tier together with annex_iii_category, classification_rationale and classified_at.

Authentication
Bearer token How it works

Path parameters

  • system_id string Required

    ID of the AI system (UUID).

Body parameters application/json

  • name string

    Name of the AI system. At most 200 characters.

  • source string

    How the system entered your organisation. Case-insensitive.

    Possible values
    • internal
    • vendor
    • shadow
    • integration
  • risk_tier string

    Risk tier under the EU AI Act. Case-insensitive.

    Possible values
    • unacceptable
    • high
    • limited
    • minimal
    • unclassified
  • owner string

    Person or team accountable for the system. At most 200 characters.

  • use_case string

    What the system is used for.

  • data_processed string

    The data the system processes.

  • user_count integer

    Number of people who use the system.

  • vendor string

    Supplier of the system. At most 200 characters.

  • annex_iii_category string

    The Annex III high-risk area, such as 4(a). At most 200 characters.

  • classification_rationale string

    Why the system has its risk tier.

  • classified_at string

    When the system was classified, as an ISO 8601 date or date-time. null or a value that cannot be parsed clears it.

  • has_documentation boolean

    Whether technical documentation exists for the system.

  • has_oversight boolean

    Whether human oversight measures are in place.

  • integration_source string

    The integration the entry comes from. At most 30 characters.

  • integration_ref object

    Identifiers of the source record in that integration. null resets it to an empty object.

Returns

Returns the updated AI system object in data.

Errors

  • 400 source or risk_tier is not one of the allowed values.
  • 404 You have no AI system with this ID.
Request
curl -X PATCH "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "risk_tier": "high",
    "annex_iii_category": "4(a)",
    "classification_rationale": "Evaluates candidates during recruitment, an Annex III point 4(a) use.",
    "classified_at": "2026-09-01T09:30:00"
  }'
Response 200
{
  "success": true,
  "data": {
    "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
    "owner_user_id": 42,
    "name": "Candidate screening assistant",
    "owner": "Talent acquisition",
    "use_case": "Ranks incoming job applications and drafts shortlists for recruiters.",
    "data_processed": "CVs, cover letters and assessment scores",
    "user_count": 35,
    "source": "vendor",
    "vendor": "Contoso HR",
    "risk_tier": "high",
    "annex_iii_category": "4(a)",
    "classification_rationale": "Evaluates candidates during recruitment, an Annex III point 4(a) use.",
    "classified_at": "2026-09-01T09:30:00",
    "has_documentation": false,
    "has_oversight": true,
    "integration_source": null,
    "integration_ref": {},
    "created_at": "2026-08-28T14:02:11.604218",
    "updated_at": "2026-09-01T09:30:00.412345"
  }
}

Delete an AI system

DEL /agent-hub-api/api/compliance/systems/{system_id}

Deletes one of your AI systems and its repository registrations.

Deletes the AI system permanently, together with its repository registrations. Risks linked to the system are kept, with ai_system_id set to null, and so are their actions.

Authentication
Bearer token How it works

Path parameters

  • system_id string Required

    ID of the AI system (UUID).

Returns

Returns the ID of the deleted AI system in data.id in data.

Errors

  • 404 You have no AI system with this ID.
Request
curl -X DELETE "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": {
    "id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90"
  }
}

Discover integrations

GET /agent-hub-api/api/compliance/integrations/discover

Returns the integrations connected to your account that you can import as AI systems.

Looks up what you have already connected — GitHub, Jira, Confluence and your data connections — so that you can pick items to add with Import integrations. Nothing is created or changed.

  • GitHub: when your GitHub account is connected, the repositories it can access as owner, collaborator or organisation member are fetched live from GitHub, most recently updated first, up to 200. This can take several seconds.
  • Jira and Confluence: up to 5 active connections each.
  • Data connections: the connections you own, most recently updated first, up to 200.

A source that cannot be read is reported as not connected or empty; the request itself does not fail.

Authentication
Bearer token How it works

Query parameters

  • include_github_repos boolean

    Set to false to skip fetching repositories from GitHub. github.connected is still reported.

    Defaults to true.

Returns

Returns data with one entry per source: github (connected and repos), jira and confluence (connected and workspaces), and data_connections.

Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/integrations/discover" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": {
    "github": {
      "connected": true,
      "repos": [
        {
          "id": "781234567",
          "full_name": "northwind/claims-triage",
          "name": "claims-triage",
          "private": true,
          "default_branch": "main",
          "description": "Scores incoming insurance claims and routes them to adjusters.",
          "language": "Python",
          "html_url": "https://github.example.com/northwind/claims-triage",
          "updated_at": "2026-08-30T14:12:09"
        }
      ]
    },
    "jira": {
      "connected": true,
      "workspaces": [
        {
          "id": "3",
          "cloud_id": "5e0b9d2a-7c4f-4e1b-8a36-d2f9c0e7b184",
          "username": "ada.lovelace@example.com",
          "label": "Jira • ada.lovelace@example.com"
        }
      ]
    },
    "confluence": {
      "connected": false,
      "workspaces": []
    },
    "data_connections": [
      {
        "id": "a91c4e7f-3d2b-4f8a-b5e6-7c0d1f9e2a38",
        "name": "Claims warehouse",
        "type": "microsoft-sql-server",
        "status": "connected",
        "description": "Historical claims and payouts",
        "host": "sql01.example.com",
        "database_name": "claims",
        "capabilities": [
          "test-connection",
          "discover-assets",
          "extract-to-vector",
          "extract-to-finetune"
        ]
      }
    ]
  }
}

Import integrations

POST /agent-hub-api/api/compliance/systems/import

Creates AI systems from the integrations you select and registers GitHub repositories for scanning.

Send the items you picked from Discover integrations, in the same shape. Each item becomes an AI system with risk_tier unclassified:

  • A GitHub repository becomes an internal system named after the repository, and a repository registration is created so that you can prepare a repository scan. A repository you have already registered is skipped, so repeating the call is safe for repositories.
  • A data connection, Jira workspace or Confluence workspace becomes an integration system. These are not de-duplicated: importing the same item twice creates two systems.

Items without their key field (full_name, id or cloud_id) are skipped. The import is all or nothing: if saving any item fails, nothing is saved.

Authentication
Bearer token How it works

Body parameters application/json

  • github_repos array of objects

    GitHub repositories to import.

    Show child parameters Hide child parameters
    • full_name string

      Repository in owner/name form. Items without it are skipped. At most 300 characters.

    • id string

      GitHub's ID for the repository.

    • name string

      Name for the AI system. Defaults to full_name.

    • owner string

      Owner recorded on the AI system. Defaults to the part of full_name before the slash.

    • default_branch string

      Branch to scan.

      Defaults to main.

    • language string

      Main language of the repository, mentioned in the system's use_case.

    • html_url string

      Web address of the repository, kept in integration_ref.

  • data_connections array of objects

    Data connections to import.

    Show child parameters Hide child parameters
    • id string

      ID of the data connection. Items without it are skipped.

    • name string

      Name for the AI system.

      Defaults to Data connection.

    • owner string

      Owner recorded on the AI system.

      Defaults to Data team.

    • type string

      Connection type, mentioned in the system's use_case.

    • description string

      Stored as the system's data_processed.

    • host string

      Host of the connection, kept in integration_ref.

    • database_name string

      Database of the connection, kept in integration_ref.

  • jira_workspaces array of objects

    Jira workspaces to import.

    Show child parameters Hide child parameters
    • cloud_id string

      Jira site ID. Items without it are skipped.

    • label string

      Name for the AI system.

      Defaults to Jira workspace.

    • username string

      Account the workspace is connected with, recorded as the system's owner.

  • confluence_workspaces array of objects

    Confluence workspaces to import.

    Show child parameters Hide child parameters
    • cloud_id string

      Confluence site ID. Items without it are skipped.

    • label string

      Name for the AI system.

      Defaults to Confluence workspace.

    • username string

      Account the workspace is connected with, recorded as the system's owner.

Returns

Returns data.systems, the AI system objects created, and data.repos, the repository registrations created. Both lists are empty when every item was skipped in data.

Request
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/import" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "github_repos": [
      {
        "id": "781234567",
        "full_name": "northwind/claims-triage",
        "name": "claims-triage",
        "default_branch": "main",
        "language": "Python",
        "html_url": "https://github.example.com/northwind/claims-triage"
      }
    ],
    "jira_workspaces": [
      {
        "cloud_id": "5e0b9d2a-7c4f-4e1b-8a36-d2f9c0e7b184",
        "username": "ada.lovelace@example.com",
        "label": "Jira • ada.lovelace@example.com"
      }
    ]
  }'
Response 201
{
  "success": true,
  "data": {
    "systems": [
      {
        "id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
        "owner_user_id": 42,
        "name": "claims-triage",
        "owner": "northwind",
        "use_case": "Source code repository tracked for EU AI Act compliance (Python).",
        "data_processed": null,
        "user_count": null,
        "source": "internal",
        "vendor": null,
        "risk_tier": "unclassified",
        "annex_iii_category": null,
        "classification_rationale": null,
        "classified_at": null,
        "has_documentation": false,
        "has_oversight": false,
        "integration_source": "github",
        "integration_ref": {
          "repo_id": "781234567",
          "full_name": "northwind/claims-triage",
          "default_branch": "main",
          "html_url": "https://github.example.com/northwind/claims-triage"
        },
        "created_at": "2026-09-02T08:15:42.120931",
        "updated_at": "2026-09-02T08:15:42.120931"
      },
      {
        "id": "c3e1a7b4-5d2f-4e8a-b691-7f0d3c2e5a18",
        "owner_user_id": 42,
        "name": "Jira • ada.lovelace@example.com",
        "owner": "ada.lovelace@example.com",
        "use_case": "Jira workspace integrated for governance tracking.",
        "data_processed": null,
        "user_count": null,
        "source": "integration",
        "vendor": null,
        "risk_tier": "unclassified",
        "annex_iii_category": null,
        "classification_rationale": null,
        "classified_at": null,
        "has_documentation": false,
        "has_oversight": false,
        "integration_source": "jira",
        "integration_ref": {
          "cloud_id": "5e0b9d2a-7c4f-4e1b-8a36-d2f9c0e7b184",
          "username": "ada.lovelace@example.com"
        },
        "created_at": "2026-09-02T08:15:42.121874",
        "updated_at": "2026-09-02T08:15:42.121874"
      }
    ],
    "repos": [
      {
        "id": "2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65",
        "ai_system_id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
        "user_id": 42,
        "repo_id": "781234567",
        "repo_full_name": "northwind/claims-triage",
        "default_branch": "main",
        "last_scan_run_id": null,
        "last_scan_at": null,
        "registered_at": "2026-09-02T08:15:42.121302",
        "updated_at": "2026-09-02T08:15:42.121302"
      }
    ]
  }
}

List repository registrations

GET /agent-hub-api/api/compliance/repos

Returns the GitHub repositories you have registered for scanning.

Returns your repository registrations, most recently registered first. Registrations are created by Import integrations and deleted together with their AI system. last_scan_run_id and last_scan_at show the most recent scan run you recorded.

Authentication
Bearer token How it works

Parameters

No parameters.

Returns

Returns a list of repository registrations in data.

Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/repos" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": [
    {
      "id": "2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65",
      "ai_system_id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
      "user_id": 42,
      "repo_id": "781234567",
      "repo_full_name": "northwind/claims-triage",
      "default_branch": "main",
      "last_scan_run_id": "6c2b8e4f-9a1d-4f3c-b7e5-2d8a0f6c3b91",
      "last_scan_at": "2026-09-02T08:21:07.845113",
      "registered_at": "2026-09-02T08:15:42.121302",
      "updated_at": "2026-09-02T08:21:07.846020"
    }
  ]
}

Prepare a repository scan

POST /agent-hub-api/api/compliance/repos/{repo_reg_id}/scan

Returns the agent run that scans a registered repository, or records the ID of a scan run you started.

This endpoint does not run anything itself. A scan is a sequence of calls your client makes:

  1. Call this endpoint without a body. It returns 202 with the agent_name, prompt and context for the scan.
  2. Send those three fields unchanged to Run an agent. The scan agent analyses the repository and answers, in the run's output, with a JSON report: a risks list whose entries carry title, description, eu_ai_act_article, severity, evidence and suggested actions, each with a title and priority. The report is model-generated, so validate it before you use it.
  3. Call this endpoint again with run_id set to the run's execution_id. It records the run on the registration and returns 200.
  4. Record the findings with Create a risk and Create an action. Send source github_scan and a stable dedup_key per finding so that repeated scans do not create duplicates.

Nothing is written to your risks or actions until you create them in step 4.

Authentication
Bearer token How it works

Path parameters

Body parameters application/json

  • run_id string

    ID of the scan run you started. When present, it is stored as the registration's last_scan_run_id, last_scan_at is set to now, and the updated registration is returned instead of a run payload. At most 120 characters.

Returns

Without run_id, returns 202 and data with agent_name, prompt and context to pass to Run an agent. With run_id, returns 200 and data.repo, the updated repository registration.

Errors

  • 404 You have no repository registration with this ID.
Request
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/repos/2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65/scan" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 202
{
  "success": true,
  "data": {
    "agent_name": "github_eu_aiact_repo_scan",
    "prompt": "Scan the GitHub repository `northwind/claims-triage` (branch `main`) for EU AI Act compliance risks. Use ONLY this repo_full_name when calling tools — do not use any example values from the system prompt.\n\nrepo_full_name: northwind/claims-triage\ndefault_branch: main\nai_system_id: 9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73\nregistration_id: 2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65\n\nEmit the structured JSON report exactly as the system prompt specifies, with risks mapped to EU AI Act articles and suggested remediation actions.",
    "context": {
      "repo_full_name": "northwind/claims-triage",
      "default_branch": "main",
      "ai_system_id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
      "registration_id": "2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65"
    }
  }
}

List risks

GET /agent-hub-api/api/compliance/risks

Returns your compliance risks, optionally filtered.

Returns your risks, most recently updated first. Filters combine: a risk must match all of them. Repeat severity or status to match any of several values, for example ?status=open&status=in_progress. Values are matched exactly, so send them in lower case.

Authentication
Bearer token How it works

Query parameters

  • ai_system_id string

    Only return risks linked to this AI system.

  • severity array of strings

    Only return risks with this severity: unacceptable, high, limited, minimal or info. Repeatable.

  • status array of strings

    Only return risks with this status: open, in_progress, mitigated, accepted or withdrawn. Repeatable.

  • eu_ai_act_article string

    Only return risks mapped to this article, matched exactly, such as Art. 14.

Returns

Returns a list of risks in data.

Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/risks?ai_system_id=0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90&status=open" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": [
    {
      "id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
      "ai_system_id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
      "owner_user_id": 42,
      "source": "manual",
      "source_ref": null,
      "dedup_key": null,
      "title": "No human review before candidates are rejected",
      "description": "Applications scored below the threshold are rejected automatically, without a recruiter seeing them.",
      "eu_ai_act_article": "Art. 14",
      "severity": "high",
      "status": "open",
      "evidence": {
        "observed_in": "Screening workflow, step 3"
      },
      "created_by": 42,
      "created_at": "2026-09-01T10:05:19.337461",
      "updated_at": "2026-09-01T10:05:19.337461"
    }
  ]
}

Create a risk

POST /agent-hub-api/api/compliance/risks

Records a compliance risk.

Creates a risk owned by you. If you send a dedup_key that matches one of your existing risks, nothing is created: that risk is returned unchanged with status 200. Use this to record scan findings idempotently.

Authentication
Bearer token How it works

Body parameters application/json

  • title string Required

    Short statement of the risk. At most 300 characters.

  • severity string

    How serious the risk is, using the EU AI Act tiers plus info for observations. Case-insensitive.

    Defaults to info.

    Possible values
    • unacceptable
    • high
    • limited
    • minimal
    • info
  • status string

    Where the risk stands. Case-insensitive.

    Defaults to open.

    Possible values
    • open
    • in_progress
    • mitigated
    • accepted
    • withdrawn
  • ai_system_id string

    ID of the AI system the risk relates to (UUID).

  • description string

    Details of the finding.

  • eu_ai_act_article string

    Article of the Act the risk relates to, such as Art. 9, Art. 14 or Annex IV. At most 60 characters.

  • source string

    Where the finding came from. The product uses manual, classification, github_scan and gap_report. Stored in lower case; at most 30 characters.

    Defaults to manual.

  • source_ref string

    Reference to the origin of the finding, such as the ID of the scan run. At most 200 characters.

  • dedup_key string

    Your own stable key for the finding, such as github_scan:<registration_id>:<finding>. At most 200 characters.

  • evidence object

    Supporting evidence, such as the tool and file that revealed the finding.

    Defaults to {}.

Returns

Returns the risk in data: the new risk with status 201, or the existing risk with the same dedup_key with status 200.

Errors

  • 400 title is missing or empty, or severity or status is not one of the allowed values.
Request
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/risks" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ai_system_id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
    "title": "Training data sources are not documented",
    "description": "The repository loads claim histories from three sources, but none of them is described in the model documentation.",
    "eu_ai_act_article": "Art. 10",
    "severity": "high",
    "source": "github_scan",
    "source_ref": "6c2b8e4f-9a1d-4f3c-b7e5-2d8a0f6c3b91",
    "dedup_key": "github_scan:2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65:training-data-sources-are-not-documented",
    "evidence": {
      "tool": "repo_map",
      "ref": "training/load_claims"
    }
  }'
Response 201
{
  "success": true,
  "data": {
    "id": "e8a3f6d1-2c7b-4f5e-a9d0-3b6c1e8f2a47",
    "ai_system_id": "9d4c2f61-3b8e-4a7d-8c15-6e2f0a9b4d73",
    "owner_user_id": 42,
    "source": "github_scan",
    "source_ref": "6c2b8e4f-9a1d-4f3c-b7e5-2d8a0f6c3b91",
    "dedup_key": "github_scan:2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65:training-data-sources-are-not-documented",
    "title": "Training data sources are not documented",
    "description": "The repository loads claim histories from three sources, but none of them is described in the model documentation.",
    "eu_ai_act_article": "Art. 10",
    "severity": "high",
    "status": "open",
    "evidence": {
      "tool": "repo_map",
      "ref": "training/load_claims"
    },
    "created_by": 42,
    "created_at": "2026-09-02T08:21:09.502877",
    "updated_at": "2026-09-02T08:21:09.502877"
  }
}

Update a risk

PATCH /agent-hub-api/api/compliance/risks/{risk_id}

Updates fields of one of your risks.

Changes only the fields you send. dedup_key cannot be changed. Send ai_system_id as null to unlink the risk from its AI system.

Authentication
Bearer token How it works

Path parameters

  • risk_id string Required

    ID of the risk (UUID).

Body parameters application/json

  • status string

    Where the risk stands. Case-insensitive.

    Possible values
    • open
    • in_progress
    • mitigated
    • accepted
    • withdrawn
  • severity string

    How serious the risk is. Case-insensitive.

    Possible values
    • unacceptable
    • high
    • limited
    • minimal
    • info
  • title string

    Short statement of the risk. At most 300 characters.

  • description string

    Details of the finding.

  • eu_ai_act_article string

    Article of the Act the risk relates to. At most 60 characters.

  • ai_system_id string

    ID of the AI system the risk relates to (UUID), or null.

  • evidence object

    Supporting evidence. Replaces the stored object; null resets it to an empty object.

  • source string

    Where the finding came from. At most 30 characters.

  • source_ref string

    Reference to the origin of the finding. At most 200 characters.

Returns

Returns the updated risk in data.

Errors

  • 400 severity or status is empty or not one of the allowed values.
  • 404 You have no risk with this ID.
Request
curl -X PATCH "$VDF_BASE_URL/agent-hub-api/api/compliance/risks/b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "in_progress"
  }'
Response 200
{
  "success": true,
  "data": {
    "id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
    "ai_system_id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
    "owner_user_id": 42,
    "source": "manual",
    "source_ref": null,
    "dedup_key": null,
    "title": "No human review before candidates are rejected",
    "description": "Applications scored below the threshold are rejected automatically, without a recruiter seeing them.",
    "eu_ai_act_article": "Art. 14",
    "severity": "high",
    "status": "in_progress",
    "evidence": {
      "observed_in": "Screening workflow, step 3"
    },
    "created_by": 42,
    "created_at": "2026-09-01T10:05:19.337461",
    "updated_at": "2026-09-03T16:40:02.918305"
  }
}

List actions

GET /agent-hub-api/api/compliance/actions

Returns the remediation actions on your risks, optionally filtered.

Returns the actions attached to your risks, most recently updated first. Repeat status to match any of several values.

Authentication
Bearer token How it works

Query parameters

  • risk_id string

    Only return actions for this risk.

  • status array of strings

    Only return actions with this status: todo, in_progress, done or blocked. Repeatable.

Returns

Returns a list of actions in data.

Request
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/actions?risk_id=b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "data": [
    {
      "id": "4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73",
      "risk_id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
      "title": "Require recruiter sign-off before automated rejections",
      "description": "Route every rejection proposed by the assistant to a recruiter for approval.",
      "owner_user_id": 57,
      "due_date": "2026-10-15T00:00:00",
      "status": "in_progress",
      "priority": "p0",
      "notes": "Agreed with Grace Hopper in the hiring review.",
      "completed_at": null,
      "created_at": "2026-09-01T10:12:44.081259",
      "updated_at": "2026-09-03T16:41:30.270114"
    }
  ]
}

Create an action

POST /agent-hub-api/api/compliance/actions

Adds a remediation action to one of your risks.

Creates an action on a risk you own. owner_user_id records who is responsible for the action; it does not share it. Actions are visible only to the owner of their risk.

Authentication
Bearer token How it works

Body parameters application/json

  • risk_id string Required

    ID of the risk the action addresses (UUID).

  • title string Required

    What needs to be done. At most 300 characters.

  • priority string

    Urgency, p0 being the most urgent. Case-insensitive.

    Defaults to p2.

    Possible values
    • p0
    • p1
    • p2
  • status string

    Progress of the action. Case-insensitive.

    Defaults to todo.

    Possible values
    • todo
    • in_progress
    • done
    • blocked
  • description string

    Details of the action.

  • owner_user_id integer

    ID of the user responsible for the action. Defaults to you.

  • due_date string

    Deadline, as an ISO 8601 date or date-time. A value that cannot be parsed is stored as null.

  • notes string

    Free-text notes.

Returns

Returns the new action in data.

Errors

  • 400 risk_id or title is missing, or status or priority is not one of the allowed values.
  • 404 You have no risk with the given risk_id.
Request
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/actions" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "risk_id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
    "title": "Require recruiter sign-off before automated rejections",
    "description": "Route every rejection proposed by the assistant to a recruiter for approval.",
    "priority": "p0",
    "owner_user_id": 57,
    "due_date": "2026-10-15"
  }'
Response 201
{
  "success": true,
  "data": {
    "id": "4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73",
    "risk_id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
    "title": "Require recruiter sign-off before automated rejections",
    "description": "Route every rejection proposed by the assistant to a recruiter for approval.",
    "owner_user_id": 57,
    "due_date": "2026-10-15T00:00:00",
    "status": "todo",
    "priority": "p0",
    "notes": null,
    "completed_at": null,
    "created_at": "2026-09-01T10:12:44.081259",
    "updated_at": "2026-09-01T10:12:44.081259"
  }
}

Update an action

PATCH /agent-hub-api/api/compliance/actions/{action_id}

Updates fields of an action on one of your risks.

Changes only the fields you send. Setting status to done records completed_at (unless it is already set); setting any other status clears it.

Authentication
Bearer token How it works

Path parameters

  • action_id string Required

    ID of the action (UUID).

Body parameters application/json

  • status string

    Progress of the action. Case-insensitive.

    Possible values
    • todo
    • in_progress
    • done
    • blocked
  • priority string

    Urgency, p0 being the most urgent. Case-insensitive.

    Possible values
    • p0
    • p1
    • p2
  • title string

    What needs to be done. At most 300 characters.

  • description string

    Details of the action.

  • owner_user_id integer

    ID of the user responsible for the action, or null.

  • due_date string

    Deadline, as an ISO 8601 date or date-time. null or a value that cannot be parsed clears it.

  • notes string

    Free-text notes.

Returns

Returns the updated action in data.

Errors

  • 400 status or priority is empty or not one of the allowed values.
  • 404 You have no action with this ID.
Request
curl -X PATCH "$VDF_BASE_URL/agent-hub-api/api/compliance/actions/4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "done",
    "notes": "Sign-off step live in the screening workflow since 12 October."
  }'
Response 200
{
  "success": true,
  "data": {
    "id": "4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73",
    "risk_id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
    "title": "Require recruiter sign-off before automated rejections",
    "description": "Route every rejection proposed by the assistant to a recruiter for approval.",
    "owner_user_id": 57,
    "due_date": "2026-10-15T00:00:00",
    "status": "done",
    "priority": "p0",
    "notes": "Sign-off step live in the screening workflow since 12 October.",
    "completed_at": "2026-10-13T09:02:57.664810",
    "created_at": "2026-09-01T10:12:44.081259",
    "updated_at": "2026-10-13T09:02:57.665342"
  }
}