API Documentation
Read your AI system registry — systems, models, model versions, evaluation results, reviews and approvals, metrics, model and system cards, and AI risks — and feed it from your ML pipelines: propose systems, register model versions, record evaluation results and report metrics.
Overview
The Backsplice API gives programmatic access to your organization's AI system registry (AI systems, models, model versions, evaluation results, reviews and approvals, metrics, model and system cards, and the AI risk register), and to the governance program around it: assessments, findings, remediation, evidence metadata, vendors, incidents, policies, training, the audit log and the program score. All requests must be made over HTTPS.
| Base URL | https://backsplice.ai/api/v1/ |
| Availability | The REST API is included on Premium and Enterprise. It is not part of the 30-day demo, and a key from an organization that is not on a plan returns 403. |
| Format | JSON (Content-Type: application/json) |
| Authentication | Authorization: Bearer <api_key> |
| Rate limit | 100 requests per minute per API key. Exceeding the limit returns 429 Too Many Requests. |
Authentication
All API requests require a Bearer token. To create an API key, go to Settings → API Keys in your dashboard and click Generate new key. Store the key securely - it will only be shown once.
Include the key in every request using the Authorization header:
Authorization: Bearer bsk_••••••••••••••••••••••••••••••••••••••••••••••••
A key is bsk_ followed by 48 hexadecimal characters. Keys created before September 2026 begin ohk_ and keep working.
Scopes
Each API key is issued with one or more scopes that control which resources it can access.
| Scope | Access granted |
|---|---|
findings:read |
Read findings |
findings:write |
Create & update findings (write) |
assessments:read |
Read assessments |
assessments:write |
Create & update assessments (write) |
remediation:read |
Read remediation tasks |
remediation:write |
Create & update remediation tasks (write) |
evidence:read |
Read evidence metadata |
evidence:write |
Update evidence metadata (write) |
vendors:read |
Read vendors & agreements |
vendors:write |
Create & update vendors & agreements (write) |
incidents:read |
Read incidents |
incidents:write |
Create incidents (write) |
policies:read |
Read policies |
audit:read |
Read the audit log |
compliance:read |
Read the compliance score & posture |
risk_register:read |
Read the risk register |
risk_register:write |
Create risks in the risk register (write) |
ai_systems:read |
Read the AI system registry |
ai_systems:write |
Propose AI systems (write) |
models:read |
Read AI models, versions and evaluation results |
models:write |
Register model versions (write) |
evaluations:write |
Record model evaluation results (write) |
cards:read |
Read published model and system cards |
approvals:read |
Read AI system reviews and signed decisions |
monitoring:read |
Read AI system monitoring metrics |
monitoring:write |
Report AI system monitoring metrics (write) |
training:read |
Read the training roster & assignment report |
training:write |
Manage the training employee roster (write) |
webhooks:read |
List webhook endpoints |
webhooks:write |
Manage webhook endpoints (write) |
Endpoints
Returns a list of findings for your organization.
Required scope: findings:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: open, in_progress, resolved, accepted_risk, false_positive, or all_open for every finding still open (open and in_progress, the set the dashboard's Open Findings figure counts). open alone is the literal status. |
risk_level | string | Filter by risk: critical, high, medium, low, informational |
Returns a list of assessments for your organization.
Required scope: assessments:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: draft, in_progress, review, completed, archived. An unrecognized value returns 400. |
limit | integer | Page size, clamped to 1–100. Default 100. |
offset | integer | Rows to skip. Default 0. |
Returns a list of remediation tasks linked to your organization's findings.
Required scope: remediation:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: open, in_progress, completed, deferred |
priority | string | Filter by priority: critical, high, medium, low |
Read and update evidence metadata (filename, type, size, description, review/expiry dates, version). File contents are never served or writable via the API.
- GET — list evidence metadata (evidence:read).
- PATCH — update metadata by
id(evidence:write). Writable:description,review_date,expires_atonly.
Query parameters (GET)
| Parameter | Type | Description |
|---|---|---|
limit | int | Page size, 1–100 (default 100) |
offset | int | Row offset for pagination |
Read and manage vendors, including the AI each supplies (ai_involvement), whether it trains on your data (customer_data_training), agreement status (has_agreement, agreement_signed_at, agreement_expires_at) and review dates. Pass ?id= to GET a single vendor.
- GET — list or fetch vendors (vendors:read).
- POST — create a vendor (vendors:write). Body:
name(required), plus optionalcontact_name,contact_email,website,services_provided,data_access,risk_level,status,has_agreement,agreement_signed_at,agreement_expires_at,ai_involvement,customer_data_training,next_review_date,notes. Returns HTTP 201. - PATCH — update a vendor by
id(vendors:write).
Query parameters (GET)
| Parameter | Type | Description |
|---|---|---|
id | string | Return a single vendor by id |
status | string | Filter by status: active, under_review, terminated |
risk_level | string | Filter by risk: low, medium, high, critical |
ai_involvement | string | Filter by the AI the vendor supplies: none, embedded, ai_product, model_provider |
customer_data_training | string | Filter by whether the vendor trains on your data: unknown, no, opt_out, yes |
| An unrecognized filter value is refused with HTTP 400, naming the allowed values. | ||
The AI system registry. GET lists systems (filters stage, risk_tier, generative, q) or fetches one with ?id=, adding its intended use, oversight design and models (ai_systems:read). POST proposes a system (ai_systems:write): it is created in proposed, unclassified, and counts toward your system cap. The API never decides: a request carrying risk_tier, eu_ai_act_class, is_gpai, lifecycle_stage or next_review_date is refused. A person sets those on the system's page, and the lifecycle moves only through a review.
Filters take the listed values only; any other value is refused with HTTP 400, naming the allowed values.
AI models (models:read). ?id= returns one model with its recorded versions, the systems it backs and how many evaluation results exist.
Register a new version of a model from a CI or ML pipeline (models:write). Body: model_id, version (required), optional released_on, evaluation_summary, notes. It changes no system's approval; a system that pins a version keeps its pin.
Model evaluation results, one metric per result. GET ?model_id= (optional version_id) lists them newest first, paged with limit (at most 200) and offset (models:read). POST records one (evaluations:write, not granted by default): model_id, version_id, metric, value, optional threshold, passed, dataset, notes, measured_at. Results are append-only, and passed is recorded as sent, never worked out from the threshold.
Published model and system card versions (cards:read). Pass version_id, or system_id / model_id for that subject's latest published card with its content. Drafts are never returned.
AI system reviews and the decisions approvers signed (approvals:read). Filter by system_id or status; ?id= returns one review with its approvers and decisions. Read-only: a decision is signed in the dashboard with a password and a second factor, never through a key.
Filters take the listed values only; any other value is refused with HTTP 400, naming the allowed values.
The AI risk register. GET lists risks (filters status, category, treatment, ai_system_id) or fetches one with its treating controls (risk_register:read). POST creates a risk (risk_register:write, org admins only) under the same rules as the form: the trustworthy characteristic is required, a NIST AI 600-1 category needs a generative system or model, and the residual pair is both or neither. Unrated residual values are null, never zero.
Filters take the listed values only; any other value is refused with HTTP 400, naming the allowed values.
Manage the delivered-training employee roster — built for HR-system sync. Employees are keyed by email (unique per organization), so re-posting a person updates them and never duplicates. Course assignment and invite emails stay in the dashboard.
- GET — list the roster,
?id=for one employee,?active=1for active only (training:read). - POST — upsert by
email(training:write). Body:full_name(required),email(required), optionaldepartmentandai_roles, a list drawn frombuilder,reviewer(approvers) andexecutive(leadership); everyone takes AI literacy and each role adds its own course. Returns HTTP 201 when created, 200 when an existing email was updated. - PATCH — update by
id:full_name,department,is_active(training:write). Deactivation excludes the employee from bulk assignment while preserving history. - DELETE — remove by
?id=(training:write). Employees with completed training cannot be deleted (HTTP 409) — completions are compliance evidence; deactivate instead.
Read-only delivered-training report (training:read): every assignment with its effective status (expired once a pass is older than the 12-month validity window), score, attempts, duration, valid-through date, reminder count, invite-failure flag, and certificate id, plus an org-level stats block. Filters: course_key, status, employee_id; paginate with limit/offset. Assigning, resending, and revoking are dashboard-only actions (they send email).
The complete merged training transcript (training:read) — both delivered employee training and legacy manually-logged completions, the same dataset as the dashboard transcript export. One call gives an auditor or HR system the organization's full training record. Filters: q (person name/email), source (delivered|logged), status; paginate with limit (max 200) / offset. Every pull is recorded in the audit log.
Manage your organization's outbound webhook endpoints.
- GET — list endpoints (webhooks:read). Append
?catalog=1for the list of subscribable event names. Signing secrets are never returned on read. - POST — create an endpoint (webhooks:write). Body:
url,events(array), optionaldescription. The signingsecretis returned once in the response. - PATCH — update
url/events/description/is_activebyid(webhooks:write). - DELETE — remove an endpoint by
id(webhooks:write).
Webhook URLs are validated against an SSRF guard. Use the X-HTTP-Method-Override header if your client can't send PATCH/DELETE.
Returns AI incidents for your organization: type, severity, the AI system and model involved, whether personal data was involved, people affected (null when not yet known), and whether the incident is serious and when an authority was notified. Pass ?id= for a single incident. POST creates one (incidents:write) with title, discovery_date and optional incident_type, severity, ai_system_id, ai_model_id, description, personal_data_involved, people_affected, serious_incident. A new incident starts open; move it on in the dashboard once it has been triaged.
Required scope: incidents:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Return a single incident by id |
status | string | Filter: open, under_review, resolved, reported |
incident_type | string | Filter: harmful_output, inaccurate_output, biased_outcome, performance_degradation, misuse_or_attack, data_exposure, safety_harm, rights_impact, unapproved_use, outage, other |
severity | string | Filter: low, medium, high, critical |
ai_system_id | string | Filter to incidents involving one AI system |
personal_data_involved | boolean | Filter to incidents where personal data was involved |
serious_incident | boolean | Filter to incidents your organization marked serious |
Returns policies with status, version, owner, and review dates. Pass ?id= for a single policy.
Required scope: policies:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Return a single policy by id |
status | string | Filter: draft, active, under_review, retired |
policy_type | string | Filter by type (e.g. governance, acceptable_use, transparency) |
overdue_review | boolean | Only policies past their review date |
Returns your organization's tamper-evident audit log, newest first — the same event stream that drives webhooks and SIEM export. Ideal for pulling activity into your own SIEM/GRC tooling.
Required scope: audit:read
Query parameters
| Parameter | Type | Description |
|---|---|---|
event | string | Prefix match on the event name (e.g. incident matches incident.created, incident.closed) |
event_exact | string | Match one full event name exactly |
entity_type | string | Filter by entity type (e.g. finding, policy) |
from / to | string | Bound created_at (inclusive), YYYY-MM-DD or YYYY-MM-DD HH:MM[:SS]; a date alone as to includes that whole day. Anything else, including a relative date such as yesterday, returns 400. |
Returns your organization's current compliance score (0–100), letter grade, and the per-dimension breakdown (Findings, Policies & Docs, Training, Incident Response), plus the date of the last daily snapshot.
Required scope: compliance:read
Write operations
Each requires the matching *:write scope. Send a JSON body; use the X-HTTP-Method-Override header for PATCH if your client can't send it directly.
- PATCH
/api/v1/findings.php— update a finding byid. Editable:status(open,in_progress,resolved,accepted_risk,false_positive),risk_level,title,notes,description,category,recommendation,due_date. - POST
/api/v1/remediation.php— create a task. Body:title(required),description,status(notcompleted),priority,assigned_to(the email of an active member of your organization; invite anyone else from the dashboard),due_date(YYYY-MM-DD),finding_id. Returns HTTP 201 with the created task. - PATCH
/api/v1/remediation.php— update a task byid. Editable:title,description,status,priority,assigned_to,due_date. Completing a task that needs approval (or an AI approval condition) sends it to the approvers instead, answeringpending_approval: true; the other fields are still saved. - PATCH
/api/v1/assessments.php— update an assessment'sname,status, ordue_datebyid. Changing the status needs an organization admin's key, as in the dashboard:in_progress,review,completedorarchived(neverdraft). Completing does what Mark Complete does, raising the findings and recording the score. An archived assessment cannot be changed, and a completed one cannot be renamed. - POST / PATCH
/api/v1/vendors.php— create (201) or update a vendor byid(vendors:write). - PATCH
/api/v1/evidence.php— update evidence metadata (description,review_date,expires_at) byid(evidence:write). - POST / PATCH / DELETE
/api/v1/training-employees.php— upsert (by email), update, or remove training-roster employees (training:write); employees with completions can only be deactivated. POST acceptsauto_assign: trueto also assign every due built-in course and email the invites (HR-sync onboarding in one call).
Response format
List (GET) responses return HTTP 200 with a data array, the count in this page, and the limit / offset used. Findings and remediation also include a total (the full match count); assessments omit total. A successful create (POST /api/v1/remediation.php) returns HTTP 201 with the created record.
{
"data": [
{ "id": "abc123", "title": "...", "status": "open", ... }
],
"count": 1,
"total": 1,
"limit": 100,
"offset": 0
}
Paginate with ?limit= (1–100, default 100) and ?offset=.
Error responses
Errors return a non-2xx HTTP status with a JSON body carrying a single
error key:
{
"error": "Invalid or expired API key."
}
| HTTP status | Meaning |
|---|---|
400 | Malformed request — an unrecognized filter value, or invalid JSON in the body |
401 | Missing or invalid API key |
403 | Valid key, but insufficient scope, insufficient role, a disabled org module, or no accepted Data Processing Agreement |
404 | No such record, or it belongs to another organization |
405 | Method not supported on this endpoint |
409 | Conflicts with the current state of the record |
415 | Request body was not application/json |
422 | Well-formed request that fails a validation rule |
429 | Rate limit exceeded. See the Retry-After and X-RateLimit-* headers |
500 | Internal server error |
Rate limit headers
Every response carries the current window state, so a client can back off before it is throttled rather than after:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests permitted in the current window |
X-RateLimit-Remaining | Requests left in it |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait. Sent with a 429. |
Example
Fetch all open critical findings using curl:
curl -s \
-H "Authorization: Bearer bsk_••••••••••••••••••••••••••••••••••••••••••••••••" \
-H "Accept: application/json" \
"https://backsplice.ai/api/v1/findings.php?status=open&risk_level=critical"
Example response:
{
"data": [
{
"id": "fnd_01j9kx4",
"title": "No documented human oversight for an automated decision system",
"risk_level": "critical",
"status": "open",
"created_at": "2026-01-15T09:32:00Z"
}
],
"count": 1
}