Introduction
The Cobalt API gives you REST access to Organizations, Assets, Pentests, Findings, and Events.
API Versions
EU Data Center
Introduction
If you’re using our EU Data center (app.eu.cobalt.io) and need to call our API, be aware that the base URL for API calls will differ from the examples in our documentation, which use the US version.
Procedure
- Identify the base URL: The base URL for customers using our EU Data center is
https://api.eu.cobalt.io
. This is the URL you should use when making API calls. - Replace the base URL in examples: All examples provided in our documentation use the US version of the base
URL (
https://api.us.cobalt.io
). When following these examples, you will need to replace the US base URL with the EU base URL. - For example, if an API call in the documentation is shown as:
https://api.us.cobalt.io/example-endpoint
You should replace it with:
https://api.eu.cobalt.io/example-endpoint
By following the steps outlined above, you can ensure that your API calls correctly target our EU Data center. If you encounter any issues or need further assistance, please don’t hesitate to contact us: integrations@cobalt.io.
Authentication
Cobalt uses API tokens to allow access to various endpoints. You can create a new Cobalt API token from within your Cobalt profile.
Cobalt expects the API token to be included in all API requests to the server in a header that looks like the following:
Authorization: Bearer YOUR-PERSONAL-API-TOKEN
Most API calls are scoped to a specific organization, with the X-Org-Token
header. We include that header, as needed,
in our API calls.
To see which organizations you belong to:
- Send a GET request to the
/orgs
endpoint. - Copy the
token
attribute associated with your target organization from response. - Include it as a header (
X-Org-Token
) to your requests when required.
Organizations
Get All Organizations
curl -X GET "https://api.us.cobalt.io/orgs" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "or_Uevoq7MyoYsPT9NPc3conL",
"name": "Acme Corp.",
"token": "e9d6da*****************************0e8ad"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
},
{
"resource": {
"id": "or_SnUYXDBYd2qbaDSuNRNa5q",
"name": "Lorem Corp.",
"token": "f1d6da*****************************0e8ad"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/orgs?cursor=a1b2c3d4",
"prev_page": "/orgs?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of organizations, or orgs, that you belong to. Save the token
field to be used in
your X-Org-Token
header in subsequent calls in querying for assets, findings, pentests and events that belong to that
organization.
HTTP Request
GET https://api.us.cobalt.io/orgs
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/orgs?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of organizations. Example: https://api.us.cobalt.io/orgs?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the organization. Starts with or_ |
name | The name of the organization |
token | The organization token you’ll need in subsequent calls |
links.ui.url | A link to redirect an authorized user to this organization in the Cobalt web application |
Assets
Get All Assets
curl -X GET "https://api.us.cobalt.io/assets" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "as_GZgcehapJUNh6mjNuqsE4T",
"title": "Acme Corp. HR System",
"description": "HR system of the Acme Corp. holding sensitive employee data",
"asset_type": "web",
"logo": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/cat.jpeg?something=1",
"technology_stack": [
{
"title": "React 18.0.0"
}
],
"attachments": [
{
"id": "at_LA5GcEL4HRitFGCHREqmzL",
"file_name": "rainbow.jpeg",
"download_url": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/rainbow.jpeg?something=1"
}
],
"tags": [
{
"name": "tag1"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/assets?cursor=a1b2c3d4",
"prev_page": "/assets?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of assets that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/assets
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/assets?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of assets. Example: https://api.us.cobalt.io/assets?limit=5 |
asset_type | N/A | If specified, returns assets that match asset_type . See Response Fields below for example asset_type values. Example: https://api.us.cobalt.io/assets?asset_type=web . Returns an empty list if no assets match the asset_type filter. |
tags_contains_all[] | N/A | If specified, returns assets that contain all matching tags . This query parameter can be specified multiple times. Returns an empty list if no matches are found. Example: https://api.us.cobalt.io/assets?tags_contains_all[]=third party&tags_contains_all[]=some-tag-id |
sort | N/A | If specified, returns assets sorted by one of the chosen parameters: asset_type . When defined, records are returned in ascending order by the sort parameter. To return in descending order, use a - before the sort parameter. Example: https://api.us.cobalt.io/assets?sort=-asset_type . |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the asset. Starts with as_ |
title | The title of the asset; set by user creating the asset |
description | A description of the asset; set by user creating the asset |
asset_type | An asset type, such as; api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , other |
logo | A link pointing the location of the uploaded asset logo |
technology_stack | A list of technology stacks. Each element contains the title of the technology. Example: React 18.0.0. |
attachments | A list of asset attachments. Attachment download URLs are pre-authorized and will expire after 10 minutes. |
tags | A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] |
links.ui.url | A link to redirect an authorized user to this asset in the Cobalt web application |
Get an Asset
curl -X GET "https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": {
"resource": {
"id": "as_GZgcehapJUNh6mjNuqsE4T",
"title": "Acme Corp. HR System",
"description": "HR system of the Acme Corp. holding sensitive employee data",
"asset_type": "web",
"logo": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/cat.jpeg?something=1",
"technology_stack": [
{
"title": "React 18.0.0"
}
],
"attachments": [
{
"id": "at_LA5GcEL4HRitFGCHREqmzL",
"file_name": "rainbow.jpeg",
"download_url": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/rainbow.jpeg?something=1"
}
],
"tags": [
{
"name": "tag1"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
}
This endpoint retrieves a specific asset belonging to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER
Response Fields
Field | Description |
---|---|
id | A unique ID representing the asset. Starts with as_ |
title | The title of the asset; set by user creating the asset |
description | A description of the asset; set by user creating the asset |
asset_type | An asset type, such as; api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , other |
logo | A link pointing the location of the uploaded asset logo |
technology_stack | A list of technology stacks. Each element contains the title of the technology. Example: React 18.0.0. |
attachments | A list of asset attachments (including the logo). Attachment download URLs are pre-authorized and will expire after 10 minutes. |
tags | A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] |
links.ui.url | A link to redirect an authorized user to this asset in the Cobalt web application |
Create an Asset
curl -X POST "https://api.us.cobalt.io/assets" \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN' \
--data '{
"title": "Test Asset",
"description": "Lorem ipsum",
"asset_type": "web",
"tags": []
}'
The above command returns the created asset and a
201
response code when successful. There will be aLocation
header pointing at the newly created asset.
{
"data": {
"resource": {
"id": "as_REXzZ1jXCxEvVvCx3MRMHN",
"title": "Test Asset",
"description": "Lorem ipsum",
"asset_type": "web",
"logo": null,
"technology_stack": [],
"attachments": [],
"tags": []
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoiQVNTRVQiLCJvcmdTbHVnIjoiZ2t1aG5zLXRlc3Qtb3JnIiwicGVudGVzdFRhZyI6IiIsImZpbmRpbmdJZCI6IiIsImFzc2V0VGFnIjoiYXNfR2ZqODZqTSJ9"
}
}
}
}
This endpoint creates a new asset belonging to the organization specified in the X-Org-Token
header.
HTTP Request
POST https://api.us.cobalt.io/assets
Body
Field | Description |
---|---|
title | The title of the asset; set by user creating the asset |
description | Optional; A description of the asset; set by user creating the asset |
asset_type | api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , or other |
tags | Optional; A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] . Defaults to empty list if not provided |
Response
You get a 201
response code for a successful request. The Location
response header contains the URL of the new
asset within the Cobalt API.
Field | Description |
---|---|
id | A unique ID representing the asset. Starts with as_ |
title | The title of the asset; set by user creating the asset |
description | A description of the asset; set by user creating the asset |
asset_type | An asset type, such as; api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , other |
logo | A link pointing the location of the uploaded asset logo |
technology_stack | A list of technology stacks. Each element contains the title of the technology. Example: React 18.0.0. |
attachments | A list of asset attachments (including the logo). Attachment download URLs are pre-authorized and will expire after 10 minutes. |
tags | A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] |
links.ui.url | A link to redirect an authorized user to this asset in the Cobalt web application |
Update an Asset
curl -X PUT 'https://api.us.cobalt.io/assets/AN-ASSET-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN' \
--data '{
"title": "Updated title",
"description": "Updated description",
"asset_type": "web",
"tags": []
}'
The above command returns the updated asset and a
200
response code when successful.
{
"data": {
"resource": {
"id": "as_REXzZ1jXCxEvVvCx3MRMHN",
"title": "Updated title",
"description": "Updated description",
"asset_type": "web",
"logo": null,
"technology_stack": [],
"attachments": [],
"tags": []
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoiQVNTRVQiLCJvcmdTbHVnIjoiZ2t1aG5zLXRlc3Qtb3JnIiwicGVudGVzdFRhZyI6IiIsImZpbmRpbmdJZCI6IiIsImFzc2V0VGFnIjoiYXNfR2ZqODZqTSJ9"
}
}
}
}
This endpoint updates an asset belonging to the organization specified in the X-Org-Token
header.
HTTP Request
PUT https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER
Body
Field | Description |
---|---|
title | The title of the asset; set by user creating the asset |
description | Optional; A description of the asset; set by user creating the asset |
asset_type | Options: api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , other |
tags | Optional; A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] . If tags field is not provided in the PUT request, no changes will occur to the asset tags. Any tags that already exist for the asset and are not provided in the PUT request will be deleted. Any tags that already exist for the asset and are provided in the PUT request will remain. Any tags that do not exist for the asset and are provided in the PUT request will be created. |
Response
On a successful update, a 200
response code will be returned.
Field | Description |
---|---|
id | A unique ID representing the asset. Starts with as_ |
title | The title of the asset; set by user creating the asset |
description | A description of the asset; set by user creating the asset |
asset_type | An asset type, such as; api , cloud_config , external_network , internal_network , mobile , web , web_plus_api , web_plus_mobile , wireless_network , iot , thick_client , physical , other |
logo | A link pointing the location of the uploaded asset logo |
technology_stack | A list of technology stacks. Each element contains the title of the technology. Example: React 18.0.0. |
attachments | A list of asset attachments (including the logo). Attachment download URLs are pre-authorized and will expire after 10 minutes. |
tags | A list of tags. A tag has a name attribute. Example: [{"name": "third-party system-id"}, {"name": "some-tag-id"}] |
links.ui.url | A link to redirect an authorized user to this asset in the Cobalt web application |
Delete an Asset
curl -X DELETE 'https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
The above command returns no data and a
204
response code when successful.
This endpoint deletes an asset belonging to the organization specified in the header. Note that deleting an asset will
also delete all associated tags
for the asset.
HTTP Request
DELETE https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER
Response
On successful deletion, a 204
response code will be returned.
Upload an Attachment
curl -X POST 'https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/attachments' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: multipart/form-data' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
--form 'attachment=@"/path/to/image.jpg"'
The above command returns no data and a
201
response code when successful. There will be aLocation
header pointing at the newly created attachment.
This endpoint uploads a new attachment for an asset belonging to the organization specified in the X-Org-Token
header.
HTTP Request
POST https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/attachments
Body
Form field | Description |
---|---|
attachment | The file to upload as an attachment. |
File Requirements
- The file must be smaller than 10 MB.
Response
On successful upload, a 201
response code will be returned. A response header, Location
, will contain the URL within
Cobalt API of the new attachment which you can use only to DELETE the attachment.
Delete an Attachment
curl -X DELETE 'https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/attachments/YOUR-ATTACHMENT-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
The above command returns no data and a
204
response code when successful.
This endpoint deletes an attachment from an asset belonging to the organization specified in the header.
HTTP Request
DELETE https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/attachments/YOUR-ATTACHMENT-IDENTIFIER
You can obtain this URL from the
Location
response header of the create attachment endpoint, or build it by getting the attachment identifier from the response data of theGET /assets
endpoint.
Response
On successful deletion, a 204
response code will be returned.
Upload a Logo
curl -X POST 'https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/logo' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: multipart/form-data' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-UPLOADS' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
--form 'attachment=@"/path/to/image.jpg"'
The above command returns no data and a
201
response code when successful.
This endpoint updates the logo for an asset belonging to the organization specified in the X-Org-Token
header. This
means the old logo is removed and replaced by the new logo.
HTTP Request
POST https://api.us.cobalt.io/assets/YOUR-ASSET-IDENTIFIER/logo
Body
Form field | Description |
---|---|
attachment | The file to upload as a logo. |
File Requirements
- The file must be an image, for example a
.png
or.jpg
. - The file must be smaller than 10 MB.
Response
On successful upload, a 201
response code will be returned.
Pentests
Get All Pentests
curl -X GET "https://api.us.cobalt.io/pentests" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "pt_JQJpAAMjyc8sVtXW2X2Aq5",
"title": "HR System Security Test 2022-Q4",
"objectives": "Coverage of OWASP top 10, ASVS and application logic.",
"state": "new",
"tag": "#PT5940",
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"testing_type": "agile",
"platform_tags": [
"rails",
"ruby",
"aws"
],
"methodology": "web",
"targets": [
"https://cobalt.io",
"192.168.1.1"
],
"start_date": "Dec 11 2019",
"end_date": "Dec 25 2019"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/pentests?cursor=a1b2c3d4",
"prev_page": "/pentests?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all pentests that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/pentests
URL Parameters
Parameter | Default | Description |
---|---|---|
asset | N/A | If specified, returns pentests scoped to this asset id. Example: https://api.us.cobalt.io/pentests?asset=as_GZgcehapJUNh6mjNuqsE4T or 404 if asset not found |
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/pentests?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of pentests. Example: https://api.us.cobalt.io/pentests?limit=5 |
sort | N/A | If specified, returns pentests sorted by one of the chosen properties: start_date , or end_date . When defined, pentests are sorted in ascending order by the sort property. To sort in descending order, use a - before the sort property. Example: https://api.us.cobalt.io/pentests?sort=-start_date . |
state | N/A | If specified, returns pentests that match state . See Response Fields below for example state values. Example: https://api.us.cobalt.io/pentests?state=new . Returns an empty list if no pentests match the state filter. |
testing_type | N/A | If specified, returns pentests that match testing_type . See Response Fields below for example testing_type values. Example: https://api.us.cobalt.io/pentests?testing_type=agile . Returns an empty list if no pentests match the testing_type filter. |
platform_tags_contains_all[] | N/A | If specified, returns pentests that contain all specified platform tags. This query parameter can be specified multiple times. Returns an empty list if no matches are found. Example: https://api.us.cobalt.io/pentests?platform_tags_contains_all[]=Kotlin&platform_tags_contains_all[]=AWS |
start_date_lte | N/A | If specified, returns pentests where the start_date is less than or equal to the input date. Input format: YYYY-MM-DD . Returns an empty list if no pentests match the filter. Example: https://api.us.cobalt.io/pentests?start_date_lte=2021-04-16 |
start_date_gte | N/A | If specified, returns pentests where the start_date is greater than or equal to the input date. Input format: YYYY-MM-DD . Returns an empty list if no pentests match the filter. Example: https://api.us.cobalt.io/pentests?start_date_gte=2021-04-16 |
end_date_lte | N/A | If specified, returns pentests where the end_date is less than or equal to the input date. Input format: YYYY-MM-DD . Returns an empty list if no pentests match the filter. Example: https://api.us.cobalt.io/pentests?end_date_lte=2021-04-16 |
end_date_gte | N/A | If specified, returns pentests where the end_date is greater than or equal to the input date. Input format: YYYY-MM-DD . Returns an empty list if no pentests match the filter. Example: https://api.us.cobalt.io/pentests?end_date_gte=2021-04-16 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest, for example, “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
testing_type | Pentest testing type, where can be: agile or comprehensive |
platform_tags | Tech stack of the target, for example, Java, Kotlin, Ruby, or AWS. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Get a Pentest
curl -X GET "https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": {
"resource": {
"id": "pt_JQJpAAMjyc8sVtXW2X2Aq5",
"title": "HR System Security Test 2022-Q4",
"objectives": "Coverage of OWASP top 10, ASVS and application logic.",
"state": "new",
"tag": "#PT5940",
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"testing_type": "agile",
"platform_tags": [
"rails",
"ruby",
"aws"
],
"methodology": "web",
"targets": [
"https://cobalt.io",
"192.168.1.1"
],
"start_date": "Dec 11 2019",
"end_date": "Dec 25 2019"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
}
This endpoint retrieves a specific pentest that belongs to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER-HERE
Response Fields
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest. for example “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
testing_type | Pentest testing type, where can be: agile or comprehensive |
platform_tags | Tech stack of the target. for example java, kotlin, ruby, aws, and so on. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Get a Pentest Report
curl -X GET "https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER/report" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": {
"resource": {
"id": "pt_JQJpAAMjyc8sVtXW2X2Aq5",
"title": "Pentest Title",
"state": "live",
"asset": {
"id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
},
"pentesters": [
{
"username": "user1",
"full_name": "User One"
},
{
"username": "user2",
"full_name": null
}
],
"report": {
"report_state": "final",
"title": "Pentest Title",
"starts_at": "2022-06-09",
"ends_at": "2022-06-13",
"executive_summary": "A pentest.",
"executive_analysis": "A pentest.",
"scope_of_work": "Everything.",
"summary_of_findings": "Some findings were found.",
"summary_of_recommendations": "Fix some things."
},
"findings": {
"severity": {
"informational": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j2",
},
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j3",
}
],
"low": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j4",
}
],
"medium": [],
"high": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j5",
}
],
"critical": []
},
"state": {
"new": [],
"triaging": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j5",
}
],
"invalid": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j3",
}
],
"duplicate": [],
"out_of_scope": [
{
"id": "vl_3sP2RCWWUajc3oRXmbQ4j2",
}
],
"need_fix": [],
"wont_fix": [],
"check_fix": [],
"valid_fix": []
}
},
"accepted_risks": [
{
"finding_id": "vl_VuLnerabiLityVuLnerab4",
"accepted_risk_reason": "internal_dependencies",
"state": "wont_fix"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
}
This endpoint retrieves the report for a specific pentest that belongs to the organization specified
in the X-Org-Token
header. The pentest must be in one of the states live
, remediation
, or
closed
.
Note that being able to view a pentest does not equal the ability to view a pentest report. Pentest report visibility depends on a number of factors:
- Whether or not the pentest report has been finalized.
- The role within the organization of the user who owns the API token.
If this endpoint returns a 404
but the underlying pentest is viewable, it’s likely a permissions
issue.
HTTP Request
GET https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER-HERE/report
Response Fields
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ . |
title | Optional; if present, the title of the returned pentest. |
state | One of live , remediation , or closed (reports can not be generated for pentests in other states). |
asset | Optional; if present, an object representing the asset associated with this pentest. |
asset.id | The unique ID representing the asset associated with this pentest. Starts with as_ . |
pentesters | Optional; if present, a list of the pentesters who performed this pentest. |
report | Optional; if present, a summary of this pentest’s findings and recommendations. |
findings | A list of the findings broken down by both severity and state . severity is not a required field so some findings may appear in the state section but not in severity . For a list of the valid severity keys, refer to the table in the Calculations section. For a list of valid state keys refer to the States section. |
accepted_risks | Optional; if present, a list of the accepted risk findings. For details, refer to the Accepted Risk Response Fields section below. |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application. |
Pentester Response Fields
Field | Description |
---|---|
username | The username of the pentester. |
full_name | The full name of the pentester; can be null . |
Report Response Fields
Field | Description |
---|---|
report_state | Optional; if present, one of new_state , draft , in_review , or final . |
title | Optional; if present, the title of the pentest. |
starts_at | Optional; if present, the date the pentest starts. |
ends_at | Optional; if present, the date the pentest ends. |
executive_summary | Optional; if present, a high-level overview of the pentest. |
executive_analysis | Optional; if present, a high-level analysis of the pentest. |
scope_of_work | Optional; if present, a description of the scope of work. |
summary_of_findings | Optional; if present, a high-level summary of the findings. |
summary_of_recommendations | Optional; if present, a high-level summary of the recommendations. |
Accepted Risk Response Fields
Field | Description |
---|---|
finding_id | A unique ID representing the finding. Starts with vl_ . |
accepted_risk_reason | One of low_severity , mitigated_by_waf , mitigated_by_other , no_longer_relevant , third_party_dependencies , internal_dependencies , intended_functionality , or other . |
state | The state of the finding. |
Duplicate a Pentest
curl -X POST "https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER/duplicate" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Content-Type: application/vnd.cobalt.v2+json" \
-H "Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns the new duplicate pentest and a
201
response code when successful. There will be aLocation
header pointing at the newly created pentest.
{
"data": {
"resource": {
"id": "pt_MsZGgJW55dJZxAs2AgXAF5",
"title": "[COPY] foobar - September 2023",
"objectives": "",
"state": "new",
"tag": "#PT83653",
"asset_id": "as_7PFxAamzsqDNixMcQoR723",
"platform_tags": [
"rails"
],
"methodology": "web",
"targets": [
"127.0.0.1"
],
"start_date": null,
"end_date": null,
"testing_type": "agile"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoiUEVOVEVTVCIsIm9yZ1NsdWciOiJna3VobnMtdGVzdC1vcmciLCJwZW50ZXN0VGFnIjoiY29weS1mb29iYXItc2VwdGVtYmVyLTIwMjMtcHQ4MzY1MyIsImZpbmRpbmdJZCI6IiIsImFzc2V0VGFnIjoiIn0="
}
}
}
}
This endpoint creates a duplicate pentest based on the identifier provided.
The pentest to be duplicated must exist and belong to the organization specified in the X-Org-Token
header.
Note there is no Request body required for this endpoint.
Note that you cannot duplicate a pentest that is in Draft state.
The new pentest will be in Draft state and will have the same brief as the pentest provided in the identifier.
HTTP Request
POST https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER-HERE/duplicate
Response
You get a 201
response code for a successful request. The Location
response header contains the URL of the new
pentest within the Cobalt API.
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest. for example “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
testing_type | Pentest testing type, where can be: agile or comprehensive |
platform_tags | Tech stack of the target. for example java, kotlin, ruby, aws, and so on. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Create a Pentest
curl -X POST "https://api.us.cobalt.io/pentests" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "Content-Type: application/vnd.cobalt.v2+json" \
-H "Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN" \
--data '{
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"title": "Pentest Title",
"description": "Pentest description.",
"technology_stack": "ruby,golang,rails,kotlin",
"instructions": "The pentest target is the v1 endpoints",
"additional_requests": "Do not test webhook endpoints.",
"test_credentials": "Account: foobar, password: foobar",
"test_credentials_option": "provided",
"targets": "1.1.1.1,https://google.com",
"testing_type": "comprehensive",
"scoping": {
"api": {
"num_of_endpoints": 1,
"num_of_roles": 1
}
}
}'
The above command returns the created pentest and a
201
response code when successful. There will be aLocation
header pointing at the newly created pentest.
{
"data": {
"resource": {
"id": "pt_G8kBTQUR3Nrmv3mWzYvzxT",
"title": "Pentest Title",
"objectives": "",
"state": "new",
"tag": "#PT83597",
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"platform_tags": [
"ruby",
"golang",
"rails",
"kotlin"
],
"methodology": "api",
"targets": [
"1.1.1.1",
"https://google.com"
],
"start_date": null,
"end_date": null,
"testing_type": "comprehensive"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoiUEVOVEVTVCIsIm9yZ1NsdWciOiJna3VobnMtdGVzdC1vcmciLCJwZW50ZXN0VGFnIjoicGVudGVzdC10aXRsZS1wdDgzNTk3IiwiZmluZGluZ0lkIjoiIiwiYXNzZXRUYWciOiIifQ=="
}
}
}
}
This endpoint creates a new pentest from the information provided. The pentest will belong to the
organization specified in the X-Org-Token
header. The pentest will be in the Draft state.
HTTP Request
POST https://api.us.cobalt.io/pentests
Body
Field | Description |
---|---|
asset_id | The ID of the asset being pentested; this asset must exist and belong to the organization specified in the X-Org-Token header. |
title | The title of the pentest. |
description | A description of the pentest. |
technology_stack | A comma separated list of technologies in use; for example, “Ruby, Go, C#” |
instructions | Optional; if present, instructions for the pentesters. |
additional_requests | Optional; if present, special requests or instructions for the pentesters. |
test_credentials | Optional; if present, credentials to be used by the pentesters. |
test_credentials_option | Optional; if present, additional information about the credentials. Must be one of the following: provided , distributed , not_required |
targets | Optional; if present, the URLs, endpoints, etc. being targeted by the pentest. A comma separated list; "1.1.1.1, https://cobalt.io" |
testing_type | Optional; If present, this will be the type of the pentest. Must be one of the following: agile , comprehensive . Default: comprehensive |
scoping | Optional; if present, information about the size of the pentest. For details, refer to the Scoping Body Fields section below. |
Scoping Body Fields
If scoping data is provided, it must match the type of the asset being pentested. For example, if
the asset being pentested is of type API
, the API-related scoping fields should be filled in.
Field | Description |
---|---|
api.num_of_endpoints | The number of API endpoints to be pentested. |
api.num_of_roles | The number of roles to be pentested per API endpoint. |
cloud_config.num_of_services | The number of cloud services to be pentested. |
cloud_config.num_of_accounts | The number of roles to be pentested per cloud service. |
mobile.num_of_views | The number of mobile app views to be pentested. |
mobile.num_of_roles | The number of roles to be pentested per mobile app view. |
mobile.num_of_operating_systems | The number of operating systems to be pentested per mobile app. |
network.num_of_ips | The number of network IP addresses to be pentested. |
web.num_of_pages | The number of web pages to be pentested. |
web.num_of_roles | The number of roles to be pentested per web page. |
Response
You get a 201
response code for a successful request. The Location
response header contains the URL of the new
pentest within the Cobalt API.
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest. for example “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
testing_type | Pentest testing type, where can be: agile or comprehensive |
platform_tags | Tech stack of the target. for example java, kotlin, ruby, aws, and so on. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Update a Pentest
curl -X PUT "https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "Content-Type: application/vnd.cobalt.v2+json" \
-H "Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN" \
--data '{
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"title": "Pentest Title",
"description": "Pentest description.",
"technology_stack": "ruby,golang,rails,kotlin",
"instructions": "The pentest target is the v1 endpoints",
"additional_requests": "Do not test webhook endpoints.",
"test_credentials": "Account: foobar, password: foobar",
"test_credentials_option": "provided",
"targets": "1.1.1.1,https://google.com",
"testing_type": "comprehensive",
"scoping": {
"api": {
"num_of_endpoints": 1,
"num_of_roles": 1
}
}
}'
The above command returns the updated pentest and a
200
response code when successful.
{
"data": {
"resource": {
"id": "pt_8T215LptHHFKhdRENjm8Ka",
"title": "Pentest Title",
"objectives": "Pentest description.",
"state": "new",
"tag": "#PT83652",
"asset_id": "as_4L4ZjKgfzP7VBwUmqCZmmL",
"platform_tags": [
"ruby",
"golang",
"rails",
"kotlin"
],
"methodology": "api",
"targets": [
"1.1.1.1",
"https://google.com"
],
"start_date": null,
"end_date": null,
"testing_type": "comprehensive"
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoiUEVOVEVTVCIsIm9yZ1NsdWciOiJna3VobnMtdGVzdC1vcmciLCJwZW50ZXN0VGFnIjoicGVudGVzdC10aXRsZS1wdDgzNjUyIiwiZmluZGluZ0lkIjoiIiwiYXNzZXRUYWciOiIifQ=="
}
}
}
}
This endpoint updates a pentest from the information provided.
HTTP Request
PUT https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER
Body
Field | Description |
---|---|
asset_id | The ID of the asset being pentested; this asset must exist and belong to the organization specified in the X-Org-Token header. |
title | The title of the pentest. |
description | A description of the pentest. |
technology_stack | A description of the technology stacks in use; for example, C# or Ruby on Rails. |
instructions | Optional; if present, instructions for the pentesters. |
additional_requests | Optional; if present, special requests or instructions for the pentesters. |
test_credentials | Optional; if present, credentials to be used by the pentesters. |
test_credentials_option | Optional; if present, additional information about the credentials. |
targets | Optional; if present, the URLs, endpoints, etc being targeted by the pentest. |
testing_type | Optional; If present, this will be the new type of the pentest. Must be one of the following: agile , comprehensive . |
scoping | Optional; if present, information about the size of the pentest. For details, refer to the Scoping Body Fields section below. |
Scoping Body Fields
If scoping data is provided, it must match the type of the asset being pentested. For example, if
the asset being pentested is of type API
, the API-related scoping fields should be filled in.
Field | Description |
---|---|
api.num_of_endpoints | The number of API endpoints to be pentested. |
api.num_of_roles | The number of roles to be pentested per API endpoint. |
cloud_config.num_of_services | The number of cloud services to be pentested. |
cloud_config.num_of_accounts | The number of roles to be pentested per cloud service. |
mobile.num_of_views | The number of mobile app views to be pentested. |
mobile.num_of_roles | The number of roles to be pentested per mobile app view. |
mobile.num_of_operating_systems | The number of operating systems to be pentested per mobile app. |
network.num_of_ips | The number of network IP addresses to be pentested. |
web.num_of_pages | The number of web pages to be pentested. |
web.num_of_roles | The number of roles to be pentested per web page. |
Response
On success, a 200
response code will be returned.
Field | Description |
---|---|
id | A unique ID representing the pentest. Starts with pt_ |
title | The title of the returned pentest. |
objectives | The objectives of the pentest. for example “Coverage of OWASP Top 10” |
asset_id | ID of the asset that the returned pentest belongs to |
testing_type | Pentest testing type, where can be: agile or comprehensive |
platform_tags | Tech stack of the target. for example java, kotlin, ruby, aws, and so on. |
methodology | Pentest methodology. Web, API, Web+API, Mobile, External Network and so on. |
targets | Targetted IP addresses, domains, services, and so on. |
start_date | The starting date of the pentest. Format: Dec 11 2019 |
end_date | The ending date of the pentest. Format: Dec 11 2019 |
state | new , in_review , planned , cancelled , live , remediation , or closed |
links.ui.url | A link to redirect an authorized user to this pentest in the Cobalt web application |
Delete a Pentest
curl -X DELETE 'https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
The above command returns no data and a
204
response code when successful.
This endpoint deletes a pentest belonging to the organization specified in the header. Note that you can only delete a pentest when it is in draft or review state.
HTTP Request
DELETE https://api.us.cobalt.io/pentests/YOUR-PENTEST-IDENTIFIER
Response
On successful deletion, a 204
response code will be returned.
Findings
States
The table below describes how the finding state values used by the API correspond to finding states shown in the user interface.
API Value | UI Name | Description |
---|---|---|
new | Draft | A pentester has created a draft finding but has not yet submitted it for triaging |
triaging | Triaging | The finding is being triaged |
need_fix | Pending Fix | The finding is valid and needs to be fixed |
check_fix | Ready for Retest | A fix is awaiting validation by a pentester |
valid_fix | Fixed | The finding was fixed and validated by a pentester |
wont_fix | Accepted Risk | The risk has been accepted. The finding will not be fixed |
carried_over | Carried Over | The finding was carried over from a previous pentest |
not_applicable | Not Applicable | The finding is not applicable |
invalid | Invalid | The finding is invalid |
duplicate | Invalid | The finding is invalid (deprecated state) |
stale | Invalid | The finding is invalid (deprecated state) |
out_of_scope | Invalid | The finding is invalid (deprecated state) |
Get All Findings
curl -X GET "https://api.us.cobalt.io/findings" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "vl_3sP2RCWWUajc3oRXmbQ4j9",
"tag": "#PT3334_37",
"title": "XSS vulnerability",
"description": "Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts...",
"type_category": "Cross-Site Scripting (XSS)",
"labels": [
{
"name": "Your label"
}
],
"impact": 5,
"likelihood": 4,
"severity": "high",
"affected_targets": [
"https://example.com",
"192.168.1.1"
],
"proof_of_concept": "Here you can see...",
"severity_justification": "The vulnerability can cause a lot of damage",
"suggested_fix": "Ensure this...",
"prerequisites": "Credentials are needed",
"pentest_id": "pt_PEtv4dqnwGV2efZhLw3BM5",
"http_request": "HTTP GET / ...",
"asset_id": "as_HcChCMueiPQQgvckmZtRSd",
"log": [
{
"action": "created",
"timestamp": "2021-04-01T15:13:24.322Z"
},
{
"action": "likelihood_changed",
"value": 4,
"timestamp": "2021-04-01T15:14:05.856Z"
},
{
"action": "impact_changed",
"value": 5,
"timestamp": "2021-04-01T15:14:05.856Z"
},
{
"action": "state_changed",
"value": "need_fix",
"timestamp": "2021-04-01T15:14:06.757Z"
},
{
"action": "state_changed",
"value": "check_fix",
"timestamp": "2021-04-01T15:14:57.845Z"
}
],
"state": "check_fix",
"created_at": "2022-09-26T18:35:18.759Z",
"updated_at": "2022-09-26T18:36:57.462Z",
"attachments": [
{
"id": "at_LA5GcEL4HRitFGCHREqmzL",
"file_name": "rainbow.jpeg",
"download_url": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/rainbow.jpeg?something=1"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
],
"pagination": {
"next_page": "/findings?cursor=a1b2c3d4",
"prev_page": "/findings?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all pentest findings that belong to the organization specified in the X-Org-Token
header, filterable by pentest_id
or asset_id
. The log
array presents a history of each finding and corresponding
timestamp.
Calculations
We follow the standard risk model described by OWASP, where:
Risk = Impact * Likelihood
Cobalt Risk Input Fields:
impact
: 1, 2, 3, 4, or 5likelihood
: 1, 2, 3, 4, or 5
Cobalt Risk Classification (severity
, a.k.a. criticality
):
Category | Score | Description |
---|---|---|
critical | 25 | Includes vulnerabilities that require immediate attention. |
high | 16-24 | Impacts the security of your application/platform/hardware, including supported systems. Includes high probability vulnerabilities with a high business impact. |
medium | 5-15 | Includes vulnerabilities that are: medium risk, medium impact; low risk, high impact; high risk, low impact. |
low | 2-4 | Specifies common vulnerabilities with minimal impact. |
informational | 1 | Notes vulnerabilities of minimal risk to your business. |
HTTP Request
GET https://api.us.cobalt.io/findings
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/findings?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of findings. Example: https://api.us.cobalt.io/findings?limit=5 |
pentest | N/A | If specified, returns findings scoped to this pentest id. Example: https://api.us.cobalt.io/findings?pentest=pt_PEtv4dqnwGV2efZhLw3BM5 |
asset | N/A | If specified, returns findings scoped to this asset id. Example: https://api.us.cobalt.io/findings?asset=as_HcChCMueiPQQgvckmZtRSd |
state | N/A | If specified, returns findings that match state . See Response Fields below for example state values. Example: https://api.us.cobalt.io/findings?state=check_fix . Returns an empty list if no findings match the state filter. |
severity | N/A | If specified, returns findings that match severity . See Response Fields below for example severity values. Example: https://api.us.cobalt.io/findings?severity=medium . Returns an empty list if no findings match the severity filter. |
labels_contains_all[] | N/A | If specified, returns findings that contain all specified labels. This query parameter can be specified multiple times. Returns an empty list if no matches are found. Example: https://api.us.cobalt.io/findings?labels_contains_all[]=Awaiting Feedback&labels_contains_all[]=Retest Blocked |
sort | N/A | If specified, returns findings sorted by one of the chosen parameters: severity , impact , state , created_at and updated_at . When defined, findings are sorted in ascending order by the sort parameter. To sort in descending order, use a - before the sort parameter. Example: https://api.us.cobalt.io/findings?sort=-severity . |
created_at_lte | N/A | If specified, returns findings where the created_at timestamp is less than or equal to the input timestamp. ISO8601 is the supported input timestamp format. Returns an empty list if no findings match the filter. Example: https://api.us.cobalt.io/findings?created_at_lte=2020-02-20T15:28:10.335Z |
created_at_gte | N/A | If specified, returns findings where the created_at timestamp is greater than or equal to the input timestamp. ISO8601 is the supported input timestamp format. Returns an empty list if no findings match the filter. Example: https://api.us.cobalt.io/findings?created_at_gte=2020-02-20T15:28:10.335Z |
updated_at_lte | N/A | If specified, returns findings where the updated_at timestamp is less than or equal to the input timestamp. ISO8601 is the supported input timestamp format. Returns an empty list if no findings match the filter. Example: https://api.us.cobalt.io/findings?updated_at_lte=2020-02-20T15:28:10.335Z |
updated_at_gte | N/A | If specified, returns findings where the updated_at timestamp is greater than or equal to the input timestamp. ISO8601 is the supported input timestamp format. Returns an empty list if no findings match the filter. Example: https://api.us.cobalt.io/findings?updated_at_gte=2020-02-20T15:28:10.335Z |
image_attachments_render_format | markdown | If specified, returns image attachments with the specified render format. Supported values are markdown and token . Example: https://api.us.cobalt.io/findings?image_attachments_render_format=token . See the Image Attachments section for more information |
Response Fields
Field | Enum Types |
---|---|
log | created , impact_changed , likelihood_changed , state_changed |
severity | null , low , medium , high (aka criticality . will be null if likelihood/impact have not yet been set by the pentester) |
severity_justification | Optional; The justification for the severity rating |
prerequisites | Optional; The prerequisites required for reproducing the vulnerability |
http_request | Optional; An example HTTP request for reproducing the vulnerability |
state | See Finding States Documentation |
type_category | XSS, SQLi, … (about 30 more via the Cobalt Taxonomy) |
attachments | A list of finding attachments. Attachment download URLs are pre-authorized and will expire after 10 minutes. |
links.ui.url | A link to redirect an authorized user to this finding in the Cobalt web application |
Image Attachments
Several finding response fields support image attachments. By default, these attachments are rendered
in our response JSON as markdown. For example:
![screenshot.png](https://api.us.cobalt.io/v1/attachments/att_xxxxxxx/preview)
.
This format is not useful for users who want to programmatically download the attachments and associate
them with a specific position in the finding response. For this use case, we support a token format,
which renders the attachment as a token that can be used to download the attachment. For example:
<CobaltImageAttachment at_KYKDAhZPXuQ4BW23g8i9QN>
.
The token format allows users to employ a technology such as RegEx to search the finding response
fields for image attachments and extract the image attachment IDs. In the example token,
at_KYKDAhZPXuQ4BW23g8i9QN
is the attachment ID. Users can use the attachment ID to locate the full
attachment information by searching the attachments
array in the finding response for an object with
a matching ID. The attachment object includes a download_url
field that can be used to download the attachment.
Get a Finding
curl -X GET "https://api.us.cobalt.io/findings/YOUR-FINDING-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "vl_3sP2RCWWUajc3oRXmbQ4j9",
"tag": "#PT5940",
"title": "XSS vulnerability",
"description": "Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts...",
"type_category": "Cross-Site Scripting (XSS)",
"labels": [
{
"name": "Your label"
}
],
"impact": 5,
"likelihood": 4,
"severity": "high",
"affected_targets": [
"https://example.com",
"192.168.1.1"
],
"proof_of_concept": "Here you can see...",
"severity_justification": "The vulnerability can cause a lot of damage",
"suggested_fix": "Ensure this...",
"prerequisites": "Credentials are needed",
"pentest_id": "pt_PEtv4dqnwGV2efZhLw3BM5",
"http_request": "HTTP GET / ...",
"asset_id": "as_HcChCMueiPQQgvckmZtRSd",
"log": [
{
"action": "created",
"timestamp": "2021-09-22T18:43:01.677Z"
}
],
"state": "new",
"created_at": "2022-09-26T18:35:18.759Z",
"updated_at": "2022-09-26T18:36:57.462Z",
"attachments": [
{
"id": "at_LA5GcEL4HRitFGCHREqmzL",
"file_name": "rainbow.jpeg",
"download_url": "https://s3.amazonaws.com/acmecorp/uploads/attachment/file/12345/rainbow.jpeg?something=1"
}
]
},
"links": {
"ui": {
"url": "https://api.us.cobalt.io/links/eyJ0eXBlIjoic29tZXRoaW5nIiwib3JnU2x1ZyI6ImNvYmFsdCIsInBlbnRlc3RUYWciOiJz="
}
}
}
This endpoint retrieves a specific finding that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/findings/YOUR-FINDING-IDENTIFIER
URL Parameters
Parameter | Default | Description |
---|---|---|
image_attachments_render_format | markdown | If specified, returns image attachments with the specified render format. Supported values are markdown and token . Example: https://api.us.cobalt.io/findings/YOUR-FINDING-IDENTIFIER?image_attachments_render_format=token . See the Image Attachments section for more information |
Response Fields
Field | Enum Types |
---|---|
log | created, impact_changed, likelihood_changed, state_changed |
severity | null, low, medium, high (aka criticality . will be null if likelihood/impact have not yet been set by the pentester) |
severity_justification | Optional; The justification for the severity rating |
prerequisites | Optional; The prerequisites required for reproducing the vulnerability |
http_request | Optional; An example HTTP request for reproducing the vulnerability |
state | See Finding States Documentation |
type_category | XSS, SQLi, … (about 30 more via the Cobalt Taxonomy) |
attachments | A list of finding attachments. Attachment download URLs are pre-authorized and will expire after 10 minutes. |
url | The links.ui.url will redirect an authorized user to this finding in the Cobalt platform |
Image Attachments
Several finding response fields support image attachments. By default, these attachments are rendered in our response
JSON as markdown. For example:
![screenshot.png](https://api.us.cobalt.io/v1/attachments/att_xxxxxxx/preview)
.
This format is not useful for users who want to programmatically download the attachments and associate them with a
specific position in the finding response. For this use case, we support a token format, which renders the attachment
as a token that can be used to download the attachment. For example:
<CobaltImageAttachment at_KYKDAhZPXuQ4BW23g8i9QN>
.
The token format allows users to employ a technology such as RegEx to search the finding response fields for image
attachments and extract the image attachment IDs. In the example token, at_KYKDAhZPXuQ4BW23g8i9QN
is the attachment
ID. Users can use the attachment ID to locate the full attachment information by searching the attachments
array in
the finding response for an object with a matching ID. The attachment object includes a download_url
field that
can be used to download the attachment.
View Available Finding States
curl -X GET "https://api.us.cobalt.io/findings/YOUR-FINDING-ID/possible_states" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"current_state": "invalid",
"possible_states": [
"triaging",
"need_fix",
"duplicate",
"out_of_scope"
]
}
}
This endpoint retrieves the current state of a finding as well as possible next states.
HTTP Request
GET https://api.us.cobalt.io/findings/YOUR-FINDING-ID/possible_states
URL Parameters
Parameter | Description |
---|---|
YOUR-FINDING-ID | A unique ID representing the finding. Starts with vl_ |
Response Fields
Field | Description |
---|---|
current_state | The current state of the finding. |
possible_states | A list of states that the finding can be transitioned to. See Finding States Documentation |
Update Finding State
curl -X PATCH "https://api.us.cobalt.io/findings/YOUR-FINDING-ID" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Content-Type: application/vnd.cobalt.v2+json" \
-H "Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN" \
-d '{"state":"triaging"}'
If successful, this command returns
204
.
This endpoint updates the current state of a finding.
HTTP Request
PATCH https://api.us.cobalt.io/findings/YOUR-FINDING-ID
URL Parameters
Parameter | Description |
---|---|
YOUR-FINDING-ID | A unique ID representing the finding. Starts with vl_ |
Body
Field | Description |
---|---|
state | The desired next state of the finding. Should be one of the possible states. |
Attack Surface
Get Attack Surface
curl --location 'https://api.us.cobalt.io/attack_surface/stats' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"domains": "3",
"seen_hosts": "200",
"new_seen_hosts": "10"
},
"links": {
"ui": {
"url": "https://api.cobalt.io/links/base64-link"
}
}
}
This endpoint retrieves stats from the attack surface that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/attack_surface/stats
Response Fields
Field | Description |
---|---|
domains | Total amount of domains |
seen_hosts | Amount of hosts with at least one IP found within the last 7 days |
new_seen_hosts | Amount of hosts we found an IP for the first time within the last 7 days |
links.ui.url | A link to redirect an authorized user to the attack surface of the organization in the Cobalt web application |
DAST Targets
Get All DAST Targets
curl -X GET "https://api.us.cobalt.io/dast/targets" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"pagination": {
"next_page": "/resource?cursor=123asdzxc",
"prev_page": "/resource?cursor=123asdzxc"
},
"data": [
{
"resource": {
"id": "dt_GZgcehapJUNh6mjNuqsE4T",
"name": "My DAST Target",
"url": "https://myapp.local",
"enabled": true
}
}
]
}
This endpoint retrieves a list of all DAST Targets that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/targets
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/dast/targets?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of targets. Example: https://api.us.cobalt.io/dast/targets?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST target. Starts with dt_ |
name | The name of the returned DAST target. |
url | The URL of the returned DAST target |
enabled | A boolean flag specifying if the DAST target is enabled |
Get a DAST Target
curl -X GET "https://api.us.cobalt.io/dast/targets/YOUR-DAST-TARGET-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "dt_GZgcehapJUNh6mjNuqsE4T",
"name": "My DAST Target",
"url": "https://myapp.local",
"enabled": true
}
}
This endpoint retrieves a specific DAST Target that belongs to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/targets/YOUR-DAST-TARGET-IDENTIFIER
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST target. Starts with dt_ |
name | The name of the returned DAST target. |
url | The URL of the returned DAST target |
enabled | A boolean flag specifying if the DAST target is enabled |
DAST Scans
Get All DAST Scans
curl -X GET "https://api.us.cobalt.io/dast/scans" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"pagination": {
"next_page": "/resource?cursor=123asdzxc",
"prev_page": "/resource?cursor=123asdzxc"
},
"data": [
{
"resource": {
"id": "dsc_GZgceqweJUNh6mjNuqsE4T",
"target_id": "dt_GZgcehapJUNh6mjNuqsE4T",
"status": "completed",
"started_at": "2024-07-01T10:04:31.460Z",
"completed_at": "2024-07-01T10:04:31.460Z"
}
}
]
}
This endpoint retrieves a list of all DAST scans that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/scans
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/dast/scans?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of scans. Example: https://api.us.cobalt.io/dast/scans?limit=5 |
target | N/A | If specified, returns scans scoped to this target id. Example: https://api.us.cobalt.io/dast/scans?target=dt_GZgcehapJUNh6mjNuqsE4T |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST scan. Starts with dsc_ |
target_id | A unique ID representing the DAST target. Starts with dt_ |
status | Possible values: [canceled , canceling , completed , completed_with_errors , failed , paused , pausing , queued , resuming , started , under_review , finishing_up ] |
started_at | Date and time of when the scan started. |
completed_at | Date and time of when the scan was completed. |
Get a DAST Scan
curl -X GET "https://api.us.cobalt.io/dast/scans/YOUR-DAST-SCAN-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "dsc_GZgceqweJUNh6mjNuqsE4T",
"target_id": "dt_GZgcehapJUNh6mjNuqsE4T",
"status": "completed",
"started_at": "2024-07-01T10:19:11.160Z",
"completed_at": "2024-07-01T10:19:11.160Z"
}
}
This endpoint retrieves a specific DAST Scan that belongs to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/scans/YOUR-DAST-SCAN-IDENTIFIER
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST scan. Starts with dsc_ |
target_id | A unique ID representing the DAST target. Starts with dt_ |
status | Possible values: [canceled , canceling , completed , completed_with_errors , failed , paused , pausing , queued , resuming , started , under_review , finishing_up ] |
started_at | Date and time of when the scan started. |
completed_at | Date and time of when the scan was completed. |
DAST Findings
Get All DAST Findings
curl -X GET "https://api.us.cobalt.io/dast/findings" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"pagination": {
"next_page": "/resource?cursor=123asdzxc",
"prev_page": "/resource?cursor=123asdzxc"
},
"data": [
{
"resource": {
"id": "dfi_2pF7XE2nJyP3i8ComjVXj3",
"target_id": "dt_GZgcehapJUNh6mjNuqsE4T",
"scan_ids": [
"dsc_GZgceqweJUNh6mjNuqsE4T"
],
"title": "string",
"last_found_at": "2024-07-01T10:39:31.919Z",
"severity": "string",
"state": "string",
"affected_url": "string",
"description": "string",
"proof_of_concept": "string",
"suggested_fix": "string",
"http_exchanges": [
{
"request": "string",
"response": "string"
}
]
}
}
]
}
This endpoint retrieves a list of all DAST findings that belong to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/findings
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/dast/findings?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of findings. Example: https://api.us.cobalt.io/dast/findings?limit=5 |
target | N/A | If specified, returns findings scoped to this target id. Example: https://api.us.cobalt.io/dast/findings?target=dt_GZgcehapJUNh6mjNuqsE4T |
scan | N/A | If specified, returns findings scoped to this scan id. Example: https://api.us.cobalt.io/dast/findings?scan=dsc_GZgcehapJUNh6mjNuqsE4T |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST finding. Starts with dfi_ |
target_id | A unique ID representing the DAST target. Starts with dt_ |
scan_ids | An array of unique ID representing the scans that originated the vulnerability finding. Starts with dsc_ |
title | Name of the vulnerability |
last_found_at | Date and time of when the vulnerability was last found, in ISO 8601 UTC format. |
severity | Severity of the vulnerability finding: 10 is low. 20 is medium. 30 is high. |
state | State of the vulnerability finding: [notfixed , invalid , accepted , fixed ] |
affected_url | URL affected by the found vulnerability |
description | Description of the vulnerability. |
proof_of_concept | Evidence of the vulnerability finding. |
suggested_fix | Description of how to fix the vulnerability. |
http_exchanges | Pairs of request and response of the vulnerability finding. |
Get a DAST Finding
curl -X GET "https://api.us.cobalt.io/dast/findings/YOUR-DAST-FINDING-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "dfi_2pF7XE2nJyP3i8ComjVXj3",
"target_id": "dt_GZgcehapJUNh6mjNuqsE4T",
"scan_ids": [
"dsc_GZgceqweJUNh6mjNuqsE4T"
],
"title": "string",
"last_found_at": "2024-07-01T10:56:34.997Z",
"severity": "string",
"state": "string",
"affected_url": "string",
"description": "string",
"proof_of_concept": "string",
"suggested_fix": "string",
"http_exchanges": [
{
"request": "string",
"response": "string"
}
]
}
}
This endpoint retrieves a specific DAST finding that belongs to the organization specified in the X-Org-Token
header.
HTTP Request
GET https://api.us.cobalt.io/dast/findings/YOUR-DAST-FINDING-IDENTIFIER
Response Fields
Field | Description |
---|---|
id | A unique ID representing the DAST finding. Starts with dfi_ |
target_id | A unique ID representing the DAST target. Starts with dt_ |
scan_ids | An array of unique ID representing the scans that originated the vulnerability finding. Starts with dsc_ |
title | Name of the vulnerability |
last_found_at | Date and time of when the vulnerability was last found, in ISO 8601 UTC format. |
severity | Severity of the vulnerability finding: 10 is low. 20 is medium. 30 is high. |
state | State of the vulnerability finding: [notfixed , invalid , accepted , fixed ] |
affected_url | URL affected by the found vulnerability |
description | Description of the vulnerability. |
proof_of_concept | Evidence of the vulnerability finding. |
suggested_fix | Description of how to fix the vulnerability. |
http_exchanges | Pairs of request and response of the vulnerability finding. |
External Ticket References
Search External Ticket References
curl --location 'https://api.us.cobalt.io/external_ticket_references/search' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
--data '{}'
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "efr_NgGSgvKVGLeTpVHAiGWkMG",
"title": "6",
"reference_type": "azure_devops_boards",
"ticketing_system": "azure_devops_boards",
"external_url": "https://dev.azure.com/my-project/test/_workitems/edit/6",
"external_id": "my-project-test-6",
"finding_id": "vl_4C5HhhycuKM6BYY72PpftM"
}
},
{
"resource": {
"id": "efr_8wDddLH13BoMoyvEtMEvPX",
"title": "123",
"reference_type": "github",
"ticketing_system": "github",
"external_url": "https://github.com/my-org/my-project/issue/123",
"external_id": "my-org-my-project-123",
"finding_id": "vl_JTovzf8AW1afCRpKJejse3"
}
},
{
"resource": {
"id": "efr_2qkKUC1PGDPR7KhvixTsXW",
"title": "TEST-36",
"reference_type": "jira",
"ticketing_system": "jira",
"external_url": "https://my-project.atlassian.net/browse/TEST-36",
"external_id": "10213",
"finding_id": "dfi_2bZrrKE3Hay7oLrbNUponW"
}
}
]
}
This endpoint retrieves a list of all external ticket references that belong to the organization specified in the X-Org-Token
header.
If you want to filter the search results based on a subset of findings, you can use the
findings
property in the request body.
curl --location 'https://api.us.cobalt.io/external_ticket_references/search' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
--data '{"findings":[{"id":"vl_JTovzf8AW1afCRpKJejse3"},{"id":"dfi_2bZrrKE3Hay7oLrbNUponW"}]}'
You can filter the external ticket references by a particular ticketing system using the
ticketing_system
property.
curl --location 'https://api.us.cobalt.io/external_ticket_references/search' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
--data '{"ticketing_system":"azure_devops_boards"}'
The
external_id
property can filter the external ticket reference by its identifier in the external ticketing system.
curl --location 'https://api.us.cobalt.io/external_ticket_references/search' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
--data '{"external_id":"8"}'
HTTP Request
POST https://api.us.cobalt.io/external_ticket_references/search
Request Body
Field | Description |
---|---|
findings | An array of finding ID object s to filter the search. For example, [{"id":"vl_JTovzf8AW1afCRpKJejse3"},{"id":"dfi_2bZrrKE3Hay7oLrbNUponW"}] . |
ticketing_system | One of the supported ticketing systems. |
external_id | The external ticket’s identifier in the external ticketing system. |
Create an External Ticket Reference
curl --location 'https://api.us.cobalt.io/external_ticket_references' \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
--data '{"title":"TEST-37","ticketing_system":"jira","external_url":"https://my-project.atlassian.net/browse/TEST-37","external_id":"10214","finding_id":"vl_JTovzf8AW1afCRpKJejse3"}'
The above command returns the created external ticket reference and a
201
response code when successful.
{
"resource": {
"id": "efr_9ekpSErugPH8zst2pBcjPo",
"title": "TEST-37",
"ticketing_system": "jira",
"external_url": "https://my-project.atlassian.net/browse/TEST-37",
"external_id": "10214",
"finding_id": "vl_JTovzf8AW1afCRpKJejse3"
}
}
This endpoint creates the external ticket reference, and on a successful request, it will return a 201
response code
along with the created external ticket reference information.
HTTP Request
POST https://api.us.cobalt.io/external_ticket_references
Request Body
Field | Description |
---|---|
title | A short descriptive title of the external ticket. For example, the ticket ID. |
ticketing_system | One of the supported ticketing systems. |
external_url | The URL of the external ticket. |
external_id | An arbitrary external identifier for the ticket reference. |
finding_id | The Cobalt ID of the finding this external ticket belongs to. |
Response
You get a 201
response code for a successful request.
Field | Description |
---|---|
id | A unique ID representing the external ticket reference. Starts with efr_ |
title | A short descriptive title of the external ticket. For example, the ticket ID. |
ticketing_system | One of the supported ticketing systems. |
external_url | The URL of the external ticket. |
external_id | An arbitrary external identifier for the ticket reference. |
finding_id | The Cobalt ID of the finding this external ticket belongs to. |
Delete an External Ticket Reference
curl -X DELETE 'https://api.us.cobalt.io/external_ticket_references/YOUR-EXTERNAL-TICKET-REFERENCE-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
The above command returns no data and a
204
response code when successful.
This endpoint deletes the external ticket reference.
Supported Ticketing Systems
azure_devops_boards
: Azure DevOps Boardsgithub
: GitHubjira
: Jira
Events
Get All Events
curl -X GET "https://api.us.cobalt.io/events" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyH",
"action": "comment_created",
"subject": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyH",
"type": "comment"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
},
{
"resource": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyP",
"action": "pentest_deleted",
"subject": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyP",
"type": "program"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
},
{
"resource": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyX",
"action": "finding_created",
"subject": {
"id": "ac_Y35JcpGoakrjUSVjtVpXyX",
"type": "vulnerability"
},
"timestamp": "2022-05-03T01:34:21.587Z"
}
}
],
"pagination": {
"next_page": "/events?cursor=a1b2c3d4",
"prev_page": "/events?cursor=4d3c2b1a"
}
}
This endpoint retrieves a list of all events for your account.
HTTP Request
GET https://api.us.cobalt.io/events
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/events?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of events. Example: https://api.us.cobalt.io/events?limit=5 |
Tokens
Get All Tokens
curl -X GET "https://api.us.cobalt.io/tokens" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"data": [
{
"resource": {
"id": "api_Dge3LsHMjtX8SGEk4a8nux",
"last_characters": "redacted",
"name": "Lorem ipsum",
"expire_at": null
}
}
],
"pagination": {
"next_page": null,
"prev_page": null
}
}
This endpoint retrieves a list of all tokens that belong to you.
HTTP Request
GET https://api.us.cobalt.io/tokens
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/tokens?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of tokens. Example: https://api.us.cobalt.io/tokens?limit=5 |
Response Fields
Field | Description |
---|---|
id | A unique ID representing the token. Starts with api_ |
name | Name of the API token |
last_characters | This property is deprecated. Do not use it. |
expire_at | null (not currently implemented) |
Refresh Token
curl -X POST "https://api.us.cobalt.io/tokens/YOUR-TOKEN-ID/refresh" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "api_Dge3LsHMjtX8SGEk4a8nux",
"secret": "YOUR-NEW-PERSONAL-API-TOKEN",
"name": "Lorem ipsum",
"expire_at": null
}
}
You can revoke an existing token and issue a new one with the same name by making a POST request to the token refresh endpoint.
Process:
- Make a GET request to the
/tokens
endpoint and note theid
of the token you would like to refresh. - Make a POST request to the
/tokens/YOUR-TOKEN-ID/refresh
endpoint using the tokenid
obtained in the step above. - The new token will be contained in the
secret
field of the response. Note this value. Your old token will no longer work.
If you’ve forgotten your token, you can always re-authenticate in the Cobalt web app. Go to your profile, revoke the old token you’ve forgotten, and generate a new token.
HTTP Request
POST https://api.us.cobalt.io/tokens/YOUR-TOKEN-ID/refresh
Response Fields
Field | Description |
---|---|
id | A unique ID representing the new token. Starts with api_ |
secret | Your new personal API token. Keep it safe and don’t share with anyone |
name | Name of your API token |
expire_at | null (not currently implemented) |
Webhooks
Webhooks allow your system to be notified when events occur on the Cobalt Platform via HTTP POST requests. This eliminates the need to poll the API for updates. You can also manage your webhooks within the Integrations Hub in the Cobalt Platform.
Get all webhooks
curl -X GET "https://api.us.cobalt.io/webhooks" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"pagination": {
"next_page": null,
"prev_page": null
},
"data": [
{
"resource": {
"id": "wb_38URp3gxZqfkjEXmkybrrs",
"name": "My Webhook",
"url": "https://example.local",
"active": true,
"unhealthy_since": null,
"user": "us_RxvqT5T3WCFrfTF74B6JLC",
"subscribed_event_types": [
"PENTEST_CREATED",
"PENTEST_STATE_UPDATED",
"FINDING_DELETED",
"FINDING_PUBLISHED",
"FINDING_STATE_UPDATED",
"FINDING_UPDATED"
]
}
}
]
}
This endpoint retrieves a list of all webhooks that belong to your organization.
HTTP Request
GET https://api.us.cobalt.io/webhooks
URL Parameters
Parameter | Default | Description |
---|---|---|
cursor | N/A | Used for pagination. Example: https://api.us.cobalt.io/webhooks?cursor=a1b2c3d4 |
limit | 10 | If specified, returns only a specified amount of webhooks. Example: https://api.us.cobalt.io/webhooks?limit=5 |
Response Fields
Field | Description |
---|---|
id | The ID of the webhook |
name | The name of the webhook |
url | The URL that webhook events are sent to |
active | A boolean flag that indicates if the webhook is active |
unhealthy_since | The time that we began failing to deliver events to this webhook. If the webhook is unhealthy, this field will contain an ISO8601 time stamp. Ex: 2022-08-30T14:14:14.000Z |
user | The ID of the user that created the webhook |
subscribed_event_types | The event types that the webhook is subscribed to. See possible event types here. |
Get a webhook
curl -X GET "https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER" \
-H "Accept: application/vnd.cobalt.v2+json" \
-H "Authorization: Bearer YOUR-PERSONAL-API-TOKEN" \
-H "X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN"
The above command returns JSON structured like this:
{
"resource": {
"id": "wb_38URp3gxZqfkjEXmkybrrs",
"name": "My Webhook",
"url": "https://example.local",
"active": true,
"unhealthy_since": null,
"user": "us_RxvqT5T3WCFrfTF74B6JLC",
"subscribed_event_types": [
"PENTEST_CREATED",
"PENTEST_STATE_UPDATED",
"FINDING_DELETED",
"FINDING_PUBLISHED",
"FINDING_STATE_UPDATED",
"FINDING_UPDATED"
]
}
}
This endpoint retrieves a specific webhook belonging to your organization.
HTTP Request
GET https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER
Response Fields
Field | Description |
---|---|
id | The ID of the webhook |
name | The name of the webhook |
url | The URL that webhook events are sent to |
active | A boolean flag that indicates if the webhook is active |
unhealthy_since | The time that we began failing to deliver events to this webhook. If the webhook is unhealthy, this field will contain an ISO8601 time stamp. Example: 2022-08-30T14:14:14.000Z |
user | The ID of the user that created the webhook |
subscribed_event_types | The event types that the webhook is subscribed to. See possible event types here |
Create a webhook
curl -X POST "https://api.us.cobalt.io/webhooks" \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN' \
--data '{
"name": "My Webhook",
"active": true,
"secret": "my_secret",
"url": "https://example.local/webhook",
"subscribed_event_types": [
"FINDING_PUBLISHED"
]
}'
The above command returns the details of the created webhook and a
201
response code when successful. There will be aLocation
header pointing at the newly created webhook.
{
"resource": {
"id": "wb_38URp3gxZqfkjEXmkybrrs",
"name": "My Webhook",
"url": "https://example.local/webhook",
"active": true,
"unhealthy_since": null,
"user": "us_RxvqT5T3WCFrfTF74B6JLC",
"subscribed_event_types": [
"FINDING_PUBLISHED"
]
}
}
This endpoint creates a new webhook belonging to your organization.
When you attempt to create a webhook, we will send a test event to your endpoint to validate that events can be delivered successfully. Your endpoint must respond with a successful HTTP response status code, for example, 200, 201, 204, etc. For details on test events, see the Webhook Events section below.
HTTP Request
POST https://api.us.cobalt.io/webhooks
Body
Field | Description |
---|---|
name | The name of the webhook |
active | A boolean flag specifying if the webhook is active |
secret | An arbitrary string value. We include this value in the X-Secret header when we send webhook events to you. You can use this to verify that the events you receive are from Cobalt. This field is optional. |
url | The URL to send events to |
subscribed_event_types | The event types that the webhook should be subscribed to. May not be an empty list. See possible event types here. |
Response
When the request is successful, you get a 201
response code and the details of the created webhook.
The response body fields are the same as documented here.
The Location
response header contains the URL of the new webhook within the Cobalt API.
Update a webhook
curl -X PATCH 'https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'Idempotency-Key: A-UNIQUE-IDENTIFIER-TO-PREVENT-UNINTENTIONAL-DUPLICATION' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN' \
--data '{
"name": "FooBar",
"secret": "super_secret",
"active": false,
"url": "https://example.local/webhook2",
"subscribed_event_types": [
"FINDING_PUBLISHED"
]
}'
The above command returns the details of the updated webhook and a
200
response code when successful.
{
"resource": {
"id": "wb_38URp3gxZqfkjEXmkybrrs",
"name": "FooBar",
"url": "https://example.local/webhook2",
"active": false,
"unhealthy_since": null,
"user": "us_RxvqT5T3WCFrfTF74B6JLC",
"subscribed_event_types": [
"FINDING_PUBLISHED"
]
}
}
This endpoint updates a webhook belonging to your organization.
HTTP Request
PATCH https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER
Body
All body fields are optional. You only need to include the fields that should be updated.
Field | Description |
---|---|
name | The name of the webhook |
secret | An arbitrary string value. We include this value in the X-Secret header when we send webhook events to you. You can use this to verify that the events you receive are from Cobalt. |
active | A boolean flag specifying if the webhook is active |
url | The URL to send events to |
subscribed_event_types | The event types that the webhook should be subscribed to. May not be an empty list. Non-specified event types that are currently subscribed to will be un-subscribed from. Specified event types that are not currently subscribed to will be subscribed to. See possible event types here. |
Response
On a successful update, a 200
response code and the details of the updated webhook will be returned.
The response body fields are the same as documented here.
Delete a webhook
curl -X DELETE 'https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER' \
-H 'Accept: application/vnd.cobalt.v2+json' \
-H 'Authorization: Bearer YOUR-PERSONAL-API-TOKEN' \
-H 'Content-Type: application/vnd.cobalt.v2+json' \
-H 'X-Org-Token: YOUR-V2-ORGANIZATION-TOKEN'
The above command returns no data and a
204
response code when successful.
This endpoint deletes a webhook belonging to your organization.
HTTP Request
DELETE https://api.us.cobalt.io/webhooks/YOUR-WEBHOOK-IDENTIFIER
Response
On successful deletion, a 204
response code will be returned.
Webhook Delivery and Health
Delivery process:
- An event occurs on the Cobalt Platform that you are subscribed to
- Cobalt will attempt to send the event to your webhook endpoint via an HTTP POST request. If your endpoint responds with a successful HTTP response status code, for example, 200, 201, or 204, then we will mark the delivery as successful.
- If your endpoint does not respond with a successful HTTP status, then we will attempt to send the event 5 more times with 5 seconds between each request.
- If none of the delivery attempts succeed, then we will mark your webhook endpoint as unhealthy and put the event into our failed events queue.
- On an hourly interval we will attempt to redeliver failed events.
- If your webhook endpoint becomes able to receive events again, we will mark your webhook endpoint as healthy.
- If your webhook endpoint stays unhealthy for 48 hours then we will deactivate your webhook.
If your webhook becomes deactivated then you will need to activate it again via the user interface or the API.
Best Practices
- Set your webhook secret to a high-entrophy value of sufficient length.
When you receive an event, check that the value in the
X-Secret
header matches your secret. This ensures that you do not process fraudulent webhook events from a threat actor. - Don’t add expensive operations to the endpoint that receives webhook events. A common pattern is to receive webhook events with a lightweight endpoint that publishes received events to a message queue that can be processed by your components containing business logic. This keeps the latency and failure rate of your webhook endpoint low.
Webhook Event General Structure
Webhook event properties:
Field | Nullable | Description |
---|---|---|
id | false | The ID of the webhook event |
action | false | The action that the event is related to |
subject | false | The subject that the event is related to |
details | true | Additional details of the event |
timestamp | false | The time that the event occurred |
action
types:
FINDING_DELETED
FINDING_PUBLISHED
FINDING_STATE_UPDATED
FINDING_UPDATED
PENTEST_CREATED
PENTEST_STATE_UPDATED
TEST_EVENT
subject
properties:
Field | Nullable | Description |
---|---|---|
id | false | The ID of the subject resource |
type | false | The type of the subject resource |
associations | true | IDs of associated entities |
subject
types:
TEST_EVENT
PENTEST
FINDING
The format of the subject ID will change based on the type of the subject.
The full information about the event subject can be fetched from the GET
API route that
is appropriate for the subject type.
Examples:
- A
FINDING_PUBLISHED
event would have a subject ID with the format:vl_xxxxxxxxxxxxxxxxxxxxxx
. The full information about the finding that was published can be found by making aGET
request to the API endpoint:/findings/vl_xxxxxxxxxxxxxxxxxxxxxx
. - A
PENTEST_CREATED
event would have a subject ID with the format:pt_xxxxxxxxxxxxxxxxxxxxxx
. The full information about the pentest that was created can be found by making aGET
request to the API endpoint:/pentests/pt_xxxxxxxxxxxxxxxxxxxxxx
.
Pentest Created Event
{
"id": "eve_G2FcwQF2HD1Fvw8v6kWzut",
"action": "PENTEST_CREATED",
"subject": {
"id": "pt_JZb7yF5jtPzHkGbdv9gTm1",
"type": "PENTEST",
"associations": {
"asset_id": "as_Je7VmdguBKDgnBeVAHvvzg"
}
},
"details": null,
"timestamp": "2024-03-18T16:48:07.876Z"
}
This event is fired when a new pentest is created.
Action: PENTEST_CREATED
Subject type: PENTEST
Subject associations:
Association | Nullable |
---|---|
asset_id | false |
Event details: None
Pentest State Updated Event
{
"id": "eve_NViSofme6fkUeHA4DLMJ4Z",
"action": "PENTEST_STATE_UPDATED",
"subject": {
"id": "pt_JZb7yF5jtPzHkGbdv9gTm1",
"type": "PENTEST",
"associations": {
"asset_id": "as_Je7VmdguBKDgnBeVAHvvzg"
}
},
"details": null,
"timestamp": "2024-03-18T16:49:31.217Z"
}
This event is fired when a pentest’s state is updated.
Action: PENTEST_STATE_UPDATED
Subject type: PENTEST
Subject associations:
Association | Nullable |
---|---|
asset_id | false |
Event details: None
Finding Deleted Event
{
"id": "eve_QTDZnhhHzQAbrADCbp4iZs",
"action": "FINDING_DELETED",
"subject": {
"id": "vl_NQ1AmofsRQYich6nGda4Vh",
"type": "FINDING",
"associations": {
"pentest_id": "pt_72jWq2hJ3arozEWq9HU7Mk",
"asset_id": "as_7PFxAamzsqDNixMcQoR723"
}
},
"details": null,
"timestamp": "2024-03-18T17:18:10.355Z"
}
This event is fired when a finding is deleted.
Action: FINDING_DELETED
Subject type: FINDING
Subject associations:
Association | Nullable |
---|---|
pentest_id | false |
asset_id | false |
Event details: None
Finding Published Event
{
"id": "eve_6c355k5S7JnKBLAU4niKcZ",
"action": "FINDING_PUBLISHED",
"subject": {
"id": "vl_Mj56fMKWzkp55XLxC2xEuL",
"type": "FINDING",
"associations": {
"pentest_id": "pt_72jWq2hJ3arozEWq9HU7Mk",
"asset_id": "as_7PFxAamzsqDNixMcQoR723"
}
},
"details": null,
"timestamp": "2024-03-18T17:20:40.384Z"
}
This event is fired when a finding is published for triaging.
Action: FINDING_PUBLISHED
Subject type: FINDING
Subject associations:
Association | Nullable |
---|---|
pentest_id | false |
asset_id | false |
Event details: None
Finding State Updated Event
{
"id": "eve_9M1HKUV8GsjWVkozDLNaid",
"action": "FINDING_STATE_UPDATED",
"subject": {
"id": "vl_Mj56fMKWzkp55XLxC2xEuL",
"type": "FINDING",
"associations": {
"pentest_id": "pt_72jWq2hJ3arozEWq9HU7Mk",
"asset_id": "as_7PFxAamzsqDNixMcQoR723"
}
},
"details": {
"previous_state": "triaging",
"current_state": "need_fix"
},
"timestamp": "2024-03-18T17:23:57.207Z"
}
This event is fired when a finding’s state is updated.
Action: FINDING_STATE_UPDATED
Subject type: FINDING
Subject associations:
Association | Nullable |
---|---|
pentest_id | false |
asset_id | false |
Event details:
Detail | Nullable | Description |
---|---|---|
previous_state | false | The previous state of the finding |
current_state | false | The current state of the finding |
Finding Updated Event
{
"id": "eve_8Q4oVYu7yi1WDE6oEwKGg9",
"action": "FINDING_UPDATED",
"subject": {
"id": "vl_Mj56fMKWzkp55XLxC2xEuL",
"type": "FINDING",
"associations": {
"pentest_id": "pt_72jWq2hJ3arozEWq9HU7Mk",
"asset_id": "as_7PFxAamzsqDNixMcQoR723"
}
},
"details": null,
"timestamp": "2024-03-18T17:28:26.415Z"
}
This event is fired when a finding’s content (not state) is updated.
Action: FINDING_UPDATED
Subject type: FINDING
Subject associations:
Association | Nullable |
---|---|
pentest_id | false |
asset_id | false |
Event details: None
Pagination
Pagination can be used if the number of resources for a request exceeds the value of the limit
query parameter of the
request. If the next_page
and/or prev_page
values in the response are non-null
there are additional resources.
To paginate append the next_page
or prev_page
value to the base API URL.
For example, if the next_page
value in a response is /resource?cursor=a1b2c3d4
you can send the following request
for the next page.
GET https://api.us.cobalt.io/resource?cursor=a1b2c3d4
Idempotency
The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response. For example, if a request to create an asset does not respond due to a network connection error, you can retry the request with the same idempotency key to guarantee that no more than one asset is created.
To perform an idempotent request, provide an additional Idempotency-Key: <key>
header to the request. The
header name Mutation-Check
is also supported for backwards compatibility with previous versions of the API.
An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions.
All POST
requests optionally accept idempotency keys. Idempotency keys expire after 5 minutes.
Rate Limits
The Cobalt API sets rate limits on API requests to manage request volume and maintain system availability.
- Rate limiting follows a fixed-window policy, with a maximum number of requests allowed in a specific time window.
- Rate limiting applies on a per-user basis, regardless of how many API tokens the user has.
Rate Limits
Request Type | HTTP Verbs | Limit | Window | HTTP Response Headers |
---|---|---|---|---|
Get requests | GET | 100 | 60 seconds | X-Rate-Limit-Get-Limit and X-Rate-Limit-Remaining |
Mutate requests | POST , PATCH , PUT , DELETE | 20 | 60 seconds | X-Rate-Limit-Mutate-Limit and X-Rate-Limit-Remaining |
HTTP Response Headers
X-Rate-Limit-Get-Limit
: Indicates the maximum number ofGET
requests allowed per time window. Example:X-Rate-Limit-Get-Limit: 100
X-Rate-Limit-Mutate-Limit
: Indicates the maximum number of Mutate requests allowed per time window. Example:X-Rate-Limit-Mutate-Limit: 20
X-Rate-Limit-Remaining
: Indicates the number of requests remaining in the time window. Example:X-Rate-Limit-Remaining: 93
When the Rate Limit Is Exceeded
When a user exceeds the rate limit, the API returns a 509 BANDWIDTH_LIMIT_EXCEEDED
HTTP response code along with the
headers above. The rate limit resets after the specified time window.
Errors
The Cobalt API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request – Your request is not good |
401 | Unauthorized – Your API token is wrong |
403 | Forbidden – You don’t have access to this resource |
404 | Not Found – The specified request could not be found |
405 | Method Not Allowed – You tried to access Cobalt data with an invalid method |
406 | Not Acceptable – You requested a format that isn’t json |
409 | Conflict – You attempted to create a resource with the same Idempotency-Key header as a recent request. |
410 | Gone – The requested endpoint has been removed from Cobalt servers |
418 | I’m a teapot |
422 | Unprocessable Entity – The content and syntax are correctly formed, but something else is off. |
429 | Too Many Requests – You’re making requests too often. |
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. |
Partner Integrations
We request that you please set a custom User-Agent
header when developing a partner integration.
The custom User-Agent
header should identify your integration.
This allows us to identify traffic originating from your integration for analytical and troubleshooting purposes.
Format:
User-Agent: [IntegrationName]/[IntegrationVersion]
Example:
User-Agent: PartnerCobaltIntegration/1.0.0
The User-Agent
header is not required, but we strongly encourage partner integrations to send this header.
Changelog
New Endpoints
In the v2 release, we’ve published some additional endpoints to extend the capabilities of Cobalt API. Please refer to the following endpoints for more details:
- Get an Asset
- Create an Asset
- Update an Asset
- Delete an Asset
- Upload an Asset Attachment
- Delete an Asset Attachment
- Upload an Asset Logo
- Get a Pentest
- Get a Pentest Report
- Duplicate a Pentest
- Delete a Pentest
- Get a Finding
- View Available Finding States
- Update Finding State
- Get all Webhooks
- Get a Webhook
- Create a Webhook
- Update a Webhook
- Delete a Webhook
Identifier Changes
In Cobalt API v2, we’ve focused on standardizing and extending identifiers for all endpoints. As a result, either the structure or the length of some identifiers has changed. You can see a side-by-side comparison of v1 and v2 with some sample identifiers below:
Endpoint | Response field | v1 (example) | v2 (example) |
---|---|---|---|
organizations | id | or_A2bb4FE | or_Uevoq7MyoYsPT9NPc3conL |
organizations | token | ABCDEFGHJ12345678901 | ASDFGHJKLQWERTYUM1234567890ABCDEFGH1234567891234 |
assets | id | as_rvZRC5Y | as_GZgcehapJUNh6mjNuqsE4T |
assets | attachments.token | att_yYXZodA | at_LA5GcEL4HRitFGCHREqmzL |
pentests | id | pt_rVShby8 | pt_JQJpAAMjyc8xVtXW2X2Aq5 |
findings | id | vu_ZzZuekb | vl_3xP2RCWWUajc3oRXmbQ4j9 |
findings | pentest_id | pt_9Ig1234 | pt_PEtv4xqnwGV2efZhLw3XM5 |
findings | asset_id | as_cwrsqsL | as_HcChCMueiPQQgvckmZtRSd |
events | id | 277603 | ac_Y35JcpGoakrjUSVjtVpXyH |
events | subject.id | 277603 | ac_Y35JcpGoakrjUSVjtVpXyH |
For the majority of endpoints, the only change is the length of the identifier. However, there are some prefix and type
changes too. For example, the identifier prefix of the findings endpoint has changed from vu
to vl
. Similarly,
the attachments.token
prefix has changed from att
to at
.
We aren’t expecting any of these to be breaking changes for the majority of our customers, but, if you have any validations in place, concerning prefixes or the length of strings, please update them accordingly.
Please note - the token
attribute of the organizations endpoint now returns a different string in
v2. This value is also known as “organization token” all over the API docs, and is used as the value of X-Org-Token
header when calling endpoints.
Renamed Response Attributes
The token
attribute of the attachments
object in v1
of assets endpoint was renamed to id
in v2
.
{
// v1
"attachments": [
{
"token": "att_yYXZodA"
}
],
// v2
"attachments": [
{
"id": "at_LA5GcEL4HRitFGCHREqmzL"
}
]
}
New Response Attributes
The response from listing findings and getting a single finding now includes an attachments
attribute that
shows files attached to a finding. Finding attachments can be programmatically downloaded using this
information. Click here for more information.
Request Headers
Header | v1 | v2 | Description |
---|---|---|---|
Accept | application/vnd.cobalt.v1+json | application/vnd.cobalt.v2+json | Must be present in the request |
Content-Type | N/A | application/vnd.cobalt.v2+json | Required for POST/PUT/DELETE HTTP methods |
Idempotency-Key | N/A | Refer to idempotency | Suggested for POST requests |
In v1, the Cobalt API was read-only, and in v2 we’ve added different endpoints where you can create, update or delete resources.
With these additions in place, two new headers came into place; Content-Type
and Idempotency-Key
. The
Idempotency-Key
is explained in the idempotency section.
Pagination Defaults
In v1, some endpoints had 10, and some others had 1000 as their pagination default value. In this release, we’ve updated the default pagination values of all endpoints to 10. Two endpoints were affected by this change:
Endpoint | v1 (default) | v2 (default) |
---|---|---|
pentests | 1000 | 10 |
findings | 1000 | 10 |
Subscription
If you want to receive our API updates you can subscribe to our mailing list. We will be sending you a newsletter containing changes and improvements in our API once a month. You can also unsubscribe anytime you want. Your email address won’t be shared with any other organization.