Introduction
Welcome to the Devici API
Quick Start
Download the Postman collection and environment to get started quickly:
Import both files into Postman, set your tokenId and tokenSecret in the environment, and run the Auth > Authenticate request to obtain a token. All subsequent requests use the token automatically.
Access to our endpoints is managed via scoped API tokens.
Scopes are the mechanism used to define and control the specific resources and actions an API token can utilize. When creating a token, you assign scopes (e.g., collections:read, users:write) to enforce the principle of least privilege.
Every endpoint requires a specific, corresponding scope. Any request made without the necessary scope will be immediately denied, ensuring robust access control across your collections, threat models, and other critical resources.
API Token Prerequisites and Management
To create or manage API tokens, you must meet the following criteria:
- Subscription Tier: An Enterprise tier subscription is required.
- Role Requirements: Token creation and management are restricted to users with the Superadmin or Owner role.
The generated token must be assigned to an active user who possesses the appropriate permissions relevant to the required API actions.
Token Expiration and Renewal
The API token is short-lived and expires after the time specified in the expires_in field (typically 1 hour).
Upon expiration, you must obtain a new API token by re-initiating the authentication flow via the /auth endpoint.
Security Constraints
- Permissions: The permissions granted by the API token are strictly based on the scopes assigned to the underlying API token.
- IP Whitelisting: If your API token has IP whitelist restrictions configured, all API requests must originate exclusively from the defined, allowed IP addresses.
API Token Scopes
API tokens use a scope-based permission system to control access to resources. Each scope consists of a resource and a permission level.
Permissions
| Permission | Description |
|---|---|
read |
Read access - view and retrieve data |
write |
Write access - create, update, and delete data |
Resources
Scopes can be assigned to various resources in the system. Common resources include:
users- Users managementusers-operations- Users Operationsteams- Teams managementroles- Roles informationcollections- Collectionscollection-access- Collections Accessthreat-models- Threat modelstags- Tags (organization-level)threats- Threatscomponents- Componentscanvases- Canvasesattributes- Attributesmitigations- Mitigationscomments- Commentsaudit-logs- Audit logsdashboard- Dashboard datareports- Reports*- All resources (wildcard for full access)
Scope Validation
When making API requests:
- Each endpoint requires specific scopes to be present on your API token
- If your token lacks the required scope, you will receive a
403 Forbiddenerror with a message indicating the required scope - Scopes are validated on every request to ensure your token has the necessary permissions
Authentication
To authorize, use this code:
import axios from "axios";
axios.defaults.baseURL = "https://api.devici.com/api/v1/";
const response = await axios.post("/auth", {
clientId: "{{TOKEN_ID}}",
secret: "{{TOKEN_SECRET}}",
});
The above command returns JSON structured like this:
{
"access_token": "{{access_token}}",
"expires_in": 3600,
"token_type": "Bearer"
}
const { token_type, access_token } = response.data;
axios.defaults.headers.common = {
Authorization: `${token_type} ${access_token}`,
};
Devici uses API Tokens to allow access to the API. You can register a new Devici API token at our app.
TOKEN_ID = YOUR_TOKEN_ID
TOKEN_SECRET = YOUR_TOKEN_SECRET
Get token
POST https://api.devici.com/api/v1/auth
For the following requests, use this header:
Authorization: {{token_type}} {{access_token}}
Roles
Get Roles
To get All Roles use this code:
axios.get("/roles");
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
{
"version": "2025-09-11-1",
"updatedAt": "2025-09-11T00:00:00Z",
"roles": [
{
"key": "user",
"description": "Access to the content only; limited by permissions.",
"name": "User"
},
{
"key": "admin",
"description": "Access to the content only; limited by scopes.",
"name": "Admin"
},
{
"key": "super_admin",
"description": "Full access except payments and branding.",
"name": "Super-admin"
},
{
"key": "owner",
"description": "Account owner; full control.",
"name": "Owner"
}
]
}
This endpoint retrieves the complete list of available roles and a version identifier. Use this endpoint to fetch the initial catalog or to get an updated version when your local cache is stale. See the Caching & Change Detection section for details on revalidation.
owner - The account creator. An account can have only one owner. The owner has unrestricted access to all resources and functionality without limitations.
super-admin have full access to all resources without requiring specific scopes or permissions.
admin require granular scope assignments.
HTTP Request
GET https://api.devici.com/api/v1/roles
Check for Role List Changes
To Check for Role List Changes use this code:
axios.head("/roles");
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
(No response body)
This endpoint with method HEAD returns only the response headers (without a body). This is useful for checking if the resource has been updated by examining key headers, such as ETag or Last-Modified, allowing for efficient caching and avoiding the transfer of unnecessary data.
HTTP Request
HEAD https://api.devici.com/api/v1/roles
Caching & Change Detection
Example Request
axios.get("/roles", {
headers: {
"If-None-Match": "{{ETag}}",
"If-Modified-Since": Thu, 11 Sep 2025 00:00:00 GMT,
},
});
HTTP/1.1 304 Not Modified
(No response body)
To improve performance, clients are strongly encouraged to cache the roles response. The server provides ETag and Last-Modified headers to facilitate this.
Revalidating with Headers
When you make a subsequent GET request, include the appropriate headers to ask the server if the resource has changed.
If-None-Match (Preferred): This is the primary method for revalidation. Use the ETag value from your cached response.
If-Modified-Since (Fallback): Use the Last-Modified date from your cached response. Note: The value must be a valid HTTP-date string, not the version string.
If your cached version is still current, the server will respond with 304 Not Modified and an empty body. This signals that you should continue to use your cached copy. If the data has changed, you will receive a standard 200 OK response with the new data.
HTTP Request
HEAD https://api.devici.com/api/v1/roles
Headers
| Key | Value | Description |
|---|---|---|
| If-None-Match | {{ETag}} | This is the method for revalidation. |
| If-Modified-Since | Thu, 11 Sep 2025 00:00:00 GMT | Fallback Method. |
Users
Get Users
To get All Users use this code:
axios.get("/users/?limit=20&page=0");
{
"items": [
{
"id": "{{user_id}}",
"role": "owner",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"status": "confirmed",
"is_enabled": true
},
{
"id": "{{user_id}}",
"role": "user",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"status": "confirmed",
"is_enabled": true
},
{
"id": "{{user_id}}",
"role": "super_admin",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"status": "confirmed",
"is_enabled": true
},
{
"id": "{{user_id}}",
"role": "admin",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"status": "confirmed",
"is_enabled": true,
"scopes": [
{ "resource": "users", "permission": "read" },
{ "resource": "users", "permission": "write" },
]
},
],
"count": 4
}
This endpoint retrieves Users.
HTTP Request
GET https://api.devici.com/api/v1/users/?limit=20&page=0
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
Get a Specific User
To get specific user use this code:
axios.get("/users/:id");
The above command returns JSON structured like this:
{
"id": "{{user_id}}",
"role": "user",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"avatar_uploaded_at": "2025-03-11T09:29:23.072Z",
"avatarUrl": "{{img_url}}"
}
When receiving a user with the
adminrole:
{
"id": "{{user_id}}",
"role": "admin",
"first_name": "First",
"last_name": "Last",
"email": "{{user_email}}",
"status": "confirmed",
"is_enabled": true,
"scopes": [
{ "resource": "users", "permission": "read" },
{ "resource": "users", "permission": "write" },
]
},
This endpoint retrieves a specific user.
HTTP Request
GET https://api.devici.com/api/v1/users/:id
Search Users
To search users use this code:
axios.get("/users/search/?field=email&text=johndoe@mail.com");
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"created_at": "2025-02-10T14:26:04.248Z",
"updated_at": "2025-03-11T09:29:23.081Z",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"is_active": true,
"role": "user"
},
{
"id": "{{user_id}}",
"created_at": "2025-02-10T14:26:04.248Z",
"updated_at": "2025-03-11T09:29:23.081Z",
"email": "johndoe+2@mail.com",
"first_name": "First",
"last_name": "Last",
"role": "admin",
"is_enabled": true,
"scopes": [
{ "resource": "users", "permission": "read" },
{ "resource": "users", "permission": "write" },
]
}
]
This endpoint retrieves a users.
HTTP Request
GET https://api.devici.com/api/v1/users/search/?field=email&text=johndoe@mail.com
Query Parameters
| Parameter | Description |
|---|---|
| field | must be on of first_name, last_name, email |
| text | must be string |
Admin Scopes
Catalog of scope resources, permissions, and presets for assigning admin scopes to users. Requires Enterprise tier and Public API authentication (client credentials).
Get Resources Catalog
To get the list of scope resources use this code:
axios.get("/users/admin-scopes/resources", {
headers: {
"Authorization": "Bearer {{ACCESS_TOKEN}}"
}
});
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
{
"version": "2026-01-15-1",
"updatedAt": "2026-01-15T00:00:00Z",
"resources": [
{
"key": "users",
"description": "Users management",
"name": "Users",
"readOnly": false,
"writeOnly": false
},
{
"key": "users-operations",
"description": "User operations (invite, enable/disable, change role)",
"name": "Users-operations",
"readOnly": false,
"writeOnly": false
},
{
"key": "teams",
"description": "Teams management",
"name": "Teams",
"readOnly": false,
"writeOnly": false
},
{
"key": "roles",
"description": "Roles information",
"name": "Roles",
"readOnly": true,
"writeOnly": false
},
{
"key": "codex",
"description": "Codex resources (threats, attributes, mitigations)",
"name": "Codex",
"readOnly": false,
"writeOnly": false
},
{
"key": "dashboard",
"description": "Dashboard data and chart types",
"name": "Dashboard",
"readOnly": true,
"writeOnly": false
},
{
"key": "reports",
"description": "Reports",
"name": "Reports",
"readOnly": true,
"writeOnly": false
},
{
"key": "report-export",
"description": "Export reports (PDF, CSV)",
"name": "Report-export",
"readOnly": true,
"writeOnly": false
},
{
"key": "audit-logs",
"description": "Audit logs",
"name": "Audit-logs",
"readOnly": true,
"writeOnly": false
},
{
"key": "audit-log-export",
"description": "Export audit logs (CSV)",
"name": "Audit-log-export",
"readOnly": true,
"writeOnly": false
},
{
"key": "categories",
"description": "Categories management",
"name": "Categories",
"readOnly": false,
"writeOnly": false
},
{
"key": "app-integrations",
"description": "App integrations (Jira, Azure DevOps, etc.)",
"name": "App-integrations",
"readOnly": true,
"writeOnly": false
},
{
"key": "workflows",
"description": "Workflows management",
"name": "Workflows",
"readOnly": false,
"writeOnly": false
},
{
"key": "api-tokens",
"description": "API tokens management (view and manage personal tokens)",
"name": "Api-tokens",
"readOnly": false,
"writeOnly": false
}
]
}
Returns the list of scope resources that can be assigned to admin users, including their readOnly and writeOnly flags. Use this endpoint to fetch the initial catalog or to get an updated version when your local cache is stale. See the Caching & Change Detection section below for details on revalidation.
HTTP Request
GET https://api.devici.com/api/v1/users/admin-scopes/resources
Get Permissions Catalog
To get the list of permissions use this code:
axios.get("/users/admin-scopes/permissions", {
headers: {
"Authorization": "Bearer {{ACCESS_TOKEN}}"
}
});
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
{
"version": "2025-02-11-1",
"updatedAt": "2025-02-11T00:00:00Z",
"permissions": [
{
"key": "read",
"description": "Read access - view and retrieve data",
"name": "Read"
},
{
"key": "write",
"description": "Write access - create, update, and delete data",
"name": "Write"
}
]
}
Returns the list of permissions (e.g. read, write) used in scope assignment. Use this endpoint to fetch the initial catalog or to get an updated version when your local cache is stale. See the Caching & Change Detection section below for details on revalidation.
HTTP Request
GET https://api.devici.com/api/v1/users/admin-scopes/permissions
Get Presets Catalog
To get the list of scope presets use this code:
axios.get("/users/admin-scopes/presets", {
headers: {
"Authorization": "Bearer {{ACCESS_TOKEN}}"
}
});
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
{
"version": "2026-01-15-1",
"updatedAt": "2026-01-15T00:00:00Z",
"presets": [
{
"key": "full-access",
"description": "Full access to all admin resources.",
"name": "Full-access",
"scopes": [
{ "resource": "users", "permission": "read" },
{ "resource": "users", "permission": "write" },
{ "resource": "users-operations", "permission": "read" },
{ "resource": "users-operations", "permission": "write" },
{ "resource": "teams", "permission": "read" },
{ "resource": "teams", "permission": "write" },
{ "resource": "roles", "permission": "read" },
{ "resource": "codex", "permission": "read" },
{ "resource": "codex", "permission": "write" },
{ "resource": "dashboard", "permission": "read" },
{ "resource": "reports", "permission": "read" },
{ "resource": "report-export", "permission": "read" },
{ "resource": "audit-logs", "permission": "read" },
{ "resource": "audit-log-export", "permission": "read" },
{ "resource": "categories", "permission": "read" },
{ "resource": "categories", "permission": "write" },
{ "resource": "app-integrations", "permission": "read" },
{ "resource": "workflows", "permission": "read" },
{ "resource": "workflows", "permission": "write" },
{ "resource": "api-tokens", "permission": "read" },
{ "resource": "api-tokens", "permission": "write" }
]
},
{
"key": "users-management",
"description": "Manage users, and teams.",
"name": "Users-management",
"scopes": [
{ "resource": "users", "permission": "read" },
{ "resource": "users", "permission": "write" },
{ "resource": "users-operations", "permission": "read" },
{ "resource": "users-operations", "permission": "write" },
{ "resource": "teams", "permission": "read" },
{ "resource": "teams", "permission": "write" },
{ "resource": "roles", "permission": "read" }
]
},
{
"key": "codex",
"description": "Full access to codex management.",
"name": "Codex",
"scopes": [
{ "resource": "codex", "permission": "read" },
{ "resource": "codex", "permission": "write" }
]
},
{
"key": "analytics",
"description": "Access to dashboard and reports.",
"name": "Analytics",
"scopes": [
{ "resource": "dashboard", "permission": "read" },
{ "resource": "reports", "permission": "read" },
{ "resource": "report-export", "permission": "read" }
]
},
{
"key": "audit-logs",
"description": "View and export audit logs.",
"name": "Audit-logs",
"scopes": [
{ "resource": "audit-logs", "permission": "read" },
{ "resource": "audit-log-export", "permission": "read" }
]
},
{
"key": "admin-settings",
"description": "Manage categories, integrations, and workflows.",
"name": "Admin-settings",
"scopes": [
{ "resource": "categories", "permission": "read" },
{ "resource": "categories", "permission": "write" },
{ "resource": "app-integrations", "permission": "read" },
{ "resource": "workflows", "permission": "read" },
{ "resource": "workflows", "permission": "write" }
]
}
]
}
Returns the list of scope presets (e.g. full-access, users-management, codex, analytics, audit-logs, admin-settings) with their included scopes. Each preset has key, description, name, and scopes (array of { resource, permission }). Use this endpoint to fetch the initial catalog or to get an updated version when your local cache is stale. See the Caching & Change Detection section below for details on revalidation.
HTTP Request
GET https://api.devici.com/api/v1/users/admin-scopes/presets
Check for Admin Scopes catalog changes
Each of the three catalog endpoints supports HEAD for change detection. Use this to check if the resource has been updated without transferring the full response body.
Example: check if the resources catalog has changed
axios.head("/users/admin-scopes/resources", {
headers: {
"Authorization": "Bearer {{ACCESS_TOKEN}}"
}
});
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=86400, stale-while-revalidate=600
ETag: {{ETag}}
Last-Modified: Thu, 11 Sep 2025 00:00:00 GMT
(No response body)
This endpoint returns only the response headers (without a body). Examine ETag or Last-Modified to see if your cached copy is still current.
HTTP Request
| Catalog | HEAD endpoint |
|---|---|
| Resources | HEAD https://api.devici.com/api/v1/users/admin-scopes/resources |
| Permissions | HEAD https://api.devici.com/api/v1/users/admin-scopes/permissions |
| Presets | HEAD https://api.devici.com/api/v1/users/admin-scopes/presets |
Caching & Change Detection (Admin Scopes)
Example: revalidate the resources catalog with conditional headers
axios.get("/users/admin-scopes/resources", {
headers: {
"Authorization": "Bearer {{ACCESS_TOKEN}}",
"If-None-Match": "{{ETag}}",
"If-Modified-Since": "Thu, 11 Sep 2025 00:00:00 GMT"
}
});
HTTP/1.1 304 Not Modified
(No response body)
To improve performance, cache admin scopes catalog responses. The server returns ETag and Last-Modified on each catalog GET. The same behavior applies to all three endpoints: resources, permissions, and presets.
Revalidating with headers
On a subsequent GET, send the appropriate headers to ask if the resource has changed:
- If-None-Match (preferred): use the
ETagvalue from your cached response. - If-Modified-Since (fallback): use the
Last-Modifieddate from your cached response (valid HTTP-date string, not theversionstring).
If the catalog is unchanged, the server responds with 304 Not Modified and no body; keep using your cached copy. If it has changed, you get 200 OK with the new data.
Headers
| Key | Value | Description |
|---|---|---|
| If-None-Match | {{ETag}} | Preferred method for revalidation. |
| If-Modified-Since | Thu, 11 Sep 2025 00:00:00 GMT | Fallback method. |
Bulk invite users
To send invitations to multiple users use this code:
axios.post("/users/bulk-invite", {
payload: [
{
email: "johndoe@mail.com",
firstName: "John",
lastName: "Doe",
role: "user"
}
]
});
// bulk invite including a user with role "admin" (scopes required per admin)
axios.post("/users/bulk-invite", {
payload: [
{
email: "johndoe@mail.com",
firstName: "John",
lastName: "Doe",
role: "user"
},
{
email: "jane@email.com",
firstName: "Jane",
lastName: "Admin",
role: "admin",
scopes: [
{ resource: "roles", permission: "read" },
{ resource: "users", permission: "read" },
{ resource: "users", permission: "write" },
{ resource: "users-operations", permission: "read" },
{ resource: "users-operations", permission: "write" }
]
}
]
});
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_enabled": true,
"status": "invited",
"created_at": "2025-02-10T14:26:04.248Z"
}
]
Use this endpoint to send invitations to multiple users at once.
role field can be one of admin | user | super_admin, default is user.
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-invite
Invite specific user
To invite specific user use this code:
axios.post("/users/invite", {
email: "johndoe@mail.com",
firstName: "John",
lastName: "Doe",
role: "user"
});
// invite user with role "admin"
axios.post("/users/invite", {
email: "jane@email.com",
firstName: "Jane",
lastName: "Admin",
role: "admin",
scopes: [
{ resource: "roles", permission: "read" }
{ resource: "users", permission: "read" },
{ resource: "users", permission: "write" },
{ resource: "users-operations", permission: "read" },
{ resource: "users-operations", permission: "write" },
]
})
The above command returns JSON structured like this:
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_enabled": true,
"status": "invited",
"created_at": "2025-02-10T14:26:04.248Z",
}
Use this endpoint to invite specific user
role field can be one of admin | user | super_admin, default is user.
HTTP Request
POST https://api.devici.com/api/v1/users/invite
Bulk re-invite users
To resend invitations to multiple users use this code:
axios.post("/users/bulk-re-invite", {
emails: ["johndoe@mail.com"]
});
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_enabled": true,
"status": "invited",
"created_at": "2025-02-10T14:26:04.248Z",
}
]
Use this endpoint to resend invitations to multiple users who have not yet accepted or whose invitations have expired.
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-re-invite
Re-invite specific user
To re-invite specific user use this code:
axios.post("/users/re-invite", {
email: "johndoe@mail.com",
firstName: "John",
lastName: "Doe",
role: "user"
});
The above command returns JSON structured like this:
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_enabled": true,
"status": "invited",
"created_at": "2025-02-10T14:26:04.248Z",
}
Use this endpoint to re-invite a user who has not yet accepted the invitation or whose invitation has expired.
HTTP Request
POST https://api.devici.com/api/v1/users/re-invite
Bulk enable users
To enable multiple user accounts use this code:
axios.post("/users/bulk-enable", {
ids: ["{{user_id}}", "{{user_id}}"]
});
Use this endpoint to enable multiple user accounts at once.
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-enable
Enable specific user
To enable specific user account use this code:
axios.post("/users/enable/{{user_id}}");
Use this endpoint to enable specific user account.
HTTP Request
POST https://api.devici.com/api/v1/users/enable/{{userId}}
Bulk disable users
To disable multiple user accounts use this code:
axios.post("/users/bulk-disable", {
ids: ["{{user_id}}", "{{user_id}}"]
});
Use this endpoint to disable multiple user accounts at once.
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-disable
Disable specific users
To disable specific user account use this code:
axios.post("/users/disable/{{user_id}}");
Use this endpoint to disable specific user account.
HTTP Request
POST https://api.devici.com/api/v1/users/disable/{{user_id}}
Bulk change role for users
To update the roles of multiple users use this code:
axios.post("/users/bulk-change-role", {
payload: [
{
id: "{{user_id}}",
role: "user"
}
]
});
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
}
]
Use this endpoint to update the roles of multiple users in one request.
role field can be one of admin | user | super_admin, default is user
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-change-role
Change role for specific user
To update the role for specific user use this code:
axios.post("/users/change-role", {
id: "{{user_id}}",
role: "user"
});
// change role to "admin"
axios.post("/users/change-role", {
id: "{{user_id}}",
role: "admin",
scopes: [
{ resource: "roles", permission: "read" }
{ resource: "users", permission: "read" },
]
});
The above command returns JSON structured like this:
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
}
Use this endpoint to update the role for specific user.
role field can be one of admin | user | super_admin, default is user.
HTTP Request
POST https://api.devici.com/api/v1/users/change-role
Import users
To import users use this code:
axios.post("/users/bulk-import", {
payload: [
{
firstName: "John",
lastName: "Doe",
email: "johndoe@mail.com",
role: "user"
}
]
});
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
}
]
Use this endpoint to import users by providing their details in bulk.
role field can be one of admin | user | super_admin, default is user
HTTP Request
POST https://api.devici.com/api/v1/users/bulk-import
Delete Specific User
To delete specific user use this code:
axios.delete("/users/:id/:recipientId");
This endpoint deletes a specific user.
HTTP Request
DELETE https://api.devici.com/api/v1/users/:id/:recipientId
Params
| Parameter | Description |
|---|---|
| :id | ID of the user to be deleted |
| :recipientId | ID of the user will inherit the collections of the user being deleted |
Collections
Get All Collections
To get all collections use this code:
axios.get("/collections");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{collection_id}}",
"created_at": "2024-03-28T11:12:06.960Z",
"updated_at": "2024-03-28T11:12:06.960Z",
"title": "Default collection",
"description": null,
"color": null,
"created_by": {
"id": "{{owner_id}}"
}
},
{
"id": "{{collection_id}}",
"created_at": "2024-05-05T20:17:34.201Z",
"updated_at": "2024-05-05T20:17:34.201Z",
"title": "Test collection",
"description": null,
"color": null,
"created_by": {
"id": "{{owner_id}}"
}
}
],
"count": 2
}
This endpoint retrieves collections. By default only active (non-archived) collections are returned.
HTTP Request
GET https://api.devici.com/api/v1/collections
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
| activeOnly | — | When true, returns only active (non-archived) collections (default behaviour) |
| archivedOnly | — | When true, returns only archived collections. If both activeOnly and archivedOnly are true, defaults to active only. |
Get a Specific Collection
To get specific collection use this code:
axios.get("/collections/:id");
The above command returns JSON structured like this:
{
"id": "{{collection_id}}",
"created_at": "2024-03-28T11:12:06.960Z",
"updated_at": "2024-03-28T11:12:06.960Z",
"title": "Default collection",
"description": null,
"color": null,
"created_by": {
"id": "{{owner_id}}"
}
}
This endpoint retrieves a specific collection.
HTTP Request
GET https://api.devici.com/api/v1/collections/:id
Create Collection
To create collection use this code:
axios.post("/collections", {
title: "New Collection from Public API",
description: "This Collection created form public api",
threatModelsData: [
{
title: "Threat model",
description: "this is the Threat model desctiption",
canvasData: [
{
nodes: [],
edges: [],
title: "Canvas title",
},
],
},
],
});
This endpoint create a specific collection.
HTTP Request
POST https://api.devici.com/api/v1/collections
Update a Specific Collection
To update specific collection use this code:
axios.patch("/collections/:id", {
title: "New Title",
description: "New description",
color: "#ffffff",
});
This endpoint update a specific collection.
HTTP Request
PATCH https://api.devici.com/api/v1/collections/:id
Get Users with granted access to a specific Collection
To get users who have access to a specific collection use this code:
axios.get("/collections/users-access/{{collection_id}}");
The above command returns JSON structured like this:
[
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe"
"permission": "read"
},
...
]
Use this endpoint to retrieve all users who have been granted access to a specific collection.
HTTP Request
GET https://api.devici.com/api/v1/collections/users-access/{{collection_id}}
Bulk Grant Users Access
To bulk grant access to multiple users for one or more collections, use this code:
axios.post("/collections/users-access/bulk-grant", {
payload: [
{
collectionId: "{{collection_id}}",
usersPermissions: [
{
userId: "{{user_id}}",
permission: "read"
},
{
userId: "{{user_id}}",
permission: "write"
}
]
}
]
});
Use this endpoint to grant access to multiple users for one or more collections in bulk
permission field must be one of read | write | manage
HTTP Request
POST https://api.devici.com/api/v1/collections/users-access/bulk-grant
Grant User Access
To grant access to a specific collection to one or more users, use this code:
axios.post("/collections/users-access/grant", {
collectionId: "{{collection_id}}",
usersPermissions: [
{
userId: "{{user_id}}",
permission: "read"
},
{
userId: "{{user_id}}",
permission: "write"
}
]
});
Use this endpoint to grant access to specific collection
permission field must be one of read | write | manage
HTTP Request
POST https://api.devici.com/api/v1/collections/users-access/grant
Bulk Revoke Users Access
To bulk revoke access for multiple users from one or more collections, use this code:
axios.post("/collections/users-access/bulk-revoke", {
payload: [
{
collectionId: "{{collection_id}}",
usersIds: ["user_id", "user_id"]
}
]
});
Use this endpoint to revoke access for multiple users from one or more collections in bulk.
HTTP Request
POST https://api.devici.com/api/v1/collections/users-access/bulk-revoke
Revoke User Access
To revoke access to a specific collection from one or more users, use this code:
axios.post("/collections/users-access/revoke", {
collectionId: "{{collection_id}}",
usersIds: ["user_id", "user_id"]
});
Use this endpoint to revoke access to a specific collection
HTTP Request
POST https://api.devici.com/api/v1/collections/users-access/revoke
Get Teams with granted access to a specific Collection
To get teams that have been granted access to a specific collection use this code:
axios.get("/collections/teams-access/{{collection_id}}");
The above command returns JSON structured like this:
[
{
"id": "{{team_id}}",
"title": "Alpha",
"users": [
{
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe"
}
],
"permission": "read"
},
...
]
Use this endpoint to retrieve all teams that have been granted access to a specific collection.
HTTP Request
GET https://api.devici.com/api/v1/collections/teams-access/{{collection_id}}
Bulk Grant Teams Access
To grant access to multiple teams for one or more collections, use this code:
axios.post("/collections/teams-access/bulk-grant", {
payload: [
{
collectionId: "{{collection_id}}",
teamsPermissions: [
{
teamId: "{{team_id}}",
permission: "read"
},
{
teamId: "{{team_id}}",
permission: "write"
}
]
}
]
});
Use this endpoint to grant access to multiple teams for one or more collections in bulk.
permission field must be one of read | write | manage
HTTP Request
POST https://api.devici.com/api/v1/collections/teams-access/bulk-grant
Grant Team Access
To grant access to multiple teams for specific collection, use this code:
axios.post("/collections/teams-access/grant", {
collectionId: "{{collection_id}}",
teamsPermissions: [
{
teamId: "{{team_id}}",
permission: "read"
},
{
teamId: "{{team_id}}",
permission: "write"
}
]
});
Use this endpoint to grant access to multiple teams for specific collection.
permission field must be one of read | write | manage
HTTP Request
POST https://api.devici.com/api/v1/collections/teams-access/grant
Bulk Revoke Teams Access
To revoke access for multiple teams from one or more collections, use this code:
axios.post("/collections/teams-access/bulk-revoke", {
payload: [
{
collectionId: "{{collection_id}}",
teamsIds: ["team_id", "team_id"]
}
]
});
Use this endpoint to revoke access for multiple teams from one or more collections in bulk.
HTTP Request
POST https://api.devici.com/api/v1/collections/teams-access/bulk-revoke
Revoke Teams Access
To revoke access for multiple teams from specific collection, use this code:
axios.post("/collections/teams-access/revoke", {
collectionId: "{{collection_id}}",
teamsIds: ["team_id", "team_id"]
});
Use this endpoint to revoke access for multiple teams from specific collection.
HTTP Request
POST https://api.devici.com/api/v1/collections/teams-access/revoke
Delete a Specific Collection
To delete specific collection use this code:
axios.delete("/collections/:id");
This endpoint deletes a specific collection.
HTTP Request
DELETE https://api.devici.com/api/v1/collections/:id
Threat Models
Get All Threat Models
To get all Threat Models use this code:
axios.get("/threat-models");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{threat_model_id}}",
"created_at": "2024-05-08T16:27:08.765Z",
"updated_at": "2024-05-10T07:51:01.753Z",
"title": "Last created tm",
"description": "hello",
"status": "Threats & Mitigations",
"priority": "medium",
"due_to_date": null,
"retro_completed_at": null,
"time_invested": null,
"quality_of_model": null,
"when_to_revisit": null,
"archived_at": null,
"owner": {
"id": "{{owner_id}}",
"email": "owner.i@mail.com",
"first_name": "Temirlan",
"last_name": "sdf"
},
"collection": {
"id": "{{collection_id}}",
"title": "Hello22"
},
"tags": [
{ "id": "{{tag_id}}", "title": "compliance", "color": "#004EAD" }
]
},
{
"id": "{{threat_model_id}}",
"created_at": "2024-05-06T09:33:03.817Z",
"updated_at": "2024-05-06T09:33:03.817Z",
"title": "hello one",
"description": "test",
"status": "Representation",
"priority": "medium",
"due_to_date": null,
"retro_completed_at": null,
"time_invested": null,
"quality_of_model": null,
"when_to_revisit": null,
"archived_at": null,
"owner": {
"id": "{{owner_id}}",
"email": "owner.i@mail.com",
"first_name": "Temirlan",
"last_name": "sdf"
},
"collection": {
"id": "{{collection_id}}",
"title": "New Title 222"
},
"tags": []
}
],
"count": 2
}
This endpoint retrieves all threat models.
HTTP Request
GET https://api.devici.com/api/v1/threat-models
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
| include_archived | false | Include archived Threat Models |
| tagsIds | Optional. Filter to threat models having any of the supplied tag IDs. |
Get All Threat Models by Collection
To get all Threat Models by Collection id use this code:
axios.get("/threat-models/collection/:collectionId");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{threat_model_id}}",
"created_at": "2024-05-08T16:27:08.765Z",
"updated_at": "2024-05-10T07:51:01.753Z",
"title": "Draft Threat Model",
"description": "hello",
"status": "Threats & Mitigations",
"priority": "medium",
"due_to_date": null,
"retro_completed_at": null,
"time_invested": null,
"quality_of_model": null,
"when_to_revisit": null,
"archived_at": null,
"owner": {
"id": "{{owner_id}}",
"email": "owner.i@mail.com",
"first_name": "Temirlan",
"last_name": "sdf"
},
"canvases": [
{ "id": "{{canvas_id}}" },
{ "id": "{{canvas_id}}" }
],
"collection": {
"id": "{{collection_id}}",
"title": "Collection title",
"description": null,
"color": null,
"type": "default"
},
"tags": [
{ "id": "{{tag_id}}", "title": "compliance", "color": "#004EAD" }
]
},
{
"id": "{{threat_model_id}}",
"created_at": "2024-05-06T09:33:03.817Z",
"updated_at": "2024-05-06T09:33:03.817Z",
"title": "Draft Threat Model 2",
"description": "description",
"status": "Representation",
"priority": "medium",
"due_to_date": null,
"retro_completed_at": null,
"time_invested": null,
"quality_of_model": null,
"when_to_revisit": null,
"archived_at": null,
"owner": {
"id": "{{owner_id}}",
"email": "owner.i@mail.com",
"first_name": "Temirlan",
"last_name": "sdf"
},
"canvases": [
{ "id": "{{canvas_id}}" },
{ "id": "{{canvas_id}}" }
],
"collection": {
"id": "{{collection_id}}",
"title": "Collection title",
"description": null,
"color": null,
"type": "default"
},
"tags": []
}
],
"count": 2
}
This endpoint retrieves all threat models that belong to provided collection.
HTTP Request
GET https://api.devici.com/api/v1/threat-models/collection/:collectionId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
| include_archived | false | Include archived Threat Models |
Get a Specific Threat Model
To get specific threat model use this code:
axios.get("/threat-models/:id");
The above command returns JSON structured like this:
{
"id": "{{threat_model_id}}",
"title": "hello one",
"description": "test",
"status": "Representation",
"priority": "medium",
"due_to_date": null,
"retro_completed_at": null,
"time_invested": null,
"quality_of_model": null,
"when_to_revisit": null,
"owner": {
"id": "{{owner_id}}"
},
"canvases": [],
"tags": [
{ "id": "{{tag_id}}", "title": "compliance", "color": "#004EAD" }
]
}
This endpoint retrieves a specific threat model.
HTTP Request
GET https://api.devici.com/api/v1/threat-models/:id
Create Threat Model
To create threat model use this code:
axios.post("/threat-models", {
title: "New Threat Model",
description: "This Threat model created form public api",
collectionId: "{{collection-id}}",
canvasData: [{ title: "New Canvas", nodes: [], edges: [] }],
});
This endpoint create a specific threat model.
HTTP Request
POST https://api.devici.com/api/v1/threat-models
Create Many Threat Models
To create many threat models use this code:
axios.post("/threat-models/many", {
collectionId: "{{collection-id}}",
threatModelsData: [
{
title: "New First Threat Model",
description: "This Threat model created form public api",
canvasData: [{ title: "New Canvas", nodes: [], edges: [] }],
},
{
title: "New Second Threat Model",
description: "This Threat model created form public api",
canvasData: [{ title: "New Canvas", nodes: [], edges: [] }],
},
],
});
This endpoint create a many threat models.
HTTP Request
POST https://api.devici.com/api/v1/threat-models/many
Update a Specific Threat Model
To update specific threat model use this code:
axios.patch("/threat-models/:id", {
title: "New Title",
description: "New description",
status: "new status",
priority: "new priority",
due_to_date: "due_to_date",
time_invested: 1,
quality_of_model: 1,
when_to_revisit: 1,
source_threats_methodologies: ["{{methodology_id_1}}"],
include_custom_codex: true,
tagsIds: ["{{tag_id_1}}", "{{tag_id_2}}"],
});
This endpoint updates a specific threat model.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
| title | string | Optional. New title. |
| description | string | Optional. New description. |
| status | string | Optional. New status. |
| priority | string | Optional. New priority. |
| due_to_date | string | Optional. ISO due date. |
| time_invested | number | Optional. Hours invested (1-100). |
| quality_of_model | number | Optional. Quality of model (1-10). |
| when_to_revisit | number | Optional. Revisit cadence (1-3). |
| source_threats_methodologies | string[] | Optional. Override flow — methodology UUIDs that restrict which threats Devici auto-syncs onto components when attributes are assigned. Discover valid IDs via GET /codex/built-in/threats/catalog. Empty array clears the filter (auto-sync all methodologies). Omit to leave unchanged. Unknown IDs return 400 Methodology <id> not found. Affects future attribute assignments only — threats already on components are not retroactively pruned. |
| include_custom_codex | boolean | Optional. Override flow — when true, the auto-sync also includes threats defined in your organisation's custom codex (in addition to any built-in methodologies set above); when false, the custom codex is excluded. Omit to leave unchanged. |
| tagsIds | string[] | Optional. Override flow — replaces the threat model's tag list with exactly the supplied IDs. Empty array clears all tags. Omit the field to leave tags unchanged. All IDs must belong to the caller's customer. |
HTTP Request
PATCH https://api.devici.com/api/v1/threat-models/:id
Response shape
GET / PATCH responses surface methodology data in an enriched form:
{
"id": "...",
"title": "...",
"source_threats_methodologies": [
{"id": "9b...", "title": "STRIDE"}
],
"include_custom_codex": false,
"tags": [],
"canvases": ["..."]
}
The source_threats_methodologies array contains the methodology entities currently scoping auto-sync. An empty array means auto-sync is unrestricted (all methodologies). The include_custom_codex boolean reflects whether the customer's custom codex is also included.
Common methodology / custom-codex patterns
Both source_threats_methodologies and include_custom_codex use override semantics — whatever value you send replaces the current value entirely. There is no merge.
| Goal | PATCH body |
|---|---|
| Set a single methodology | {"source_threats_methodologies": ["<stride_id>"]} |
| Set multiple methodologies | {"source_threats_methodologies": ["<stride_id>", "<linddun_id>"]} |
| Add a methodology to the current list | First GET /threat-models/:id, read the existing IDs from source_threats_methodologies[].id, append the new one, then PATCH with the merged array. Sending only the new ID replaces the current list — STRIDE will be dropped. |
| Replace one methodology with another | {"source_threats_methodologies": ["<new_id>"]} — the old ones are dropped |
| Clear the methodology filter only (keep custom codex as is) | {"source_threats_methodologies": []} |
| Clear ALL framing (no methodologies, no custom codex) | {"source_threats_methodologies": [], "include_custom_codex": false} |
| Toggle custom codex on/off without touching methodologies | {"include_custom_codex": true} or {"include_custom_codex": false} |
Affects future attribute assignments only — threats already on components are not retroactively pruned when the methodology filter changes.
Delete a Specific Threat Model
To delete specific threat model use this code:
axios.delete("/threat-models/:id");
This endpoint deletes a specific threat model.
HTTP Request
DELETE https://api.devici.com/api/v1/threat-models/:id
Export a PDF Report
To export a specific threat model PDF report, use this code:
axios.get("/threat-models/report/:id/canvas/:canvasId");
This endpoint exports a specific threat model PDF report.
HTTP Request
GET https://api.devici.com/api/v1/threat-models/report/:threatModelId/canvas/:canvasId
Export an Image
To export a specific canvas as an image, use this code:
axios.get("/threat-models/image/:canvasId");
This endpoint exports a specific canvas as an image.
HTTP Request
GET https://api.devici.com/api/v1/threat-models/image/:canvasId
Export a Neo4j
To export a specific canvas in Neo4j JSON format, use this code:
axios.get("/threat-models/neo4j/:canvasId");
The result will be json with the following data:
{
"nodes": [
{
"id": "{{component_id}}",
"labels": [
"Process"
],
"properties": {
"color": "#00BFFF",
"size": 3,
"type": "processNode"
}
},
{
"id": "{{component_id}}",
"labels": [
"Process"
],
"properties": {
"color": "#00BFFF",
"size": 3,
"type": "processNode"
}
}
],
"relationships": [
{
"id": "{{component_id}}",
"type": "Dataflow",
"start": "{{component_id}}",
"end": "{{component_id}}",
"properties": {
"color": "#6F767E"
}
}
]
}
This endpoint exports a specific canvas in Neo4j JSON format.
HTTP Request
GET https://api.devici.com/api/v1/threat-models/neo4j/:canvasId
Export an OTM
To export a specific threat model in OTM format.
To export a specific threat model in OTM format, use this code:
axios.get("/threat-models/otm/:id");
In response, a JSON file with the following fields will be received:
{
"parentProjectId": "{{parent_collection_id}}",
"otmVersion": "0.2.0",
"project": {
"name": "Draft threat model",
"id": "{{project_id}}",
"description": null,
"owner": "Tom End",
"ownerContact": "tom.e@gmail.com",
"tags": [],
"attributes": null
},
"representations": [
{
"name": "Canvas 1",
"id": "{{canvas_id}}",
"type": "diagram",
"size": null,
"attributes": null
}
],
"assets": [],
"components": [
{
"representationId": "{{canvas_id}}",
"name": "Process",
"id": "{{component_id}}",
"description": "",
"metaData": {
"user": {
"id": "{{user_id}}",
"role": "admin",
"email": "tom.e@gmail.com",
"tierData": {
"tier": "business",
"seats": {
"limit": 5,
"available": 3,
"isSeatsLimitExceeded": false
},
"codeGenius": {
"limit": 100,
"available": 100
},
"isBetaUser": false,
"billingPeriod": "year"
},
"last_name": "Tom",
"first_name": "End",
"productFruitsHash": "{{product_fruits_hash}}",
"isOnboardingCompleted": true
},
"label": "Process",
"selectedBy": [],
"representation": "{{component_id}}"
},
"parent": {
"trustZone": "{{component_id}}"
},
"type": "processNode",
"tags": [],
"representations": [
{
"representation": "{{canvas_id}}",
"id": "{{component_id}}",
"position": {
"x": -72.6225961538461,
"y": 665.6923076923076
},
"size": {
"width": -1,
"height": -1
},
"positionAbsolute": {
"x": -72.6225961538461,
"y": 661.8461538461538
}
}
],
"assets": null,
"threats": [],
"attributes": {}
}
],
"dataflows": [
{
"name": "Dataflow",
"id": "{{dataflow_id}}",
"bidirectional": false,
"source": "{{component_id}}",
"destination": "{{component_id}}",
"metaData": {
"color": "#6F767E",
"label": "Dataflow",
"points": [],
"fontSize": 12,
"algorithm": "linear",
"fontColor": "#ffffff",
"textStyle": {
"isBold": false
},
"markerType": "end",
"selectedBy": [],
"representation": "{{component_id}}"
},
"tags": null,
"assets": null,
"representations": null,
"threats": [],
"attributes": {},
"sourceHandle": "sourceRight",
"targetHandle": "sourceLeft",
"type": "default",
"markerEnd": {
"type": "arrowclosed",
"color": "#6F767E"
}
}
],
"trustZones": [],
"threats": [],
"mitigations": []
}
HTTP Request
GET https://api.devici.com/api/v1/threat-models/otm/:id
Import an OTM
To import OTM for creating the threat model, use this code:
axios.post("/threat-models/otm/:collectionId");
The following result will be received:
{
"id": "{{threat_model_id}}"
}
This endpoint imports an OTM file for creating a threat model in a specific collection.
HTTP Request
POST https://api.devici.com/api/v1/threat-models/otm/:collectionId
Tags
Tags are organization-level labels (scoped per customer) that you can attach to threat models, codex attributes, codex threats, and codex mitigations. Every tag belongs to exactly one customer; the API only ever returns and mutates tags owned by the caller's customer.
List Tags
To list tags use this code:
axios.get("/tags");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{tag_id}}",
"title": "compliance",
"color": "#004EAD",
"created_at": "2026-04-15T12:00:00.000Z"
}
],
"count": 1
}
This endpoint retrieves all tags belonging to the caller's customer.
HTTP Request
GET https://api.devici.com/api/v1/tags
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Items per page (max 100) |
| page | 0 | Page number (0-based) |
| order | ASC | Sort direction by title (ASC or DESC) |
| text | Optional case-insensitive substring filter on title |
Get a Specific Tag
To fetch a single tag use this code:
axios.get("/tags/:id");
The above command returns JSON structured like this:
{
"id": "{{tag_id}}",
"title": "compliance",
"color": "#004EAD",
"created_at": "2026-04-15T12:00:00.000Z"
}
This endpoint retrieves a single tag by ID.
HTTP Request
GET https://api.devici.com/api/v1/tags/:id
Create Tag
To create a tag use this code:
axios.post("/tags", {
title: "compliance",
color: "#004EAD",
});
The above command returns JSON structured like this:
{
"id": "{{tag_id}}",
"title": "compliance",
"color": "#004EAD",
"created_at": "2026-04-15T12:00:00.000Z"
}
This endpoint creates a tag.
HTTP Request
POST https://api.devici.com/api/v1/tags
Body Parameters
| Parameter | Type | Description |
|---|---|---|
| title | string | Required. Up to 100 characters. Allowed: alphanumerics, hyphens, single spaces (no leading/trailing spaces). |
| color | string | Required. Hex color string (#RGB or #RRGGBB). |
Update a Specific Tag
To update a tag use this code:
axios.patch("/tags/:id", {
title: "compliance-v2",
color: "#8B3BB2",
});
This endpoint updates a tag. Both fields are optional — pass only what you want to change.
HTTP Request
PATCH https://api.devici.com/api/v1/tags/:id
Delete a Specific Tag
To delete a tag use this code:
axios.delete("/tags/:id");
This endpoint deletes a tag. The tag is detached from any resources it was attached to (threat models, codex items).
HTTP Request
DELETE https://api.devici.com/api/v1/tags/:id
Canvases
Get All Canvases
To get all Canvases use this code:
axios.get("/canvases/threat-model/:threatModelId");
{
"items": [
{
"id": "{{canvas_id}}",
"created_at": "2024-05-08T16:27:08.765Z",
"updated_at": "2024-05-08T16:27:08.765Z",
"title": "Canvas title",
"format": "diagram",
"data": {
"edges": [],
"nodes": []
},
"threat_model": {
"id": "{{threat_model_id}}"
}
}
],
"count": 1
}
This endpoint retrieves all canvases for provided threat model.
HTTP Request
GET https://api.devici.com/api/v1/canvases/threat-model/:threatModelId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
Get a Specific Canvas
To get specific canvas use this code:
axios.get("/canvases/:id");
The above command returns JSON structured like this:
{
"id": "{{canvas_id}}",
"created_at": "2024-05-08T16:27:08.765Z",
"updated_at": "2024-05-08T16:27:08.765Z",
"title": "Canvas",
"format": "diagram",
"data": {
"edges": [],
"nodes": []
},
"threat_model": {
"id": "{{threat_model_id}}"
}
}
This endpoint retrieves a specific canvas.
HTTP Request
GET https://api.devici.com/api/v1/canvases/:id
Create Canvas
To create canvases use this code:
axios.post("/canvases", {
title: "New Canvas",
threatModelId: "{{threat_model_id}}"
format: "diagram",
data: {
nodes: [],
edges: [],
},
});
This endpoint create a specific canvas.
HTTP Request
POST https://api.devici.com/api/v1/canvases
Update a Specific Canvas
To update specific canvas use this code:
axios.patch("/canvases/:id", {
title: "New title",
threatModelId: "{{threat_model_id}}",
format: "diagram",
data: {
nodes: [],
edges: [],
},
});
This endpoint update a specific canvas.
HTTP Request
PATCH https://api.devici.com/api/v1/canvases/:id
Delete a Specific Canvas
To delete specific canvas use this code:
axios.delete("/canvases/:id");
This endpoint deletes a specific canvas.
HTTP Request
DELETE https://api.devici.com/api/v1/canvases/:id
Components
Get All Components
To get all Components use this code:
axios.get("/components");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{component_id}}",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"title": "Dataflow",
"description": "",
"canvas": {
"id": "{{canvas_id}}"
}
},
{
"id": "{{component_id}}",
"created_at": "2024-05-17T16:54:11.682Z",
"updated_at": "2024-05-17T16:54:11.682Z",
"title": "Process",
"description": "",
"canvas": {
"id": "{{canvas_id}}"
}
}
],
"count": 2
}
This endpoint retrieves all threat models.
HTTP Request
GET https://api.devici.com/api/v1/components
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
Get a Specific Component
To get specific component use this code:
axios.get("/components/:id");
The above command returns JSON structured like this:
{
"id": "{{component_id}}",
"created_at": "2024-05-17T16:54:11.682Z",
"updated_at": "2024-05-17T16:54:11.682Z",
"title": "Process",
"description": "",
"canvas": {
"id": "{{canvas_id}}"
},
"attributes": [],
"threats": []
}
This endpoint retrieves a specific component.
HTTP Request
GET https://api.devici.com/api/v1/components/:id
Get All Components for specific Canvas
To get all Components for specific canvas use this code:
axios.get("/components/for-canvas/:canvasId");
The above command returns JSON structured like this:
[
{
"id": "{{component_id}}",
"created_at": "2024-05-17T09:59:56.914Z",
"updated_at": "2024-05-17T09:59:56.914Z",
"title": "Datastore",
"description": "",
"attributes": [],
"threats": []
},
{
"id": "{{component_id}}",
"created_at": "2024-05-17T09:59:56.914Z",
"updated_at": "2024-05-17T09:59:56.914Z",
"title": "Dataflow",
"description": "",
"attributes": [],
"threats": []
}
]
This endpoint retrieves all components for specific canvas.
HTTP Request
GET https://api.devici.com/api/v1/components/for-canvas/:canvasId
Attributes
Attributes can be added to components from three distinct sources, clearly separated in the request body:
built_in— Attributes from the Devici built-in library (identified by the attributeidreturned fromGET /v1/codex/built-in/attributes)custom_codex— Attributes from your organisation's custom codex (identified by id)custom— User-defined attributes scoped to the canvas: create new ones (providetitle) or reuse existing custom attributes from the same canvas (provideid)
When built-in or custom codex attributes are added, related threats are automatically synced to the component.
Rate Limits & Constraints
| Limit | Value |
|---|---|
Max attributes per source per request (built_in, custom_codex, custom) |
20 |
| Max operations per bulk-add request | 20 |
| Max IDs per bulk-remove request | 100 |
Add Attribute(s) to Component
To add attributes to a component use this code:
axios.post("/attributes", {
component_id: "{{component_id}}",
built_in: [
{ id: "{{built_in_attribute_id}}" }
],
custom_codex: [
{ id: "{{codex_attribute_id}}" }
],
custom: [
{ title: "New custom attribute", description: "A custom description" },
{ id: "{{existing_custom_attr_id}}" }
]
});
The above command returns JSON structured like this:
{
"built_in": [
{
"id": "{{attribute_id}}",
"ref_id": "{{built_in_attribute_id}}",
"title": "Authentication",
"description": "Validates the identity of a user or system.",
"type": "functional",
"assignable_to_components": ["process", "external_entity"]
}
],
"custom_codex": [
{
"id": "{{attribute_id}}",
"ref_id": "{{codex_attribute_id}}",
"title": "My Codex Attribute",
"description": "From organisation codex.",
"type": "data",
"assignable_to_components": ["datastore", "process"]
}
],
"custom": [
{
"id": "{{attribute_id}}",
"title": "New custom attribute",
"description": "A custom description",
"created_by": "{{user_id}}"
}
]
}
This endpoint adds one or more attributes to a component from any combination of sources. At least one of built_in, custom_codex, or custom must be provided and non-empty.
HTTP Request
POST https://api.devici.com/api/v1/attributes
Request Body
| Field | Required | Description |
|---|---|---|
| component_id | Yes | UUID of the target component |
| built_in | No | Built-in library attributes. Each item requires id (the attribute primary UUID returned by GET /v1/codex/built-in/attributes). Max 20 items. |
| custom_codex | No | Custom codex attributes. Each item requires id. Max 20 items. |
| custom | No | Canvas-scoped user-defined attributes. Each item requires either id (reuse an existing custom attribute from the same canvas) or title (create a new one). Max 20 items. |
Custom Source Item Fields
| Field | Description |
|---|---|
| id | UUID of an existing custom attribute to reuse — must belong to the same canvas as the target component |
| title | Title for a new custom attribute (required when id is not provided) |
| description | Optional description for new custom attributes |
Built-in and Custom Codex Response Item Fields
| Field | Description |
|---|---|
| id | UUID of the attribute instance attached to the component |
| ref_id | UUID of the source attribute. For built_in items this is the library attribute primary id (the same one you sent in the request); for custom_codex items it's the codex attribute primary id. Use it to deduplicate or to look up the original definition. |
| title | Attribute title |
| description | Attribute description |
| type | Attribute type: functional or data |
| assignable_to_components | Component types this attribute can be applied to. Possible values: process, external_entity, datastore, dataflow, trust_boundary |
Duplicate Prevention
The same library or codex attribute cannot be attached twice to the same component. If a request would attach the same attribute (matched by ref_id) more than once — either across built_in and custom_codex items in a single request, or against an attribute already present on the component — the call returns 400 Bad Request with a message like Attribute <ref_id> is already attached to component <component_id>. Custom (inline) attributes are unaffected and may have duplicate titles.
Bulk Add Attributes
To bulk add attributes to multiple components use this code:
axios.post("/attributes/bulk-add", {
operations: [
{
component_id: "{{component_id_1}}",
built_in: [{ id: "{{built_in_attribute_id_1}}" }],
custom: [{ title: "Custom attr A" }]
},
{
component_id: "{{component_id_2}}",
built_in: [{ id: "{{built_in_attribute_id_2}}" }]
}
]
});
The above command returns JSON structured like this:
[
{
"component_id": "{{component_id_1}}",
"attributes": {
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id_1}}", "title": "Authentication", "description": "...", "type": "functional", "assignable_to_components": ["process", "external_entity"] }
],
"custom_codex": [],
"custom": [
{ "id": "{{attribute_id}}", "title": "Custom attr A", "description": null, "created_by": "{{user_id}}" }
]
}
},
{
"component_id": "{{component_id_2}}",
"attributes": {
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id_2}}", "title": "Authorization", "description": "...", "type": "functional", "assignable_to_components": ["process"] }
],
"custom_codex": [],
"custom": []
}
}
]
This endpoint adds attributes to one or multiple components in a single request. Returns an array of { component_id, attributes } entries — one entry per affected component (operations targeting the same component are merged into a single entry).
HTTP Request
POST https://api.devici.com/api/v1/attributes/bulk-add
Request Body
| Field | Required | Description |
|---|---|---|
| operations | Yes | Array of add-attribute operations. Each operation follows the same schema as POST /attributes. Min 1, max 20 operations. |
Bulk Remove Attributes
To bulk remove attributes use this code:
axios.post("/attributes/bulk-remove", {
ids: [
"{{attribute_id_1}}",
"{{attribute_id_2}}"
]
});
This endpoint removes multiple attributes by IDs in a single request. Any threats caused exclusively by a removed attribute are automatically deleted.
HTTP Request
POST https://api.devici.com/api/v1/attributes/bulk-remove
Request Body
| Field | Required | Description |
|---|---|---|
| ids | Yes | Array of attribute UUIDs to remove. Min 1, max 100 IDs. |
Get Attributes by Component
To get attributes for a specific component use this code:
axios.get("/attributes/component/{{component_id}}");
The above command returns JSON structured like this:
{
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id}}", "title": "Authentication", "description": "...", "type": "functional", "assignable_to_components": ["process", "external_entity"] }
],
"custom_codex": [
{ "id": "{{attribute_id}}", "ref_id": "{{codex_attribute_id}}", "title": "My Codex Attribute", "description": "...", "type": "data", "assignable_to_components": ["datastore"] }
],
"custom": [
{ "id": "{{attribute_id}}", "title": "My Custom Attribute", "description": "...", "type": null, "created_by": "{{user_id}}" }
]
}
This endpoint retrieves all attributes on a component, grouped by source.
HTTP Request
GET https://api.devici.com/api/v1/attributes/component/:componentId
Get Attributes by Canvas
To get attributes for all components in a canvas use this code:
// Nested by component (default)
axios.get("/attributes/canvas/{{canvas_id}}");
// Flat — all components merged, deduplicated by title per source
axios.get("/attributes/canvas/{{canvas_id}}?flat=true");
Default response (nested by component):
[
{
"component_id": "{{component_id}}",
"component_title": "Process",
"attributes": {
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id}}", "title": "Authentication", "description": "...", "type": "functional", "assignable_to_components": ["process", "external_entity"] }
],
"custom_codex": [],
"custom": []
}
}
]
Flat response (
?flat=true):
{
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id}}", "title": "Authentication", "description": "...", "type": "functional", "assignable_to_components": ["process", "external_entity"] }
],
"custom_codex": [],
"custom": []
}
This endpoint retrieves attributes for all components in a canvas. By default returns a list nested by component. Use ?flat=true to receive a flat grouped response with attributes deduplicated by title.
HTTP Request
GET https://api.devici.com/api/v1/attributes/canvas/:canvasId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a flat grouped response instead of nesting by component |
Get Attributes by Threat Model
To get attributes for all components in a threat model use this code:
// Nested by component (default)
axios.get("/attributes/threat-model/{{threat_model_id}}");
// Flat
axios.get("/attributes/threat-model/{{threat_model_id}}?flat=true");
Default response (nested by component):
[
{
"component_id": "{{component_id}}",
"component_title": "Process",
"attributes": {
"built_in": [
{ "id": "{{attribute_id}}", "ref_id": "{{built_in_attribute_id}}", "title": "Authentication", "description": "...", "type": "functional", "assignable_to_components": ["process", "external_entity"] }
],
"custom_codex": [],
"custom": []
}
}
]
This endpoint retrieves attributes for all components across all canvases in a threat model. By default returns a list nested by component. Use ?flat=true to receive a flat grouped response with attributes deduplicated by title.
HTTP Request
GET https://api.devici.com/api/v1/attributes/threat-model/:threatModelId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a flat grouped response instead of nesting by component |
Update Custom Attribute
To update a custom attribute use this code:
axios.patch("/attributes/{{attribute_id}}", {
title: "Updated title",
description: "Updated description"
});
This endpoint updates a custom attribute. Only attributes created by users (custom source) can be updated — built-in and codex attributes are read-only. The title must not conflict with another attribute on the same component or with a reserved built-in name.
HTTP Request
PATCH https://api.devici.com/api/v1/attributes/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | No | New title for the attribute |
| description | No | New description |
| type | No | Attribute type: functional or data |
Delete Attribute
To delete an attribute use this code:
axios.delete("/attributes/{{attribute_id}}");
This endpoint deletes an attribute from a component. Any threats caused exclusively by this attribute are automatically deleted as well.
HTTP Request
DELETE https://api.devici.com/api/v1/attributes/:id
Threats
Manage threats on diagram components. Threats can come from three distinct sources, mirroring how the diagram editor lets you drop a Devici-codex threat, an organisation-codex threat, or write a custom one.
built_in— Threats from Devici's built-in library (identified by their library threat id). Adding one auto-imports the threat content and links it to any neutralising attributes already on the component.custom_codex— Threats from your organisation's custom codex (identified by codex threat id).custom— Free-form threats authored inline (title,description,priority, optionalstatus).
Threat Rate Limits & Constraints
| Limit | Value |
|---|---|
| Max threats per source per request | 20 |
| Max operations per bulk-add request | 20 |
| Max IDs per bulk-remove request | 100 |
Add Threat(s) to Component
To add threats to a component use this code:
axios.post("/threats/add-to-component", {
component_id: "{{component_id}}",
built_in: [
{ id: "{{built_in_threat_id}}" }
],
custom_codex: [
{ id: "{{codex_threat_id}}" }
],
custom: [
{
title: "Custom inline threat",
description: "Free-form threat",
priority: "medium",
status: "open"
}
]
});
This endpoint adds one or more threats to a component from any combination of sources. At least one of built_in, custom_codex, or custom must be provided and non-empty.
HTTP Request
POST https://api.devici.com/api/v1/threats/add-to-component
Request Body
| Field | Required | Description |
|---|---|---|
| component_id | Yes | UUID of the target component |
| built_in | No | Built-in library threats. Each item requires id (library threat UUID). Max 20 items. |
| custom_codex | No | Custom codex threats. Each item requires id (codex threat UUID). Max 20 items. |
| custom | No | Inline custom threats. Each item requires title, description, priority. status is optional. Max 20 items. |
Custom Source Item Fields
| Field | Required | Description |
|---|---|---|
| title | Yes | Title of the inline custom threat |
| description | Yes | Description of the threat |
| priority | Yes | One of low, medium, high, critical |
| status | No | One of open, mitigated, transferred, acknowledged (default open) |
Returns the threats grouped by source (current full state of the component):
{
"built_in": [
{
"id": "{{threat_id}}",
"title": "Spoofing Identity",
"description": "...",
"priority": "high",
"status": "open"
}
],
"custom_codex": [],
"custom": [
{
"id": "{{threat_id}}",
"title": "Custom inline threat",
"description": "Free-form threat",
"priority": "medium",
"status": "open",
"created_by": "{{user_id}}"
}
]
}
Bulk Add Threats
To bulk add threats to multiple components use this code:
axios.post("/threats/bulk-add", {
operations: [
{
component_id: "{{component_id_1}}",
built_in: [{ id: "{{built_in_threat_id_1}}" }],
custom: [{ title: "Bulk inline threat", description: "...", priority: "low" }]
},
{
component_id: "{{component_id_2}}",
built_in: [{ id: "{{built_in_threat_id_2}}" }]
}
]
});
This endpoint adds threats to one or multiple components in a single request. Returns an array of grouped responses — one entry per operation, in the same order.
HTTP Request
POST https://api.devici.com/api/v1/threats/bulk-add
Request Body
| Field | Required | Description |
|---|---|---|
| operations | Yes | Array of add-threat operations. Each follows the same schema as POST /threats/add-to-component. Min 1, max 20 operations. |
Returns an array of grouped responses — one entry per operation, in the same order:
[
{
"built_in": [
{ "id": "{{threat_id}}", "title": "Spoofing Identity", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": [
{ "id": "{{threat_id}}", "title": "Bulk inline threat", "description": "...", "priority": "low", "status": "open", "created_by": "{{user_id}}" }
]
},
{
"built_in": [
{ "id": "{{threat_id}}", "title": "Tampering", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": []
}
]
Bulk Remove Threats
To bulk remove threats use this code:
axios.post("/threats/bulk-remove", {
ids: [
"{{threat_id_1}}",
"{{threat_id_2}}"
]
});
Soft-deletes the listed threats. Cross-tenant IDs are rejected.
HTTP Request
POST https://api.devici.com/api/v1/threats/bulk-remove
Request Body
| Field | Required | Description |
|---|---|---|
| ids | Yes | Array of threat UUIDs to remove. Min 1, max 100 IDs. |
Responds with 201 Created and an empty body on success. Returns 403 Forbidden if any ID belongs to another tenant; nothing is removed in that case. Returns 400 Bad Request if any ID is unknown.
Get All Threats
To get all threats use this code:
axios.get("/threats");
This endpoint retrieves all threats for the customer.
HTTP Request
GET https://api.devici.com/api/v1/threats
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 0 | Page number (0-based) |
| sort | created_at | Order by |
| order | ASC | ASC or DESC |
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{threat_id}}",
"created_at": "2024-05-22T16:25:46.212Z",
"updated_at": "2024-05-22T16:25:46.212Z",
"ref_id": "0dda2bb4-c754-471b-93a1-fe74067e1ff0",
"title": "Information Disclosure",
"description": "Information disclosure is the unintentional exposure or release of confidential or sensitive data to unauthorized individuals or entities.",
"source": null,
"priority": "medium",
"status": "open",
"is_custom": false,
"component": {
"id": "{{component_id}}"
}
}
],
"count": 1
}
Get a Specific Threat
To get a specific threat use this code:
axios.get("/threats/:id");
HTTP Request
GET https://api.devici.com/api/v1/threats/:id
Returns:
{
"id": "{{threat_id}}",
"created_at": "2024-05-22T16:25:46.212Z",
"updated_at": "2024-05-22T16:25:46.212Z",
"ref_id": null,
"title": "Custom inline threat",
"description": "Free-form threat",
"source": null,
"priority": "medium",
"status": "open",
"is_custom": true,
"component": {
"id": "{{component_id}}"
}
}
ref_id, source, is_custom indicate the origin: built-in / custom-codex threats have ref_id set to the source UUID and is_custom: false; inline custom threats have ref_id: null and is_custom: true.
Get Threats by Component
To get threats for a specific component (grouped by source) use this code:
axios.get("/threats/component/{{component_id}}");
HTTP Request
GET https://api.devici.com/api/v1/threats/component/:componentId
Returns:
{
"built_in": [
{ "id": "{{threat_id}}", "title": "Spoofing Identity", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": [
{ "id": "{{threat_id}}", "title": "Custom inline threat", "description": "...", "priority": "medium", "status": "open", "created_by": "{{user_id}}" }
]
}
Get Threats for a Specific Component (flat list)
To get all threats for a specific component as a flat list use this code:
axios.get("/threats/for-component/:componentId");
Returns a flat list (not grouped by source). Prefer /threats/component/:componentId (above) when you want the grouped shape.
HTTP Request
GET https://api.devici.com/api/v1/threats/for-component/:componentId
Returns:
[
{
"id": "{{threat_id}}",
"title": "Spoofing Identity",
"description": "...",
"priority": "high",
"status": "open",
"is_custom": false,
"ref_id": "{{built_in_threat_id}}"
}
]
Get Threats by Canvas
To get threats for all components in a canvas use this code:
// Nested by component (default)
axios.get("/threats/canvas/{{canvas_id}}");
// Flat — all components merged, deduplicated by title per source
axios.get("/threats/canvas/{{canvas_id}}?flat=true");
By default returns a list nested by component. Use ?flat=true to receive a single grouped response with threats deduplicated by title.
HTTP Request
GET https://api.devici.com/api/v1/threats/canvas/:representationId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a flat grouped response instead of nesting by component |
Default response (nested by component):
[
{
"component_id": "{{component_id}}",
"component_title": "Process",
"threats": {
"built_in": [
{ "id": "{{threat_id}}", "title": "Spoofing Identity", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": []
}
}
]
Get Threats by Threat Model
To get threats for all components in a threat model use this code:
axios.get("/threats/threat-model/{{threat_model_id}}");
axios.get("/threats/threat-model/{{threat_model_id}}?flat=true");
Same shape as /threats/canvas/:id, scoped to all canvases in the threat model.
HTTP Request
GET https://api.devici.com/api/v1/threats/threat-model/:threatModelId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a flat grouped response instead of nesting by component |
Default response (nested by component, one entry per component across all canvases):
[
{
"component_id": "{{component_id}}",
"component_title": "Process",
"threats": {
"built_in": [
{ "id": "{{threat_id}}", "title": "Spoofing Identity", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": []
}
}
]
Flat response (
?flat=true):
{
"built_in": [
{ "id": "{{threat_id}}", "title": "Spoofing Identity", "description": "...", "priority": "high", "status": "open" }
],
"custom_codex": [],
"custom": []
}
Create a Custom Threat
To create a single custom threat on a component use this code:
axios.post("/threats", {
componentId: "{{component_id}}",
title: "New Threat",
priority: "low",
description: "description"
});
Equivalent to sending a single custom item to POST /threats/add-to-component — useful when you only need to create one inline custom threat at a time and don't need the grouped response.
HTTP Request
POST https://api.devici.com/api/v1/threats
Request Body
| Field | Required | Description |
|---|---|---|
| componentId | Yes | UUID of the target component |
| title | Yes | Threat title |
| description | Yes | Threat description |
| priority | Yes | One of low, medium, high, critical |
| status | No | One of open, mitigated, transferred, acknowledged (default open) |
Returns:
{
"threatId": "{{threat_id}}",
"componentId": "{{component_id}}"
}
Update a Specific Threat
To update a specific threat use this code:
axios.patch("/threats/:id", {
title: "New Title",
description: "New description",
priority: "low",
status: "open"
});
HTTP Request
PATCH https://api.devici.com/api/v1/threats/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | No | New title |
| description | No | New description |
| priority | No | One of low, medium, high, critical |
| status | No | One of open, mitigated, transferred, acknowledged |
Responds with 200 OK and an empty body on success.
Delete a Specific Threat
To delete a specific threat use this code:
axios.delete("/threats/:id");
HTTP Request
DELETE https://api.devici.com/api/v1/threats/:id
Responds with 200 OK and an empty body on success. Soft-deletes the threat — any cascading mitigation links are removed too.
Mitigations
Manage mitigations on threats. Mitigations can come from three distinct sources, mirroring how the diagram editor lets you drop a Devici-codex mitigation, an organisation-codex mitigation, or write a custom one.
built_in— Mitigations from Devici's built-in library (identified by library mitigation id). Auto-imports content from the library.custom_codex— Mitigations from your organisation's custom codex (identified by codex mitigation id).custom— Free-form mitigations authored inline (title,definition, optionalconsideration/explanation/example/question).
Mitigation Rate Limits & Constraints
| Limit | Value |
|---|---|
| Max mitigations per source per request | 20 |
| Max operations per bulk-add request | 20 |
| Max IDs per bulk-remove request | 100 |
Add Mitigation(s) to Threat
To add mitigations to a threat use this code:
axios.post("/mitigations/add-to-threat", {
threat_id: "{{threat_id}}",
built_in: [
{ id: "{{built_in_mitigation_id}}" }
],
custom_codex: [
{ id: "{{codex_mitigation_id}}" }
],
custom: [
{
title: "Custom inline mitigation",
definition: "Free-form mitigation",
consideration: "Optional consideration",
example: "Optional example"
}
]
});
This endpoint attaches one or more mitigations to a threat from any combination of sources. At least one of built_in, custom_codex, or custom must be provided and non-empty.
HTTP Request
POST https://api.devici.com/api/v1/mitigations/add-to-threat
Request Body
| Field | Required | Description |
|---|---|---|
| threat_id | Yes | UUID of the target threat |
| built_in | No | Built-in library mitigations. Each item requires id. Max 20 items. |
| custom_codex | No | Custom codex mitigations. Each item requires id. Max 20 items. |
| custom | No | Inline custom mitigations. Each item requires title and definition. consideration, explanation, example, question are optional. Max 20 items. |
Custom Source Item Fields
| Field | Required | Description |
|---|---|---|
| title | Yes | Mitigation title |
| definition | Yes | What the mitigation does |
| consideration | No | Implementation consideration |
| explanation | No | Why the mitigation works |
| example | No | Concrete example |
| question | No | Question the mitigation answers |
Returns mitigations grouped by source for the threat:
{
"built_in": [
{
"id": "{{mitigation_id}}",
"title": "Strong Authentication",
"definition": "Requires verified identity before granting access."
}
],
"custom_codex": [],
"custom": [
{
"id": "{{mitigation_id}}",
"title": "Custom inline mitigation",
"definition": "Free-form mitigation",
"consideration": "Optional consideration",
"example": "Optional example",
"created_by": "{{user_id}}"
}
]
}
Bulk Add Mitigations
To bulk add mitigations to multiple threats use this code:
axios.post("/mitigations/bulk-add", {
operations: [
{
threat_id: "{{threat_id_1}}",
built_in: [{ id: "{{built_in_mitigation_id_1}}" }],
custom: [{ title: "Bulk mitigation A", definition: "..." }]
},
{
threat_id: "{{threat_id_2}}",
custom_codex: [{ id: "{{codex_mitigation_id_1}}" }]
}
]
});
Returns an array of grouped responses — one entry per operation, in the same order.
HTTP Request
POST https://api.devici.com/api/v1/mitigations/bulk-add
Request Body
| Field | Required | Description |
|---|---|---|
| operations | Yes | Array of add-mitigation operations. Each follows the same schema as POST /mitigations/add-to-threat. Min 1, max 20 operations. |
Returns an array of grouped responses — one entry per operation, in the same order:
[
{
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": [
{ "id": "{{mitigation_id}}", "title": "Bulk mitigation A", "definition": "...", "created_by": "{{user_id}}" }
]
},
{
"built_in": [],
"custom_codex": [
{ "id": "{{mitigation_id}}", "title": "Codex mitigation", "definition": "..." }
],
"custom": []
}
]
Bulk Remove Mitigations
To bulk remove mitigations use this code:
axios.post("/mitigations/bulk-remove", {
ids: [
"{{mitigation_id_1}}",
"{{mitigation_id_2}}"
]
});
HTTP Request
POST https://api.devici.com/api/v1/mitigations/bulk-remove
Request Body
| Field | Required | Description |
|---|---|---|
| ids | Yes | Array of mitigation UUIDs to remove. Min 1, max 100 IDs. |
Responds with 201 Created and an empty body on success. Returns 403 Forbidden if any ID belongs to another tenant; nothing is removed in that case. Returns 400 Bad Request if any ID is unknown.
Get All Mitigations
To get all mitigations use this code:
axios.get("/mitigations");
HTTP Request
GET https://api.devici.com/api/v1/mitigations
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 0 | Page number (0-based) |
| sort | created_at | Order by |
| order | ASC | ASC or DESC |
Get a Specific Mitigation
To get a specific mitigation use this code:
axios.get("/mitigations/:id");
HTTP Request
GET https://api.devici.com/api/v1/mitigations/:id
Returns:
{
"id": "{{mitigation_id}}",
"title": "Strong Authentication",
"definition": "Requires verified identity before granting access.",
"consideration": "...",
"explanation": "...",
"example": "...",
"question": "...",
"status": null,
"is_custom": false,
"threat": {
"id": "{{threat_id}}"
}
}
is_custom: true indicates an inline custom mitigation. Built-in / custom-codex mitigations carry is_custom: false.
Get Mitigations by Threat
To get mitigations grouped by source for a threat use this code:
axios.get("/mitigations/threat/{{threat_id}}");
HTTP Request
GET https://api.devici.com/api/v1/mitigations/threat/:threatId
Returns:
{
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
Get Mitigations for a Specific Threat (flat list)
To get all mitigations on a threat as a flat list use this code:
axios.get("/mitigations/for-threat/:threatId");
Returns a flat list (not grouped by source). Prefer /mitigations/threat/:threatId (above) when you want the grouped shape.
HTTP Request
GET https://api.devici.com/api/v1/mitigations/for-threat/:threatId
Returns:
[
{
"id": "{{mitigation_id}}",
"title": "Strong Authentication",
"definition": "Requires verified identity before granting access.",
"consideration": "...",
"explanation": "...",
"example": "...",
"question": "...",
"status": null,
"is_custom": false,
"threat": { "id": "{{threat_id}}" }
}
]
Get Mitigations by Component
To get mitigations across all threats on a component use this code:
axios.get("/mitigations/component/{{component_id}}");
Returns a list nested by threat — each entry includes the threat id, title, and grouped mitigations.
HTTP Request
GET https://api.devici.com/api/v1/mitigations/component/:componentId
Returns:
[
{
"threat_id": "{{threat_id}}",
"threat_title": "Spoofing Identity",
"mitigations": {
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
}
]
Get Mitigations by Canvas
To get mitigations for all threats in a canvas use this code:
// Nested by threat (default)
axios.get("/mitigations/canvas/{{canvas_id}}");
// Flat — all threats merged, deduplicated by title per source
axios.get("/mitigations/canvas/{{canvas_id}}?flat=true");
HTTP Request
GET https://api.devici.com/api/v1/mitigations/canvas/:representationId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a single grouped response instead of nesting by threat |
Default response (nested by threat):
[
{
"threat_id": "{{threat_id}}",
"threat_title": "Spoofing Identity",
"mitigations": {
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
}
]
Flat response (
?flat=true):
{
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
Get Mitigations by Threat Model
To get mitigations for every threat in a threat model use this code:
axios.get("/mitigations/threat-model/{{threat_model_id}}");
axios.get("/mitigations/threat-model/{{threat_model_id}}?flat=true");
Same shape as /mitigations/canvas/:id, scoped to all canvases in the threat model.
HTTP Request
GET https://api.devici.com/api/v1/mitigations/threat-model/:threatModelId
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| flat | false | When true, returns a flat grouped response instead of nesting by threat |
Default response (nested by threat, one entry per threat across all canvases in the model):
[
{
"threat_id": "{{threat_id}}",
"threat_title": "Spoofing Identity",
"mitigations": {
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
}
]
Flat response (
?flat=true):
{
"built_in": [
{ "id": "{{mitigation_id}}", "title": "Strong Authentication", "definition": "..." }
],
"custom_codex": [],
"custom": []
}
Create a Custom Mitigation
To create a single custom mitigation on a threat use this code:
axios.post("/mitigations", {
threatId: "{{threat_id}}",
title: "New Mitigation",
definition: "How it mitigates the threat"
});
Equivalent to sending a single custom item to POST /mitigations/add-to-threat — useful when you only need to create one inline custom mitigation at a time and don't need the grouped response.
HTTP Request
POST https://api.devici.com/api/v1/mitigations
Request Body
| Field | Required | Description |
|---|---|---|
| threatId | Yes | UUID of the parent threat |
| title | Yes | Mitigation title |
| definition | Yes | What the mitigation does |
| consideration | No | Implementation consideration |
| explanation | No | Why the mitigation works |
| example | No | Concrete example |
| question | No | Question the mitigation answers |
Returns:
{
"mitigationId": "{{mitigation_id}}",
"threatId": "{{threat_id}}"
}
Update a Specific Mitigation
To update a specific mitigation use this code:
axios.patch("/mitigations/:id", {
title: "New Title",
definition: "New definition"
});
HTTP Request
PATCH https://api.devici.com/api/v1/mitigations/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | No | New title |
| definition | No | New definition |
| consideration | No | New consideration |
| explanation | No | New explanation |
| example | No | New example |
| status | No | New status |
Responds with 200 OK and an empty body on success.
Delete a Specific Mitigation
To delete a specific mitigation use this code:
axios.delete("/mitigations/:id");
HTTP Request
DELETE https://api.devici.com/api/v1/mitigations/:id
Responds with 200 OK and an empty body on success. Soft-deletes the mitigation.
Comments
Get All Comments
To get all Comments use this code:
axios.get("/comments");
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{comment_id}}",
"text": "This is first comment",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"is_edited": false,
"threat": {
"id": "{{threat_id}}"
},
"user": {
"id": "{{owner_id}}",
"avatar_uploaded_at": "2024-05-17T16:54:05.143Z"
}
},
{
"id": "{{comment_id}}",
"text": "This is second comment",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"is_edited": false,
"threat": {
"id": "{{threat_id}}"
},
"user": {
"id": "{{owner_id}}",
"avatar_uploaded_at": "2024-05-17T16:54:05.143Z"
}
}
],
"count": 2
}
This endpoint retrieves all comments.
HTTP Request
GET https://api.devici.com/api/v1/comments
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| sort | created_at | Order by created at |
| order | ASC | Sort by ASC |
Get a Specific Comment
To get specific comment use this code:
axios.get("/comments/:id");
The above command returns JSON structured like this:
{
"id": "{{comment_id}}",
"text": "This is second comment",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"is_edited": false,
"threat": {
"id": "{{threat_id}}"
},
"user": {
"id": "{{owner_id}}",
"avatar_uploaded_at": "2024-05-17T16:54:05.143Z"
}
}
This endpoint retrieves a specific comment.
HTTP Request
GET https://api.devici.com/api/v1/comments/:id
Get All Comments for specific Threat
To get all Comments for specific Threat use this code:
axios.get("/comments/for-threat/:threatId");
The above command returns JSON structured like this:
[
{
"id": "{{comment_id}}",
"text": "This is first comment",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"is_edited": false,
"user": {
"id": "{{owner_id}}",
"avatar_uploaded_at": "2024-05-17T16:54:05.143Z"
}
},
{
"id": "{{comment_id}}",
"text": "This is second comment",
"created_at": "2024-05-17T16:54:05.143Z",
"updated_at": "2024-05-17T16:54:05.143Z",
"is_edited": false,
"user": {
"id": "{{owner_id}}",
"avatar_uploaded_at": "2024-05-17T16:54:05.143Z"
}
}
]
This endpoint retrieves all comments for specific threat.
HTTP Request
GET https://api.devici.com/api/v1/comments/for-threat/:threatId
Create Comment
To create comment use this code:
axios.post("/comments", {
threatId: "{{threat_id}}",
text: "Comment text",
});
This endpoint create a specific comment.
HTTP Request
POST https://api.devici.com/api/v1/comments
Create Many Comments
To create many comments use this code:
axios.post("/comments/many", [
{
threatId: "{{threat_id}}",
userId: "{{user_id}}",
text: "Comment text"
},
{
threatId: "{{threat_id}}",
userId: "{{user_id}}",
text: "Comment text"
},
{
threatId: "{{threat_id}}",
userId: "{{user_id}}",
text: "Comment text"
}
]);
This endpoint create a many comments.
HTTP Request
POST https://api.devici.com/api/v1/comments/many
Update a Specific Comment
To update specific comment use this code:
axios.patch("/comments/:id", {
text: "Updated text",
});
This endpoint update a specific comment.
HTTP Request
PATCH https://api.devici.com/api/v1/comments/:id
Delete a Specific Comment
To delete specific comment use this code:
axios.delete("/comments/:id");
This endpoint deletes a specific comment.
HTTP Request
DELETE https://api.devici.com/api/v1/comments/:id
Codex Attributes
Manage the attributes that belong to your organisation's custom Codex. Attributes can optionally reference causing/neutralising threats, tags, aliases, and external resource links.
Field Constraints
| Field | Constraint |
|---|---|
title |
1–256 characters |
description |
1–1000 characters |
aliases |
Up to 10 entries, each 1–256 characters |
resources |
Up to 5 entries; per entry: title 1–256, url 1–500 |
causedThreatsIds / neutralizedThreatsIds |
Arrays of UUIDs (built-in threat IDs) |
tagsIds |
Array of tag UUIDs belonging to your organisation |
Get All Attributes
To get all attributes, use this code:
axios.get("/codex/attributes?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/attributes
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | created_at | Sort field (e.g. title, created_at, updated_at) |
| order | no | ASC | Sort order: ASC or DESC |
| text | no | Free-text search across title, description, tag titles, and alias titles | |
| tagIds | no | Filter by tag UUIDs (repeatable: tagIds=uuid1&tagIds=uuid2) |
|
| createdByIds | no | Filter by creator user UUIDs (repeatable) |
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{attribute_id}}",
"title": "Attribute 1",
"description": "Description 1",
"aliases": ["Alias 1", "Alias 2", "Alias 3"],
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii",
"color": "#FF0000"
}
],
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T08:54:45.294Z",
"updated_at": "2024-08-08T08:54:45.294Z"
}
],
"count": 1
}
Search Attributes
To search attributes, use this code:
axios.get("/codex/attributes/search?text={{some text}}");
HTTP Request
GET https://api.devici.com/api/v1/codex/attributes/search
Query Parameters
| Parameter | Required | Description |
|---|---|---|
| text | yes | Search query, 1–20 characters. Matches attribute title (case-insensitive). |
The above command returns JSON structured like this:
[
{
"id": "{{attribute_id}}",
"title": "Search Result Attribute",
"description": "Description for Search Result",
"aliases": ["Search Alias 1"],
"created_at": "2024-08-08T13:06:42.770Z"
}
]
Get a Specific Attribute
To get a specific attribute, use this code:
axios.get("/codex/attributes/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/attributes/:id
The above command returns JSON structured like this:
{
"id": "{{attribute_id}}",
"title": "Specific Attribute",
"description": "Description for Specific Attribute",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"aliases": ["Specific Alias 1", "Specific Alias 2"],
"causedThreatsIds": ["{{threat_id}}"],
"neutralizedThreatsIds": [],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii",
"color": "#FF0000"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-07-18T14:27:11.414Z",
"updated_at": "2024-07-18T14:27:11.414Z"
}
causedThreatsIds / neutralizedThreatsIds are the same UUIDs you send on write — the response uses matching field names so the shape can be round-tripped back into PUT /codex/attributes/:id without remapping.
Create a New Attribute
To create a new attribute, use this code:
axios.post("/codex/attributes", {
title: "New Attribute",
description: "Description for Attribute",
aliases: ["Alias 1", "Alias 2"],
resources: [
{
url: "https://example.com",
title: "Reference"
}
],
causedThreatsIds: ["{{threat_id}}"],
neutralizedThreatsIds: [],
tagsIds: ["{{tag_id}}"]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/attributes
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | Attribute title, 1–256 chars. Must be unique within the codex. |
| description | no | 1–1000 chars |
| aliases | no | Up to 10 alias strings, each 1–256 chars |
| resources | no | Up to 5 resource objects (url, title) |
| causedThreatsIds | no | UUIDs of built-in threats this attribute causes |
| neutralizedThreatsIds | no | UUIDs of built-in threats this attribute neutralises |
| tagsIds | no | UUIDs of tags belonging to your organisation |
The above command returns JSON structured like this:
{
"id": "{{attribute_id}}",
"title": "New Attribute",
"description": "Description for Attribute",
"resources": null,
"aliases": ["New Attribute", "Alias 1", "Alias 2"],
"causedThreatsIds": ["{{threat_id}}"],
"neutralizedThreatsIds": [],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:42:32.853Z",
"updated_at": "2024-08-08T14:42:32.853Z"
}
The attribute's own title is automatically added to its alias set.
Create Multiple Attributes
To create multiple attributes, use this code:
axios.post("/codex/attributes/many", {
attributes: [
{
title: "New Attribute 1",
description: "Description for Attribute 1",
aliases: ["Alias 1", "Alias 2"],
causedThreatsIds: ["{{threat_id}}"]
},
{
title: "New Attribute 2",
description: "Description for Attribute 2",
aliases: ["Alias 3"]
}
]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/attributes/many
Request Body
| Field | Required | Description |
|---|---|---|
| attributes | yes | Array of attribute objects. Max 20 per request. Each object follows the same schema as POST /codex/attributes. All titles within the array must be unique. |
The above command returns JSON structured like this:
[
{
"id": "{{attribute_id}}",
"title": "New Attribute 1",
"description": "Description for Attribute 1",
"resources": null,
"aliases": ["New Attribute 1", "Alias 1", "Alias 2"],
"causedThreatsIds": ["{{threat_id}}"],
"neutralizedThreatsIds": [],
"tags": [],
"created_at": "2024-08-08T13:06:42.770Z",
"updated_at": "2024-08-08T13:06:42.770Z"
},
{
"id": "{{attribute_id}}",
"title": "New Attribute 2",
"description": "Description for Attribute 2",
"resources": null,
"aliases": ["New Attribute 2", "Alias 3"],
"causedThreatsIds": [],
"neutralizedThreatsIds": [],
"tags": [],
"created_at": "2024-08-08T13:06:42.770Z",
"updated_at": "2024-08-08T13:06:42.770Z"
}
]
Update a Specific Attribute
To update a specific attribute, use this code:
axios.put("/codex/attributes/:id", {
title: "Updated Attribute",
description: "Updated Description",
aliases: ["Updated Alias 1"],
resources: [
{
url: "https://example.com",
title: "Updated Reference"
}
],
causedThreatsIds: ["{{threat_id}}"],
neutralizedThreatsIds: [],
tagsIds: ["{{tag_id}}"]
});
HTTP Request
PUT https://api.devici.com/api/v1/codex/attributes/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | 1–256 chars |
| aliases | yes | Full replacement. Send the complete list of aliases you want the attribute to have. The attribute's title is always added automatically. |
| description | no | 1–1000 chars |
| resources | no | Full replacement. Up to 5 entries. |
| causedThreatsIds | no | Full replacement of caused-threats mapping. |
| neutralizedThreatsIds | no | Full replacement of neutralised-threats mapping. |
| tagsIds | no | Full replacement of tags. |
The above command returns the full attribute — same shape as
GET /codex/attributes/:id:
{
"id": "{{attribute_id}}",
"title": "Updated Attribute",
"description": "Updated Description",
"resources": [
{
"url": "https://example.com",
"title": "Updated Reference"
}
],
"aliases": ["Updated Attribute", "Updated Alias 1"],
"causedThreatsIds": ["{{threat_id}}"],
"neutralizedThreatsIds": [],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-07-18T14:27:11.414Z",
"updated_at": "2024-07-18T15:12:08.041Z"
}
Delete a Specific Attribute
To delete a specific attribute, use this code:
axios.delete("/codex/attributes/:id");
HTTP Request
DELETE https://api.devici.com/api/v1/codex/attributes/:id
Delete Multiple Attributes
To delete multiple attributes, use this code:
axios.delete("/codex/attributes/many", {
data: {
ids: ["{{attribute_id}}"]
}
});
HTTP Request
DELETE https://api.devici.com/api/v1/codex/attributes/many
Request Body
| Field | Required | Description |
|---|---|---|
| ids | yes | Array of attribute UUIDs to delete |
Codex Mitigations
Manage mitigations that belong to your organisation's custom Codex. Mitigations describe how to address a threat and can be attached to threats via the threat attach-mitigations / detach-mitigations endpoints.
Field Constraints
| Field | Constraint |
|---|---|
title |
1–256 characters, unique within the codex |
definition |
1–1000 characters, required |
consideration |
1–1000 characters, optional |
explanation |
1–1000 characters, optional |
example |
1–1000 characters, optional |
question |
1–256 characters, optional |
resources |
Up to 5 entries; per entry: title 1–256, url 1–500 |
tagsIds |
UUIDs of tags belonging to your organisation |
Get All Codex Mitigations
To get all mitigations, use this code:
axios.get("/codex/mitigations?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/mitigations
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | created_at | Sort field |
| order | no | ASC | ASC or DESC |
| text | no | Free-text search across title, definition, and tag titles | |
| tagIds | no | Filter by tag UUIDs (repeatable) | |
| createdByIds | no | Filter by creator UUIDs (repeatable) |
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{mitigation_id}}",
"title": "Mitigation",
"definition": "Description Mitigation",
"tags": [],
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z"
}
],
"count": 1
}
Search Mitigations
To search mitigations, use this code:
axios.get("/codex/mitigations/search?text={{some text}}");
HTTP Request
GET https://api.devici.com/api/v1/codex/mitigations/search
Query Parameters
| Parameter | Required | Description |
|---|---|---|
| text | yes | Search query, 1–20 characters. Matches mitigation title. |
The above command returns JSON structured like this:
[
{
"id": "{{mitigation_id}}",
"title": "Mitigation3",
"definition": "Description Mitigation3",
"created_at": "2024-08-08T08:59:18.952Z"
}
]
Get a Specific Codex Mitigation
To get a specific mitigation, use this code:
axios.get("/codex/mitigations/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/mitigations/:id
The above command returns JSON structured like this:
{
"id": "{{mitigation_id}}",
"title": "Mitigation",
"definition": "Description Mitigation",
"consideration": "Consideration",
"explanation": "Explanation",
"example": "Example",
"question": "Question",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"tags": [],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z"
}
Create a New Mitigation
To create a new mitigation, use this code:
axios.post("/codex/mitigations", {
title: "New Mitigation",
definition: "Description for Mitigation",
example: "Example for Mitigation",
question: "Question for Mitigation",
explanation: "Explanation for Mitigation",
consideration: "Consideration for Mitigation",
resources: [
{
url: "https://example.com",
title: "Reference"
}
],
tagsIds: ["{{tag_id}}"]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/mitigations
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | 1–256 chars, unique within the codex |
| definition | yes | 1–1000 chars |
| consideration | no | 1–1000 chars |
| explanation | no | 1–1000 chars |
| example | no | 1–1000 chars |
| question | no | 1–256 chars |
| resources | no | Up to 5 resource objects (url, title) |
| tagsIds | no | UUIDs of tags |
The above command returns JSON structured like this:
{
"id": "{{mitigation_id}}",
"title": "New Mitigation",
"definition": "Description for Mitigation",
"consideration": "Consideration for Mitigation",
"explanation": "Explanation for Mitigation",
"example": "Example for Mitigation",
"question": "Question for Mitigation",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii",
"color": "#FF0000"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z"
}
Create Multiple Mitigations
To create multiple mitigations, use this code:
axios.post("/codex/mitigations/many", {
mitigations: [
{
title: "Mitigation1",
definition: "Description Mitigation1",
example: "Example1",
question: "Question1",
explanation: "Explanation1",
consideration: "Consideration1"
},
{
title: "Mitigation2",
definition: "Description Mitigation2"
}
]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/mitigations/many
Request Body
| Field | Required | Description |
|---|---|---|
| mitigations | yes | Array of mitigation objects. Max 20 per request. Each object follows the same schema as POST /codex/mitigations. All titles within the array must be unique. |
The above command returns JSON structured like this:
[
{
"id": "{{mitigation_id}}",
"title": "Mitigation1",
"definition": "Description Mitigation1",
"consideration": "Consideration1",
"explanation": "Explanation1",
"example": "Example1",
"question": "Question1",
"resources": null,
"tags": [],
"created_at": "2024-08-08T13:51:08.098Z",
"updated_at": "2024-08-08T13:51:08.098Z"
},
{
"id": "{{mitigation_id}}",
"title": "Mitigation2",
"definition": "Description Mitigation2",
"consideration": null,
"explanation": null,
"example": null,
"question": null,
"resources": null,
"tags": [],
"created_at": "2024-08-08T13:51:08.098Z",
"updated_at": "2024-08-08T13:51:08.098Z"
}
]
Update a Specific Codex Mitigation
To update a specific codex mitigation, use this code:
axios.put("/codex/mitigations/:id", {
title: "Mitigation",
definition: "Description Mitigation",
consideration: "Consideration",
explanation: "Explanation",
example: "Example",
question: "Question",
resources: [
{
url: "https://example.com",
title: "Reference"
}
],
tagsIds: ["{{tag_id}}"]
});
HTTP Request
PUT https://api.devici.com/api/v1/codex/mitigations/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | 1–256 chars |
| definition | yes | 1–1000 chars |
| consideration | no | 1–1000 chars |
| explanation | no | 1–1000 chars |
| example | no | 1–1000 chars |
| question | no | 1–256 chars |
| resources | no | Full replacement. Up to 5 entries. |
| tagsIds | no | Full replacement of tags |
The above command returns JSON structured like this:
{
"id": "{{mitigation_id}}",
"title": "Mitigation",
"definition": "Description Mitigation",
"consideration": "Consideration",
"explanation": "Explanation",
"example": "Example",
"question": "Question",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"tags": [],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T09:12:44.201Z"
}
Delete a Specific Codex Mitigation
To delete a specific codex mitigation, use this code:
axios.delete("/codex/mitigations/:id");
HTTP Request
DELETE https://api.devici.com/api/v1/codex/mitigations/:id
Delete Multiple Mitigations
To delete multiple mitigations, use this code:
axios.delete("/codex/mitigations/many", {
data: {
ids: ["{{mitigation_id}}"]
}
});
HTTP Request
DELETE https://api.devici.com/api/v1/codex/mitigations/many
Request Body
| Field | Required | Description |
|---|---|---|
| ids | yes | Array of mitigation UUIDs to delete |
Codex Threats
Manage threats that belong to your organisation's custom Codex. Threats can reference codex attributes (as causing/neutralising) and codex mitigations. Those relationships can be set either on the create/update call or via the dedicated attach/detach endpoints.
Field Constraints
| Field | Constraint |
|---|---|
title |
1–256 characters, unique within the codex |
description |
1–1200 characters |
priority |
One of critical, high, medium, low |
resources |
Up to 5 entries; per entry: title 1–256, url 1–500 |
causedByIds / neutralizedByIds |
UUIDs of codex attributes (max 50 each). Must not overlap. |
mitigationsIds |
UUIDs of codex mitigations (max 50) |
tagsIds |
UUIDs of tags belonging to your organisation |
Get All Codex Threats
To get all codex threats, use this code:
axios.get("/codex/threats?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/threats
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | created_at | Sort field |
| order | no | ASC | ASC or DESC |
| text | no | Free-text search across title, description, and tag titles (1–20 chars) | |
| priority | no | Filter by priority (repeatable: priority=high&priority=critical) |
|
| tagIds | no | Filter by tag UUIDs (repeatable) | |
| createdByIds | no | Filter by creator UUIDs (repeatable) |
The above command returns JSON structured like this:
{
"items": [
{
"id": "{{threat_id}}",
"title": "Threats1",
"description": "Description Threats1",
"priority": "low",
"tags": [],
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
],
"count": 1
}
Search Threats
To search threats, use this code:
axios.get("/codex/threats/search?text={{some text}}");
HTTP Request
GET https://api.devici.com/api/v1/codex/threats/search
Query Parameters
| Parameter | Required | Description |
|---|---|---|
| text | yes | Search query, 1–20 characters. Matches threat title. |
The above command returns JSON structured like this:
[
{
"id": "{{threat_id}}",
"title": "Threats1",
"description": "Description Threats1",
"priority": "low"
}
]
Get a Specific Codex Threat
To get a specific codex threat, use this code:
axios.get("/codex/threats/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/threats/:id
The above command returns JSON structured like this:
{
"id": "{{threat_id}}",
"title": "Threats",
"description": "Description Threats",
"priority": "low",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"caused_by": [
{
"id": "{{attribute_id}}",
"title": "Attribute"
}
],
"neutralized_by": [],
"mitigations": [
{
"id": "{{mitigation_id}}",
"title": "Mitigation"
}
],
"causedByIds": ["{{attribute_id}}"],
"neutralizedByIds": [],
"mitigationsIds": ["{{mitigation_id}}"],
"tags": [],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
Create a New Threat
To create a new threat, use this code:
axios.post("/codex/threats", {
title: "New Threat",
description: "Description for Threat",
priority: "low",
resources: [
{
url: "https://example.com",
title: "Reference"
}
],
causedByIds: ["{{attribute_id}}"],
neutralizedByIds: [],
mitigationsIds: ["{{mitigation_id}}"],
tagsIds: ["{{tag_id}}"]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | 1–256 chars, unique within the codex |
| description | yes | 1–1200 chars |
| priority | yes | critical, high, medium, or low |
| resources | no | Up to 5 resource objects (url, title) |
| causedByIds | no | UUIDs of codex attributes that cause this threat (max 50). Must not overlap with neutralizedByIds. |
| neutralizedByIds | no | UUIDs of codex attributes that neutralise this threat (max 50) |
| mitigationsIds | no | UUIDs of codex mitigations (max 50) |
| tagsIds | no | UUIDs of tags |
The above command returns JSON structured like this:
{
"id": "{{threat_id}}",
"title": "New Threat",
"description": "Description for Threat",
"priority": "low",
"resources": [
{
"url": "https://example.com",
"title": "Reference"
}
],
"caused_by": [
{
"id": "{{attribute_id}}",
"title": "Attribute"
}
],
"neutralized_by": [],
"mitigations": [
{
"id": "{{mitigation_id}}",
"title": "Mitigation"
}
],
"causedByIds": ["{{attribute_id}}"],
"neutralizedByIds": [],
"mitigationsIds": ["{{mitigation_id}}"],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii",
"color": "#FF0000"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
Create Multiple Threats
To create multiple threats, use this code:
axios.post("/codex/threats/many", {
threats: [
{
title: "Threats1",
description: "Description Threats1",
priority: "low",
causedByIds: ["{{attribute_id}}"],
mitigationsIds: ["{{mitigation_id}}"],
tagsIds: ["{{tag_id}}"]
},
{
title: "Threats2",
description: "Description Threats2",
priority: "medium"
}
]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats/many
Request Body
| Field | Required | Description |
|---|---|---|
| threats | yes | Array of threat objects. Max 20 per request. Each object follows the same schema as POST /codex/threats. All titles within the array must be unique. |
The above command returns JSON structured like this:
[
{
"id": "{{threat_id}}",
"title": "Threats1",
"description": "Description Threats1",
"priority": "low",
"resources": null,
"caused_by": [
{
"id": "{{attribute_id}}",
"title": "Attribute"
}
],
"neutralized_by": [],
"mitigations": [
{
"id": "{{mitigation_id}}",
"title": "Mitigation"
}
],
"causedByIds": ["{{attribute_id}}"],
"neutralizedByIds": [],
"mitigationsIds": ["{{mitigation_id}}"],
"tags": [
{
"id": "{{tag_id}}",
"title": "pii",
"color": "#FF0000"
}
],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
},
{
"id": "{{threat_id}}",
"title": "Threats2",
"description": "Description Threats2",
"priority": "medium",
"resources": null,
"caused_by": [],
"neutralized_by": [],
"mitigations": [],
"causedByIds": [],
"neutralizedByIds": [],
"mitigationsIds": [],
"tags": [],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
]
Update a Specific Codex Threat
To update a specific codex threat, use this code:
axios.put("/codex/threats/:id", {
title: "Updated Threat",
description: "Updated Description",
priority: "medium",
resources: [
{
url: "https://example.com",
title: "Updated Reference"
}
],
causedByIds: ["{{attribute_id}}"],
neutralizedByIds: [],
mitigationsIds: ["{{mitigation_id}}"],
tagsIds: []
});
HTTP Request
PUT https://api.devici.com/api/v1/codex/threats/:id
Request Body
| Field | Required | Description |
|---|---|---|
| title | yes | 1–256 chars |
| description | yes | 1–1200 chars |
| priority | yes | critical, high, medium, or low |
| resources | no | Full replacement. Up to 5 entries. |
| causedByIds | no | Full replacement of caused-by attribute mapping |
| neutralizedByIds | no | Full replacement of neutralised-by attribute mapping |
| mitigationsIds | no | Full replacement of mitigations mapping |
| tagsIds | no | Full replacement of tags |
The above command returns JSON structured like this:
{
"id": "{{threat_id}}",
"title": "Updated Threat",
"description": "Updated Description",
"priority": "medium",
"resources": [
{
"url": "https://example.com",
"title": "Updated Reference"
}
],
"caused_by": [
{
"id": "{{attribute_id}}",
"title": "Attribute"
}
],
"neutralized_by": [],
"mitigations": [
{
"id": "{{mitigation_id}}",
"title": "Mitigation"
}
],
"causedByIds": ["{{attribute_id}}"],
"neutralizedByIds": [],
"mitigationsIds": ["{{mitigation_id}}"],
"tags": [],
"created_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"last_modified_by": {
"id": "{{user_id}}",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com"
},
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:25:03.112Z"
}
Attach Attributes to a Threat
Adds attributes to a threat's caused_by or neutralized_by collection. Unlike PUT /:id, this is additive — use it when you want to grow the mapping without replacing it wholesale.
To attach attributes to a threat, use this code:
axios.post("/codex/threats/attach-attributes", {
threatId: "{{threat_id}}",
attributesIds: ["{{attribute_id}}"],
type: "caused_by"
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats/attach-attributes
Request Body
| Field | Required | Description |
|---|---|---|
| threatId | yes | UUID of the threat |
| attributesIds | yes | UUIDs of codex attributes (max 10) |
| type | yes | caused_by or neutralized |
Returns the full threat (same shape as GET /codex/threats/:id).
Detach Attributes from a Threat
To detach attributes from a threat, use this code:
axios.post("/codex/threats/detach-attributes", {
threatId: "{{threat_id}}",
attributesIds: ["{{attribute_id}}"],
type: "caused_by"
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats/detach-attributes
Request Body
Same as attach-attributes above. Returns the full threat.
Attach Mitigations to a Threat
To attach mitigations to a threat, use this code:
axios.post("/codex/threats/attach-mitigations", {
threatId: "{{threat_id}}",
mitigationsIds: ["{{mitigation_id}}"]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats/attach-mitigations
Request Body
| Field | Required | Description |
|---|---|---|
| threatId | yes | UUID of the threat |
| mitigationsIds | yes | UUIDs of codex mitigations (max 10) |
Returns the full threat.
Detach Mitigations from a Threat
To detach mitigations from a threat, use this code:
axios.post("/codex/threats/detach-mitigations", {
threatId: "{{threat_id}}",
mitigationsIds: ["{{mitigation_id}}"]
});
HTTP Request
POST https://api.devici.com/api/v1/codex/threats/detach-mitigations
Request Body
Same as attach-mitigations above. Returns the full threat.
Delete a Specific Codex Threat
To delete a specific codex threat, use this code:
axios.delete("/codex/threats/:id");
HTTP Request
DELETE https://api.devici.com/api/v1/codex/threats/:id
Delete Multiple Threats
To delete multiple threats, use this code:
axios.delete("/codex/threats/many", {
data: {
ids: ["{{threat_id}}"]
}
});
HTTP Request
DELETE https://api.devici.com/api/v1/codex/threats/many
Request Body
| Field | Required | Description |
|---|---|---|
| ids | yes | Array of threat UUIDs to delete |
Devici Codex Attributes
The Devici Codex provides read-only access to Devici's built-in security attributes. These are curated attributes maintained by Devici and cannot be modified via the API.
Get All Devici Codex Attributes
To get all Devici Codex attributes, use this code:
axios.get("/codex/built-in/attributes?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/attributes
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | title | Sort field: title, description, type, created_at, updated_at |
| order | no | ASC | Sort order: ASC or DESC |
| text | no | Search by title or description (min 2 characters) | |
| detailed | no | false | Include caused_threats and neutralized_threats |
| types | no | Filter by type: functional, data |
The above command returns JSON structured like this:
{
"items": [
{
"id": "9509597d-50d8-462e-864d-9a8825a79175",
"title": "3DES",
"description": "Triple DES -- an enhancement of DES...",
"type": "functional",
"aliases": ["3DES"],
"categories": [],
"created_at": "2023-10-28T16:51:20.523Z",
"updated_at": "2024-03-06T19:02:47.034Z"
}
],
"count": 1
}
With
detailed=true, each item also includes:
{
"id": "9509597d-50d8-462e-864d-9a8825a79175",
"title": "3DES",
"description": "Triple DES -- an enhancement of DES...",
"type": "functional",
"aliases": ["3DES"],
"categories": [],
"created_at": "2023-10-28T16:51:20.523Z",
"updated_at": "2024-03-06T19:02:47.034Z",
"assignable_to_components": ["process", "external_entity"],
"caused_threats": [
{
"id": "a1b2c3d4-...",
"title": "Weak Encryption",
"priority": "high"
}
],
"neutralized_threats": [
{
"id": "e5f6g7h8-...",
"title": "Brute Force Attack",
"priority": "medium"
}
]
}
Get a Specific Devici Codex Attribute
To get a specific Devici Codex attribute, use this code:
axios.get("/codex/built-in/attributes/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/attributes/:id
The above command returns JSON structured like this (always detailed):
{
"id": "9509597d-50d8-462e-864d-9a8825a79175",
"title": "3DES",
"description": "Triple DES -- an enhancement of DES...",
"type": "functional",
"aliases": ["3DES"],
"categories": [],
"created_at": "2023-10-28T16:51:20.523Z",
"updated_at": "2024-03-06T19:02:47.034Z",
"assignable_to_components": ["process", "external_entity"],
"caused_threats": [
{
"id": "a1b2c3d4-...",
"title": "Weak Encryption",
"priority": "high"
}
],
"neutralized_threats": [
{
"id": "e5f6g7h8-...",
"title": "Brute Force Attack",
"priority": "medium"
}
]
}
Devici Codex Threats
The Devici Codex provides read-only access to Devici's built-in security threats. These are curated threats maintained by Devici and cannot be modified via the API.
Get All Devici Codex Threats
To get all Devici Codex threats, use this code:
axios.get("/codex/built-in/threats?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/threats
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | title | Sort field: title, description, priority, created_at, updated_at |
| order | no | ASC | Sort order: ASC or DESC |
| text | no | Search by title or description (min 2 characters) | |
| detailed | no | false | Include source, caused_by, neutralized_by, and mitigations |
| priority | no | Filter by priority: low, medium, high, critical (repeatable) |
|
| methodologyIds | no | Filter by methodology UUIDs (repeatable). See /codex/built-in/threats/catalog for the available methodologies. |
|
| categoryIds | no | Filter by category UUIDs (repeatable). When both methodologyIds and categoryIds are provided, categoryIds wins (categories already imply their methodology). |
The above command returns JSON structured like this:
{
"items": [
{
"id": "f1a2b3c4-...",
"title": "SQL Injection",
"description": "Injection of malicious SQL queries...",
"priority": "high",
"resources": [
{
"title": "OWASP SQL Injection",
"url": "https://owasp.org/www-community/attacks/SQL_Injection"
}
],
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
],
"count": 1
}
With
detailed=true, each item also includessource,caused_by,neutralized_by, andmitigations:
{
"id": "f1a2b3c4-...",
"title": "SQL Injection",
"description": "Injection of malicious SQL queries...",
"priority": "high",
"resources": [
{
"title": "OWASP SQL Injection",
"url": "https://owasp.org/www-community/attacks/SQL_Injection"
}
],
"source": {
"methodology": {
"id": "m1a2b3c4-...",
"title": "STRIDE"
},
"category": {
"id": "c1a2b3c4-...",
"title": "Tampering"
}
},
"caused_by": [
{
"id": "a1b2c3d4-...",
"title": "Unsanitized Input",
"type": "functional"
}
],
"neutralized_by": [
{
"id": "a5b6c7d8-...",
"title": "Input Validation",
"type": "functional"
}
],
"mitigations": [
{
"id": "b1c2d3e4-...",
"title": "Parameterized Queries",
"definition": "Separates SQL logic from data input"
}
],
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
source may be null when a threat is not associated with any methodology.
Get Threats Catalog
Returns the methodologies and their categories that the built-in threats are organised by. Use the returned UUIDs to filter the threats list via methodologyIds / categoryIds.
To get the threats catalog, use this code:
axios.get("/codex/built-in/threats/catalog");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/threats/catalog
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | no | 0 | Page number (0-based) |
| limit | no | 20 | Items per page (max 100) |
| all | no | false | When true, returns all methodologies (paging is ignored) |
The above command returns JSON structured like this:
{
"items": [
{
"id": "m1a2b3c4-...",
"title": "STRIDE",
"description": "Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege",
"categories": [
{
"id": "c1a2b3c4-...",
"title": "Tampering",
"description": "Modifying data or code without authorisation"
},
{
"id": "c2b3c4d5-...",
"title": "Spoofing",
"description": "Impersonating another user or process"
}
]
}
],
"count": 1
}
Get a Specific Devici Codex Threat
To get a specific Devici Codex threat, use this code:
axios.get("/codex/built-in/threats/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/threats/:id
The above command returns JSON structured like this (always detailed):
{
"id": "f1a2b3c4-...",
"title": "SQL Injection",
"description": "Injection of malicious SQL queries...",
"priority": "high",
"resources": [
{
"title": "OWASP SQL Injection",
"url": "https://owasp.org/www-community/attacks/SQL_Injection"
}
],
"source": {
"methodology": {
"id": "m1a2b3c4-...",
"title": "STRIDE"
},
"category": {
"id": "c1a2b3c4-...",
"title": "Tampering"
}
},
"caused_by": [
{
"id": "a1b2c3d4-...",
"title": "Unsanitized Input",
"type": "functional"
}
],
"neutralized_by": [
{
"id": "a5b6c7d8-...",
"title": "Input Validation",
"type": "functional"
}
],
"mitigations": [
{
"id": "b1c2d3e4-...",
"title": "Parameterized Queries",
"definition": "Separates SQL logic from data input"
}
],
"created_at": "2024-08-08T14:19:42.080Z",
"updated_at": "2024-08-08T14:19:42.080Z"
}
Devici Codex Mitigations
The Devici Codex provides read-only access to Devici's built-in security mitigations. These are curated mitigations maintained by Devici and cannot be modified via the API.
Get All Devici Codex Mitigations
To get all Devici Codex mitigations, use this code:
axios.get("/codex/built-in/mitigations?page=0&limit=20");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/mitigations
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | yes | Page number (0-based) | |
| limit | yes | Items per page (max 100) | |
| sort | no | title | Sort field: title, definition, created_at, updated_at |
| order | no | ASC | Sort order: ASC or DESC |
| text | no | Search by title or definition (min 2 characters) | |
| detailed | no | false | Include source, explanation, consideration, example, and question |
| categoryIds | no | Filter by category UUIDs (repeatable). See /codex/built-in/mitigations/catalog for the available categories. |
The above command returns JSON structured like this:
{
"items": [
{
"id": "b1c2d3e4-...",
"title": "Parameterized Queries",
"definition": "Separates SQL logic from data input",
"resources": [
{
"title": "OWASP Guide",
"url": "https://owasp.org/www-community/..."
}
],
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z"
}
],
"count": 1
}
With
detailed=true, each item also includessource,explanation,consideration,example, andquestion:
{
"id": "b1c2d3e4-...",
"title": "Parameterized Queries",
"definition": "Separates SQL logic from data input",
"resources": [
{
"title": "OWASP Guide",
"url": "https://owasp.org/www-community/..."
}
],
"source": {
"category": {
"id": "c5a6b7c8-...",
"title": "Input Validation"
}
},
"explanation": "Prevents attackers from injecting malicious SQL by binding parameters.",
"consideration": "Requires developer adoption. May require refactoring legacy code.",
"example": "Using prepared statements in Java",
"question": "Where is user input used in queries?",
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z"
}
source may be null when a mitigation is not associated with any category.
Get Mitigations Catalog
Returns the categories that the built-in mitigations are organised by. Use the returned UUIDs to filter the mitigations list via categoryIds.
To get the mitigations catalog, use this code:
axios.get("/codex/built-in/mitigations/catalog");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/mitigations/catalog
Query Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
| page | no | 0 | Page number (0-based) |
| limit | no | 20 | Items per page (max 100) |
| all | no | false | When true, returns every category (paging is ignored) |
The above command returns JSON structured like this:
{
"items": [
{
"id": "c5a6b7c8-...",
"title": "Input Validation",
"description": "Validating and sanitising user-supplied data."
},
{
"id": "c6b7c8d9-...",
"title": "Access Control",
"description": "Restricting privileges to the minimum required."
}
],
"count": 2
}
Get a Specific Devici Codex Mitigation
To get a specific Devici Codex mitigation, use this code:
axios.get("/codex/built-in/mitigations/:id");
HTTP Request
GET https://api.devici.com/api/v1/codex/built-in/mitigations/:id
The above command returns JSON structured like this (always detailed):
{
"id": "b1c2d3e4-...",
"title": "Parameterized Queries",
"definition": "Separates SQL logic from data input",
"source": {
"category": {
"id": "c5a6b7c8-...",
"title": "Input Validation"
}
},
"resources": [
{
"title": "OWASP Guide",
"url": "https://owasp.org/www-community/..."
}
],
"created_at": "2024-08-08T08:59:18.952Z",
"updated_at": "2024-08-08T08:59:18.952Z",
"explanation": "Prevents attackers from injecting malicious SQL by binding parameters.",
"consideration": "Requires developer adoption. May require refactoring legacy code.",
"example": "Using prepared statements in Java",
"question": "Where is user input used in queries?"
}
Audit Logs
Get Audit Logs Actions
To get Audit Logs Actions use this code:
axios.get("/audit-log/types");
[
"collection-created",
"collection-deleted",
"collection-owner-changed",
"threat-model-created",
"threat-model-deleted",
"canvas-created",
"canvas-deleted",
"components-deleted",
"customer-settings-changed",
"user-deleted",
"user-role-changed",
"user-invited",
"user-toggled-mfa",
"saml-settings-created",
"saml-settings-changed",
"saml-settings-deleted",
"mfa-enabled",
"mfa-disabled",
"session-duration-changed",
"signed-up",
"signed-in",
"signed-out",
"password-changed",
"password-forgot",
"app-integration-created",
"app-integration-updated",
"app-integration-deleted",
"app-integration-test",
"api-token-created",
"api-token-updated",
"api-token-scopes-updated",
"api-token-ip-whitelist-updated",
"api-token-transferred",
"api-token-credentials-regenerated",
"api-token-disabled",
"api-token-deleted"
]
This endpoint retrieves all Action for filtering Audit Logs.
HTTP Request
GET https://api.devici.com/api/v1/audit-log/types
Get All Audit Logs
To get all Audit Logs use this code:
axios.get("/audit-log/?limit=1&actions=api-token-regenerated");
{
"items": [
{
"logId": "{{canvas_id}}",
"action": "API token renenerate",
"userIp": "123.123.123.123",
"entityId": "{{entity_id}}}",
"timestamp": "2024-05-08T16:27:08.765Z",
"expiresAt": "17457498341",
"user": {
"id": "{{user_id}}",
"email": "johndoe@mail.com",
"first_name": "John",
"last_name": "Doe",
"role": "admin"
}
}
],
"nextKey": "{{next_key_id}}"
}
This endpoint retrieves all Audit Logs.
HTTP Request
GET https://api.devici.com/api/v1/audit-log/?limit=1&nextKey={{next_key_id}}&actions=api-token-regenerated
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 25 | Count of items per request |
| users | - | Filter by specific user(s) |
| actions | - | Filter by specific action(s) |
| start | 1 month before current date |
Filter by date (start date), format: yyyy-mm-dd |
| end | Current date |
Filter by date (end date), format: yyyy-mm-dd |
| nextKey | - | Use "nextKey" from previous response to get the next chunk of data |
Export on CSV
To export Audit Logs via CSV use this code:
axios.get("/audit-log/csv");
CSV file example:
Action,User,User Ip,Timestamp,Details
API token regenerate,John Doe,123.123.123.123,1/24/2025,-
Signed in,John Doe,123.123.123.123,1/24/2025,-
Threat Model created,John Doe,123.123.123.123,1/22/2025,Title: Draft threat model | Collection: New Collection for test syslog
Signed in,John Doe,123.123.123.123,1/22/2025,-
Collection deleted,John Doe,123.123.123.123,1/21/2025,Title: Edited Collection257384
Threat Model created,John Doe,123.123.123.123,1/20/2025,Title: brave's first threat model | Collection: Default_collection
Signed in,John Doe,123.123.123.1231,1/20/2025,-
Collection deleted,John Doe,123.123.123.123,1/17/2025,Title: Edited Collection244503
...
This endpoint retrieves all Action for filtering Audit Logs.
HTTP Request
GET https://api.devici.com/api/v1/audit-log/csv?actions=api-token-regenerated&start=2025-01-01&end=2025-02-01
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| users | - | Filter by specific user(s) |
| actions | - | Filter by specific action(s) |
| start | 1 month before current date |
Filter by date (start date), format: yyyy-mm-dd |
| end | Current date |
Filter by date (end date), format: yyyy-mm-dd |
Reports
Get Threat Models Reports
To get Threat Models Reports use this code:
axios.get("/reports/threat-models/?limit=1&page=0&start=01-01-2025&end=01-31-2025");
{
"items": [
{
"id": "{{threat_model_id}}",
"created_at": "2024-10-10T14:58:26.981Z",
"title": "Title",
"status": "Threats & Mitigations",
"priority": "high",
"owner": {
"first_name": "Jon",
"last_name": "Doe"
},
"canvasCount": 1,
"mitigatedThreats": 0,
"unmitigatedThreats": 4,
"canvases": [
{
"id": "{{canvas_id}}",
"title": "Canvas 1"
}
],
"collection": {
"id": "{{collection_id}}",
"title": "Collection"
}
}
],
"count": 1
}
This endpoint retrieves Threat Models report.
HTTP Request
GET https://api.devici.com/api/v1/reports/threat-models/?limit=1&page=0&start=01-01-2025&end=01-31-2025
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| start | - | The starting point or timestamp for the query range |
| end | - | The endpoint or timestamp for the query range |
| projectId | - | Filter by a specific collection |
| runningId | - | Filter by a specific running |
Get Threat Models Reports via PDF
To get Threat Models Reports via PDF use this code:
axios.get("/reports/threat-models-pdf?start=01-01-2025&end=01-31-2026");
A PDF file will be received.
This endpoint retrieves Threat Models report via PDF file.
HTTP Request
GET https://api.devici.com/api/v1/reports/threat-models-pdf?start=01-01-2025&end=01-31-2026
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| start | - | The starting point or timestamp for the query range |
| end | - | The endpoint or timestamp for the query range |
Get Threat Models Reports via CSV
To get Threat Models Reports via CSV use this code:
axios.get("/reports/threat-models-csv?start=01-01-2025&end=01-31-2026");
CSV file example:
Title,Collection,Priority,Status,Mitigated Threats,Unmitigated Threats,Responsible,Canvases,Created At
Edited Test Model244,Default_collection,high,Threats & Mitigations,0,4,John Doe,1,10/10/2024
Default_collection Draft threat model,Default_collection,medium,Representation,0,0,John Doe,1,10/14/2024
Draft threat model,Default_collection,medium,Threats & Mitigations,0,0,John Doe,1,10/14/2024
Draft threat model,Default_collection,medium,Threats & Mitigations,0,0,John Doe,1,10/14/2024
Single node,Default_collection,medium,Threats & Mitigations,0,0,John Doe,1,10/14/2024
Draft threat model,Default_collection,medium,Representation,0,0,John Doe,1,10/14/2024
Draft threat model,Default_collection,medium,Representation,0,0,John Doe,1,10/15/2024
Draft threat model,Default_collection,medium,Representation,0,0,John Doe,1,10/15/2024
This endpoint retrieves Threat Models report via CSV file.
HTTP Request
GET https://api.devici.com/api/v1/reports/threat-models-csv?start=01-01-2025&end=01-31-2026
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| start | - | The starting point or timestamp for the query range |
| end | - | The endpoint or timestamp for the query range |
Dashboard
Get Dashboard Charts Types
To get Dashboard charts types use this code:
axios.get("/dashboard/types");
[
"total-users",
"top-threats",
"top-attributes",
"top-mitigations",
"top-risk-threat-models",
"threat-models-by-project",
"threats-vs-mitigated-threats",
"threat-models-by-status-and-priority"
]
This endpoint retrieves Dashboard Charts Types.
HTTP Request
GET https://api.devici.com/api/v1/dashboard/types
Get Dashboard data by specific chart type
To get Dashboard data by specific chart type use this code:
axios.get("/dashboard/?limit=1&page=0&start=01-01-2025&end=01-31-2025&type=top-threats");
[
{
"name": "Denial of Service",
"count": "796"
},
{
"name": "Information Disclosure",
"count": "794"
},
{
"name": "Tampering",
"count": "790"
},
{
"name": "Repudiation",
"count": "523"
},
{
"name": "Spoofing",
"count": "488"
}
]
This endpoint retrieves Dashboard data by specific chart type.
HTTP Request
GET https://api.devici.com/api/v1/dashboard/?limit=1&page=0&start=01-01-2025&end=01-31-2025&type=top-threats
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
| type | - | Use one of the types from /dashboard/types |
| start | - | The starting point or timestamp for the query range |
| end | - | The endpoint or timestamp for the query range |
| projectId | - | Filter by a specific collection |
| runningId | - | Filter by a specific running |
Teams
Get Teams
To get a list of all teams use this code:
axios.get("/teams/?limit=20&page=0");
{
"items": [
{
"id": "{{team_id}}",
"title": "Alpha",
"users": ["{{user_id}}"],
"created_at": "2025-02-10T15:01:41.411Z",
"collections": ["{{collection_id}}", "{{collection_id}}"]
}
],
"count": 1
}
Use this endpoint to retrieve a list of all teams.
HTTP Request
GET https://api.devici.com/api/v1/teams/?limit=20&page=0
Query Parameters
| Parameter | Default | Description |
|---|---|---|
| limit | 20 | Count of items per request |
| page | 1 | Page |
Get a Specific Team
To get specific team by id use this code:
axios.get("/teams/:id");
The above command returns JSON structured like this:
{
"id": "{{team_id}}",
"title": "Alpha",
"users": [
{
"id": "{{user_id}}",
"email": "{{user_email}}",
"first_name": "First",
"last_name": "Last",
"role": "user"
}
],
"collections": [
{
"id": "{{collection_id}}",
"title": "Collection title",
"permission": "write"
}
]
}
Use this endpoint to retrieve details of a specific team by its ID.
HTTP Request
GET https://api.devici.com/api/v1/teams/:id
Create Team
To create a new team use this code:
axios.post("/teams", {
payload: [
{
title: "Team 11111",
usersIds: ["{{user_id}}"],
collectionsPermissions: [{
collectionId: "{{collection_id}}",
permission: "read"
}]
},
{
title: "Team 22222",
usersIds: ["{{user_id}}"],
collectionsPermissions: [{
collectionId: "{{collection_id}}",
permission: "write"
}]
}
]
});
Use this endpoint to create a new team.
permission field must be one of read | write | manage
HTTP Request
POST https://api.devici.com/api/v1/teams
Update Teams
To update multiple teams use this code:
axios.put("/teams", {
payload: [
{
id: "{{team_id}}",
title: "Team updated title",
usersIds: ["{{user_id}}"],
collectionsPermissions: [{
collectionId: "{{collection_id}}",
permission: "read"
}]
}
]
});
Use this endpoint to update multiple teams in one request.
HTTP Request
PUT https://api.devici.com/api/v1/teams
Delete Specific Team
To delete specific team by id use this code:
axios.delete("/teams/:id");
Use this endpoint to delete a specific team by its ID.
HTTP Request
DELETE https://api.devici.com/api/v1/teams/:id
Errors
The Devici API uses the following error codes:
| Error Code | Meaning |
|---|---|
| 400 | Bad Request -- Your request is invalid. |
| 401 | Unauthorized -- Your API key is wrong. |
| 403 | Forbidden -- The entity requested is hidden for administrators only. |
| 404 | Not Found -- The specified entity could not be found. |
| 405 | Method Not Allowed -- You tried to access a entity with an invalid method. |
| 406 | Not Acceptable -- You requested a format that isn't json. |
| 410 | Gone -- The entity requested has been removed from our servers. |
| 418 | I'm a teapot. |
| 429 | Too Many Requests -- You're requesting too many entities! Slow down! |
| 500 | Internal Server Error -- We had a problem with our server. Try again later. |
| 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |