curl --request GET \
--url https://api.closedloop.sh/v1/insights \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.closedloop.sh/v1/insights"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.closedloop.sh/v1/insights', 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.closedloop.sh/v1/insights",
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>"
],
]);
$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.closedloop.sh/v1/insights"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<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.closedloop.sh/v1/insights")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.closedloop.sh/v1/insights")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_bodyList / search insights
Search processed product insights by customer, severity, product scope, date, or text, with offset or fixed-watermark incremental pagination.
curl --request GET \
--url https://api.closedloop.sh/v1/insights \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.closedloop.sh/v1/insights"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.closedloop.sh/v1/insights', 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.closedloop.sh/v1/insights",
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>"
],
]);
$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.closedloop.sh/v1/insights"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<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.closedloop.sh/v1/insights")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.closedloop.sh/v1/insights")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_bodyAuthorizations
Team-scoped API key created in the app (Settings → API Keys).
Sent as X-API-Key: <key> on every request. The header name apikey
is also accepted as an alias.
Query Parameters
Free-text search over titles and content.
Feedback category (e.g. bug, feature request, usability).
"bug"
critical, high, medium, low Filter to insights from one customer (same key as on context).
Filter by one product ID from /products.
Filter by one buildable product feature ID from /features.
Filter by one parent product-area ID from /areas.
Filter by one child feature-area ID from /areas. A feature area is the subject
area an insight is filed under; it is NOT a buildable feature ID from
/features, and the two are never interchangeable.
Inclusive start date, as a real calendar date in YYYY-MM-DD.
Any other form is rejected with 400 VALIDATION_ERROR - including
2026-5-1, 2026/05/01, May 1, 2026, a bare 2026, a date-time, and
impossible dates such as 2026-02-30.
^\d{4}-\d{2}-\d{2}$Inclusive end date, as a real calendar date in YYYY-MM-DD.
Validated by the same rule as date_from.
^\d{4}-\d{2}-\d{2}$Start a fixed-watermark incremental export after this insight-row update
timestamp. Cannot be combined with offset or cursor.
Must be a timezone-qualified ISO 8601 date-time - the offset is
required, so 2026-05-01T00:00:00 (no Z or +hh:mm) is rejected
with 400 VALIDATION_ERROR, as is a date-only value.
Opaque continuation cursor returned by the prior incremental page. A cursor
request may include only cursor and limit. It is bound to the team, exact
API key, filters, and watermark.
8192Page size (max 200).
1 <= x <= 200Number of records to skip.
x >= 0