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.
- GET /api/compliance/systems List AI systems
- POST /api/compliance/systems Create an AI system
- GET /api/compliance/systems/{system_id} Retrieve an AI system
- PATCH /api/compliance/systems/{system_id} Update an AI system
- DEL /api/compliance/systems/{system_id} Delete an AI system
- GET /api/compliance/integrations/discover Discover integrations
- POST /api/compliance/systems/import Import integrations
- GET /api/compliance/repos List repository registrations
- POST /api/compliance/repos/{repo_reg_id}/scan Prepare a repository scan
- GET /api/compliance/risks List risks
- POST /api/compliance/risks Create a risk
- PATCH /api/compliance/risks/{risk_id} Update a risk
- GET /api/compliance/actions List actions
- POST /api/compliance/actions Create an action
- PATCH /api/compliance/actions/{action_id} Update an action
Paths are relative to /agent-hub-api
The AI system object
An entry in your AI system register, returned in data.
Attributes
-
idstringUnique identifier for the AI system (UUID).
-
owner_user_idintegerID of the user who owns this entry.
-
namestringName of the AI system.
-
ownernullable stringPerson or team accountable for the system. Free text.
-
use_casenullable stringWhat the system is used for.
-
data_processednullable stringThe data the system processes.
-
user_countnullable integerNumber of people who use the system.
-
sourcestringHow the system entered your organisation:
internal(built in-house),vendor(bought from a supplier),shadow(in use without formal approval) orintegration(imported from a connected integration). -
vendornullable stringSupplier of the system, for bought-in systems.
-
risk_tierstringRisk tier under the EU AI Act:
unacceptable,high,limited,minimal, orunclassifieduntil the system has been assessed. -
annex_iii_categorynullable stringThe Annex III high-risk area the system falls under, such as
4(a)for recruitment and selection. -
classification_rationalenullable stringWhy the system was given its risk tier.
-
classified_atnullable stringWhen the system was classified.
-
has_documentationbooleanWhether technical documentation exists for the system.
-
has_oversightbooleanWhether human oversight measures are in place.
-
integration_sourcenullable stringThe integration the entry was imported from, such as
github,jira,confluenceordata_connection. -
integration_refobjectIdentifiers of the source record in that integration, for example a repository's
full_name. An empty object when there is none. -
created_atstringWhen the entry was created.
-
updated_atstringWhen the entry was last changed.
{
"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.
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/systems" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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
-
namestring RequiredName of the AI system. At most 200 characters.
-
sourcestringHow the system entered your organisation. Case-insensitive.
Possible values-
internal -
vendor -
shadow -
integration
-
-
risk_tierstringRisk tier under the EU AI Act. Case-insensitive.
Possible values-
unacceptable -
high -
limited -
minimal -
unclassified
-
-
ownerstringPerson or team accountable for the system. At most 200 characters.
-
use_casestringWhat the system is used for.
-
data_processedstringThe data the system processes.
-
user_countintegerNumber of people who use the system.
-
vendorstringSupplier of the system. At most 200 characters.
-
annex_iii_categorystringThe Annex III high-risk area, such as
4(a). At most 200 characters. -
classification_rationalestringWhy the system has its risk tier.
-
classified_atstringWhen the system was classified, as an ISO 8601 date or date-time. A value that cannot be parsed is stored as
null. -
has_documentationbooleanWhether technical documentation exists for the system.
-
has_oversightbooleanWhether human oversight measures are in place.
-
integration_sourcestringThe integration the entry comes from, such as
github. At most 30 characters. -
integration_refobjectIdentifiers of the source record in that integration.
Returns
Returns the new AI system object in data.
Errors
- 400
nameis missing or empty, orsourceorrisk_tieris not one of the allowed values.
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
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
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,
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"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,
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID of the AI system (UUID).
Returns
Returns the AI system object in data.
Errors
- 404 You have no AI system with this ID.
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID of the AI system (UUID).
Body parameters application/json
-
namestringName of the AI system. At most 200 characters.
-
sourcestringHow the system entered your organisation. Case-insensitive.
Possible values-
internal -
vendor -
shadow -
integration
-
-
risk_tierstringRisk tier under the EU AI Act. Case-insensitive.
Possible values-
unacceptable -
high -
limited -
minimal -
unclassified
-
-
ownerstringPerson or team accountable for the system. At most 200 characters.
-
use_casestringWhat the system is used for.
-
data_processedstringThe data the system processes.
-
user_countintegerNumber of people who use the system.
-
vendorstringSupplier of the system. At most 200 characters.
-
annex_iii_categorystringThe Annex III high-risk area, such as
4(a). At most 200 characters. -
classification_rationalestringWhy the system has its risk tier.
-
classified_atstringWhen the system was classified, as an ISO 8601 date or date-time.
nullor a value that cannot be parsed clears it. -
has_documentationbooleanWhether technical documentation exists for the system.
-
has_oversightbooleanWhether human oversight measures are in place.
-
integration_sourcestringThe integration the entry comes from. At most 30 characters.
-
integration_refobjectIdentifiers of the source record in that integration.
nullresets it to an empty object.
Returns
Returns the updated AI system object in data.
Errors
- 400
sourceorrisk_tieris not one of the allowed values. - 404 You have no AI system with this ID.
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"
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
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',
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.patch(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"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",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID 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.
curl -X DELETE "$VDF_BASE_URL/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.delete(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems/0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_reposbooleanSet to
falseto skip fetching repositories from GitHub.github.connectedis still reported.
Returns
Returns data with one entry per source: github (connected and repos), jira and confluence (connected and workspaces), and data_connections.
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/integrations/discover" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/integrations/discover`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/integrations/discover",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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
internalsystem 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
integrationsystem. 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_reposarray of objectsGitHub repositories to import.
Show child parameters Hide child parameters
-
full_namestringRepository in
owner/nameform. Items without it are skipped. At most 300 characters. -
idstringGitHub's ID for the repository.
-
namestringName for the AI system. Defaults to
full_name. -
ownerstringOwner recorded on the AI system. Defaults to the part of
full_namebefore the slash. -
default_branchstringBranch to scan.
-
languagestringMain language of the repository, mentioned in the system's
use_case. -
html_urlstringWeb address of the repository, kept in
integration_ref.
-
-
data_connectionsarray of objectsData connections to import.
Show child parameters Hide child parameters
-
idstringID of the data connection. Items without it are skipped.
-
namestringName for the AI system.
-
ownerstringOwner recorded on the AI system.
-
typestringConnection type, mentioned in the system's
use_case. -
descriptionstringStored as the system's
data_processed. -
hoststringHost of the connection, kept in
integration_ref. -
database_namestringDatabase of the connection, kept in
integration_ref.
-
-
jira_workspacesarray of objectsJira workspaces to import.
Show child parameters Hide child parameters
-
cloud_idstringJira site ID. Items without it are skipped.
-
labelstringName for the AI system.
-
usernamestringAccount the workspace is connected with, recorded as the system's owner.
-
-
confluence_workspacesarray of objectsConfluence workspaces to import.
Show child parameters Hide child parameters
-
cloud_idstringConfluence site ID. Items without it are skipped.
-
labelstringName for the AI system.
-
usernamestringAccount 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.
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"
}
]
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/systems/import`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
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',
},
],
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/systems/import",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"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",
},
],
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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.
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/repos" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/repos`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/repos",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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:
- Call this endpoint without a body. It returns
202with theagent_name,promptandcontextfor the scan. - 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: ariskslist whose entries carrytitle,description,eu_ai_act_article,severity,evidenceand suggestedactions, each with atitleandpriority. The report is model-generated, so validate it before you use it. - Call this endpoint again with
run_idset to the run'sexecution_id. It records the run on the registration and returns200. - Record the findings with Create a risk and Create an action. Send
sourcegithub_scanand a stablededup_keyper 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
-
repo_reg_idstring RequiredID of the repository registration (UUID), from List repository registrations.
Body parameters application/json
-
run_idstringID of the scan run you started. When present, it is stored as the registration's
last_scan_run_id,last_scan_atis 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.
curl -X POST "$VDF_BASE_URL/agent-hub-api/api/compliance/repos/2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65/scan" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/repos/2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65/scan`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/repos/2a7e5c91-8f3d-4b6a-9e20-1c4d7b8f3a65/scan",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstringOnly return risks linked to this AI system.
-
severityarray of stringsOnly return risks with this severity:
unacceptable,high,limited,minimalorinfo. Repeatable. -
statusarray of stringsOnly return risks with this status:
open,in_progress,mitigated,acceptedorwithdrawn. Repeatable. -
eu_ai_act_articlestringOnly return risks mapped to this article, matched exactly, such as
Art. 14.
Returns
Returns a list of risks in data.
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" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/risks?ai_system_id=0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90&status=open`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/risks",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
params={
"ai_system_id": "0f8b6a52-7c1e-4d3a-9b8f-2e5d7c4a1b90",
"status": "open",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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
-
titlestring RequiredShort statement of the risk. At most 300 characters.
-
severitystringHow serious the risk is, using the EU AI Act tiers plus
infofor observations. Case-insensitive.Possible values-
unacceptable -
high -
limited -
minimal -
info
-
-
statusstringWhere the risk stands. Case-insensitive.
Possible values-
open -
in_progress -
mitigated -
accepted -
withdrawn
-
-
ai_system_idstringID of the AI system the risk relates to (UUID).
-
descriptionstringDetails of the finding.
-
eu_ai_act_articlestringArticle of the Act the risk relates to, such as
Art. 9,Art. 14orAnnex IV. At most 60 characters. -
sourcestringWhere the finding came from. The product uses
manual,classification,github_scanandgap_report. Stored in lower case; at most 30 characters. -
source_refstringReference to the origin of the finding, such as the ID of the scan run. At most 200 characters.
-
dedup_keystringYour own stable key for the finding, such as
github_scan:<registration_id>:<finding>. At most 200 characters. -
evidenceobjectSupporting evidence, such as the tool and file that revealed the finding.
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
titleis missing or empty, orseverityorstatusis not one of the allowed values.
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"
}
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/risks`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
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',
},
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/risks",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"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",
},
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID of the risk (UUID).
Body parameters application/json
-
statusstringWhere the risk stands. Case-insensitive.
Possible values-
open -
in_progress -
mitigated -
accepted -
withdrawn
-
-
severitystringHow serious the risk is. Case-insensitive.
Possible values-
unacceptable -
high -
limited -
minimal -
info
-
-
titlestringShort statement of the risk. At most 300 characters.
-
descriptionstringDetails of the finding.
-
eu_ai_act_articlestringArticle of the Act the risk relates to. At most 60 characters.
-
ai_system_idstringID of the AI system the risk relates to (UUID), or
null. -
evidenceobjectSupporting evidence. Replaces the stored object;
nullresets it to an empty object. -
sourcestringWhere the finding came from. At most 30 characters.
-
source_refstringReference to the origin of the finding. At most 200 characters.
Returns
Returns the updated risk in data.
Errors
- 400
severityorstatusis empty or not one of the allowed values. - 404 You have no risk with this ID.
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"
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/risks/b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
status: 'in_progress',
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.patch(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/risks/b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"status": "in_progress",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstringOnly return actions for this risk.
-
statusarray of stringsOnly return actions with this status:
todo,in_progress,doneorblocked. Repeatable.
Returns
Returns a list of actions in data.
curl "$VDF_BASE_URL/agent-hub-api/api/compliance/actions?risk_id=b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14" \
-H "Authorization: Bearer $VDF_ACCESS_TOKEN" const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/actions?risk_id=b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14`, {
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
},
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.get(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/actions",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
params={
"risk_id": "b5d9e2c7-1a4f-4c3b-8e6d-9f2a0c7b5e14",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID of the risk the action addresses (UUID).
-
titlestring RequiredWhat needs to be done. At most 300 characters.
-
prioritystringUrgency,
p0being the most urgent. Case-insensitive.Possible values-
p0 -
p1 -
p2
-
-
statusstringProgress of the action. Case-insensitive.
Possible values-
todo -
in_progress -
done -
blocked
-
-
descriptionstringDetails of the action.
-
owner_user_idintegerID of the user responsible for the action. Defaults to you.
-
due_datestringDeadline, as an ISO 8601 date or date-time. A value that cannot be parsed is stored as
null. -
notesstringFree-text notes.
Returns
Returns the new action in data.
Errors
- 400
risk_idortitleis missing, orstatusorpriorityis not one of the allowed values. - 404 You have no risk with the given
risk_id.
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"
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/actions`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
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',
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.post(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/actions",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"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",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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_idstring RequiredID of the action (UUID).
Body parameters application/json
-
statusstringProgress of the action. Case-insensitive.
Possible values-
todo -
in_progress -
done -
blocked
-
-
prioritystringUrgency,
p0being the most urgent. Case-insensitive.Possible values-
p0 -
p1 -
p2
-
-
titlestringWhat needs to be done. At most 300 characters.
-
descriptionstringDetails of the action.
-
owner_user_idintegerID of the user responsible for the action, or
null. -
due_datestringDeadline, as an ISO 8601 date or date-time.
nullor a value that cannot be parsed clears it. -
notesstringFree-text notes.
Returns
Returns the updated action in data.
Errors
- 400
statusorpriorityis empty or not one of the allowed values. - 404 You have no action with this ID.
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."
}' const response = await fetch(`${process.env.VDF_BASE_URL}/agent-hub-api/api/compliance/actions/4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.VDF_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
status: 'done',
notes: 'Sign-off step live in the screening workflow since 12 October.',
}),
});
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json(); import os
import requests
response = requests.patch(
f"{os.environ['VDF_BASE_URL']}/agent-hub-api/api/compliance/actions/4f7c1e9a-6b2d-4a8e-93c5-0d8e2f6b1c73",
headers={"Authorization": f"Bearer {os.environ['VDF_ACCESS_TOKEN']}"},
json={
"status": "done",
"notes": "Sign-off step live in the screening workflow since 12 October.",
},
timeout=30,
)
response.raise_for_status()
data = response.json() {
"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"
}
}