Introduction
The VerityLayer API is organized around REST. It uses resource-oriented URLs, accepts and returns JSON, and relies on standard HTTP verbs and response codes. Every request is scoped to a single organization and executed as a specific user, so responses only ever include data that user is permitted to see.
- All requests must be made over HTTPS.
- Request and response bodies are JSON (
Content-Type: application/json). - Most resources follow a uniform pattern — list, read, create, update, delete — described under Resources.
Base URL
All endpoints are relative to the versioned base URL:
https://veritylayer.com/api/v1Endpoint paths are appended directly, e.g. https://veritylayer.com/api/v1/risks.
Authentication
The API authenticates with an API key sent as a bearer token, plus a tenant header identifying your organization. Both headers are required on every request.
Required headers
| Header | Value | Description |
|---|---|---|
Authorization | Bearer vl_ai_… | Your secret API key. |
X-VerityLayer-Tenant | your-org-slug | Your organization slug. Must match the key's organization. |
Getting a key
An organization administrator generates API keys inside the application under Settings → API Keys. Each key is tied to the organization and to the user who created it — API calls inherit exactly that user's module access and permissions.
Keep keys secret. A key is shown only once at creation. Treat it like a password: never embed it in client-side code or commit it to source control. If a key is exposed, revoke it in Settings and issue a new one.
Example
curl https://veritylayer.com/api/v1/risks \
-H "Authorization: Bearer vl_ai_your_api_key_here" \
-H "X-VerityLayer-Tenant: your-org-slug"Making requests
The API maps HTTP verbs to actions on a resource:
| Verb | Path | Action |
|---|---|---|
| GET | /{resource} | List records (paginated) |
| GET | /{resource}/{id} | Retrieve a single record |
| POST | /{resource} | Create a record |
| PUT | /{resource}/{id} | Update a record (PATCH also accepted) |
| DELETE | /{resource}/{id} | Delete a record |
Send JSON bodies for POST, PUT and PATCH. Whether a given verb is available on a resource depends on your permissions; a verb you cannot use returns 403 or 404.
Pagination & filtering
List endpoints are paginated. Control the page and size with query parameters:
| Parameter | Default | Notes |
|---|---|---|
page | 1 | 1-based page number. |
per_page | 25 | Records per page. Maximum 100. |
Some resources also accept filter parameters that match a field to an allowed value — for example /risks?risk_category=Operational&treatment_status=In%20Progress. Unsupported or invalid filter values are ignored.
curl "https://veritylayer.com/api/v1/vulnerabilities?page=2&per_page=50" \
-H "Authorization: Bearer vl_ai_your_api_key_here" \
-H "X-VerityLayer-Tenant: your-org-slug"Response format
Every response is a JSON object with a success boolean. The shape depends on the operation.
List
{
"success": true,
"page": 1,
"per_page": 25,
"count": 2,
"data": [
{ "id": 41, "title": "Unpatched web server", "risk_category": "Technical", "treatment_status": "In Progress" },
{ "id": 42, "title": "Weak vendor access controls", "risk_category": "Operational", "treatment_status": "Not Started" }
]
}Single record
{
"success": true,
"data": { "id": 41, "title": "Unpatched web server", "risk_category": "Technical" }
}Create / update
Create returns 201 Created with the new record's primary key; update returns 200 with the key.
{ "success": true, "id": 43 }Errors
Errors use standard HTTP status codes and return { "success": false, "error": "…" }.
| Status | Meaning | Example message |
|---|---|---|
400 | Bad request — validation failed | Field 'title' is required |
401 | Missing or invalid API key | Invalid or revoked API key |
403 | Not permitted / tenant mismatch | The acting user does not have the "risk_register_create" permission |
404 | Unknown resource or record | Not found |
405 | Verb not supported for resource | This resource does not support delete |
500 | Server error | Internal server error |
A 403 tells you exactly which permission or entitlement is missing. If a whole module is disabled for your organization you'll see "This module is not enabled for your organization" — enable it in the app, or ask an administrator.
Resources
These resources all follow the uniform pattern in Making requests. The available verbs on each are gated by your permissions.
| Resource | Description | Operations |
|---|---|---|
/risks |
Risk register entries | GET, POST, PUT, DELETE |
/vulnerabilities |
Tracked vulnerabilities | GET, POST, PUT, DELETE |
/assessments |
Project / security assessments | GET, POST, PUT, DELETE |
/assets |
Asset inventory | GET, POST, PUT, DELETE |
/incidents |
Security incidents | GET, POST, PUT, DELETE |
/changes |
Change-management records | GET, POST, PUT, DELETE |
/patches |
Patch-management records | GET, POST, PUT, DELETE |
/vendors |
Third-party vendors | GET, POST, PUT, DELETE |
/forms |
Custom forms | GET, POST, PUT, DELETE |
/evidence |
Compliance evidence items | GET, POST, PUT, DELETE |
Worked example — create a risk
POST /risks requires title, risk_category, likelihood and impact. Enum fields must use an allowed value (e.g. likelihood/impact are one of Very Low, Low, Medium, High, Very High).
curl -X POST https://veritylayer.com/api/v1/risks \
-H "Authorization: Bearer vl_ai_your_api_key_here" \
-H "X-VerityLayer-Tenant: your-org-slug" \
-H "Content-Type: application/json" \
-d '{
"title": "Unpatched web server",
"risk_category": "Technical",
"likelihood": "High",
"impact": "High",
"treatment_status": "Not Started"
}'Compliance & policies
A few areas expose purpose-built endpoints in addition to the generic resources above.
| Verb | Path | Description |
|---|---|---|
| GET | /compliance/frameworks | List compliance frameworks |
| GET | /compliance/frameworks/{code} | List a framework's controls |
| PUT | /compliance/frameworks/{code}/controls/{id} | Update a control's status |
| POST | /evidence/map | Map an evidence item to a control |
| GET | /policies | List policy documents |
| GET | /policies/{id} | Read a policy document |
| POST | /policies | Create a policy document |
| PUT | /policies/{id} | Update a policy document |
| DELETE | /policies/{id} | Delete a policy document |
| POST | /audit/export | Generate a compliance audit export |
Code samples
The same authenticated GET /risks request in several languages.
PHP
$ch = curl_init('https://veritylayer.com/api/v1/risks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer vl_ai_your_api_key_here',
'X-VerityLayer-Tenant: your-org-slug',
],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response['data']);JavaScript (fetch)
const res = await fetch('https://veritylayer.com/api/v1/risks', {
headers: {
'Authorization': 'Bearer vl_ai_your_api_key_here',
'X-VerityLayer-Tenant': 'your-org-slug',
},
});
const body = await res.json();
console.log(body.data);Python (requests)
import requests
res = requests.get(
'https://veritylayer.com/api/v1/risks',
headers={
'Authorization': 'Bearer vl_ai_your_api_key_here',
'X-VerityLayer-Tenant': 'your-org-slug',
},
)
print(res.json()['data'])Support
Need help integrating? Reach out through the contact page or the in-app support center. Include the endpoint, the HTTP status you received and the error message — but never share your API key.