curl --request GET \
--url https://api.leen.dev/v1/appsec/issues \
--header 'X-API-KEY: <api-key>' \
--header 'X-CONNECTION-ID: <api-key>'import requests
url = "https://api.leen.dev/v1/appsec/issues"
headers = {
"X-API-KEY": "<api-key>",
"X-CONNECTION-ID": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-API-KEY': '<api-key>', 'X-CONNECTION-ID': '<api-key>'}
};
fetch('https://api.leen.dev/v1/appsec/issues', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.leen.dev/v1/appsec/issues",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <api-key>",
"X-CONNECTION-ID: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.leen.dev/v1/appsec/issues"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("X-CONNECTION-ID", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.leen.dev/v1/appsec/issues")
.header("X-API-KEY", "<api-key>")
.header("X-CONNECTION-ID", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.leen.dev/v1/appsec/issues")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-KEY"] = '<api-key>'
request["X-CONNECTION-ID"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"count": 123,
"items": [
{
"code_repo": "<string>",
"description": "<string>",
"first_seen": "2023-11-07T05:31:56Z",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"last_seen": "2023-11-07T05:31:56Z",
"name": "<string>",
"package_manager": "<string>",
"package_name": "<string>",
"package_version": "<string>",
"project_file_path": "<string>",
"severity": "INFO",
"state": "OPEN",
"type": "VULNERABILITY",
"vendor": "<string>",
"vendor_id": "<string>",
"cvss_score": 123,
"exploitable": true,
"is_patchable": true,
"issue_url": "<string>",
"kb_url": "<string>",
"platform": "<string>",
"publication_time": "2023-11-07T05:31:56Z",
"reachability": "REACHABLE",
"remediation": [
"<string>"
],
"repo_branch_name": "<string>",
"repo_url": "<string>",
"state_updated_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"vendor_data": {
"attack_surface_type": "backend",
"finding_type": "cloud",
"attack_surface": {
"active": true,
"branch": "<string>",
"external_repo_id": "<string>",
"id": 123,
"name": "<string>",
"provider": "<string>",
"_dlt_id": "<string>",
"_dlt_load_id": 123
}
},
"vulnerability_identifiers": [
{
"type": "CVE",
"value": "CVE-2021-34527"
}
]
}
],
"total": 123
}{
"code": "<string>",
"detail": [
{}
],
"message": "<string>",
"type": "<string>"
}List Issues
List all the issues for a given connection. sort - supports severity:asc (eg. lowest to highest criticality) and severity:desc if not direction is provided it will default to asc
curl --request GET \
--url https://api.leen.dev/v1/appsec/issues \
--header 'X-API-KEY: <api-key>' \
--header 'X-CONNECTION-ID: <api-key>'import requests
url = "https://api.leen.dev/v1/appsec/issues"
headers = {
"X-API-KEY": "<api-key>",
"X-CONNECTION-ID": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-API-KEY': '<api-key>', 'X-CONNECTION-ID': '<api-key>'}
};
fetch('https://api.leen.dev/v1/appsec/issues', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.leen.dev/v1/appsec/issues",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <api-key>",
"X-CONNECTION-ID: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.leen.dev/v1/appsec/issues"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("X-CONNECTION-ID", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.leen.dev/v1/appsec/issues")
.header("X-API-KEY", "<api-key>")
.header("X-CONNECTION-ID", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.leen.dev/v1/appsec/issues")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-KEY"] = '<api-key>'
request["X-CONNECTION-ID"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"count": 123,
"items": [
{
"code_repo": "<string>",
"description": "<string>",
"first_seen": "2023-11-07T05:31:56Z",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"last_seen": "2023-11-07T05:31:56Z",
"name": "<string>",
"package_manager": "<string>",
"package_name": "<string>",
"package_version": "<string>",
"project_file_path": "<string>",
"severity": "INFO",
"state": "OPEN",
"type": "VULNERABILITY",
"vendor": "<string>",
"vendor_id": "<string>",
"cvss_score": 123,
"exploitable": true,
"is_patchable": true,
"issue_url": "<string>",
"kb_url": "<string>",
"platform": "<string>",
"publication_time": "2023-11-07T05:31:56Z",
"reachability": "REACHABLE",
"remediation": [
"<string>"
],
"repo_branch_name": "<string>",
"repo_url": "<string>",
"state_updated_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"vendor_data": {
"attack_surface_type": "backend",
"finding_type": "cloud",
"attack_surface": {
"active": true,
"branch": "<string>",
"external_repo_id": "<string>",
"id": 123,
"name": "<string>",
"provider": "<string>",
"_dlt_id": "<string>",
"_dlt_load_id": 123
}
},
"vulnerability_identifiers": [
{
"type": "CVE",
"value": "CVE-2021-34527"
}
]
}
],
"total": 123
}{
"code": "<string>",
"detail": [
{}
],
"message": "<string>",
"type": "<string>"
}Query Parameters
Sort by a field, written as field, field:asc or field:desc. Which fields can be sorted on differs per endpoint.
^severity$|^severity\:asc$|^severity\:desc$|^updated_at$|^updated_at\:asc$|^updated_at\:desc$|^state_updated_at$|^state_updated_at\:asc$|^state_updated_at\:desc$Only issues whose state changed at or after this time. Use it to poll for newly closed or reopened issues without re-reading everything.
"2021-01-01T00:00:00+00:00"
Only issues the vendor first recorded at or after this time. This is the vendor's own timestamp, not when Leen synced the issue.
"2021-01-01T00:00:00+00:00"
Only issues last observed at or after this time. Issues the vendor has stopped returning fall out of this window, so it is the filter for "what is still there".
"2021-01-01T00:00:00+00:00"
Severity filter, comma separated. One or more of CRITICAL, HIGH, MEDIUM, LOW, INFO. Severities are normalised, so this means the same thing whichever vendor found the issue.
"critical,high"
State filter, comma separated. One or more of OPEN, CLOSED, IGNORED, DELETED. DELETED means the vendor stopped returning the issue, which is not the same as it being fixed.
"open,closed"
Type filter, comma separated. One or more of VULNERABILITY, LICENSE, CLOUD, CODE, CUSTOM, CONFIG. Prefix the whole value with ! to exclude those types instead.
"vulnerability,license"
Fetch specific issues by Leen id, comma separated. At most 100 per request; ids that do not exist are skipped rather than erroring.
"123e4567-e89b-12d3-a456-426614174000,123e4567-e89b-12d3-a456-426614174001"
Filter by whether the vendor asserts the issue is exploitable — a known exploit exists, or it is actively exploited. Issues where the vendor reported no signal match neither true nor false.
true
Reachability filter, comma separated. One or more of REACHABLE, POTENTIALLY_REACHABLE, UNREACHABLE, UNKNOWN. UNKNOWN means the vendor analyzed the issue without reaching a conclusion; issues from vendors with no reachability analysis at all are excluded by any value.
"REACHABLE,POTENTIALLY_REACHABLE"
Enable cursor based pagination instead of default offset-based pagination
Only records whose updated_at is at or after this time. Leen bumps updated_at whenever any field on a record changes, so this is the filter for an incremental sync: it returns records that are new and records that changed, and nothing that has stood still. Example: 2021-01-01T00:00:00+00:00.
"2021-01-01T00:00:00+00:00"
How many records to return per page. The walk is the same either way; a larger page means fewer round trips and more memory per response.
1 <= x <= 500Where to start, counted in records. Offset paging is stable only while the underlying data is; prefer the cursor for anything long-running.
x >= 0Skip counting the total. Counting is the expensive half of a large query, so set this when you are walking every page anyway and never read total. total comes back null.
Opaque position of the next page, taken from the previous response. Ignore its contents; it encodes where the walk had reached.
Response
Successful Response