Get Entity Research
curl --request GET \
--url https://api.shoal.xyz/v1/entities/:id/research \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.shoal.xyz/v1/entities/:id/research"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.shoal.xyz/v1/entities/:id/research', 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.shoal.xyz/v1/entities/:id/research",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.shoal.xyz/v1/entities/:id/research"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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.shoal.xyz/v1/entities/:id/research")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.shoal.xyz/v1/entities/:id/research")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyEntities
Get Entity Research
List research and commentary-classified entity content for one Shoal entity
GET
/
v1
/
entities
/
:id
/
research
Get Entity Research
curl --request GET \
--url https://api.shoal.xyz/v1/entities/:id/research \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.shoal.xyz/v1/entities/:id/research"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.shoal.xyz/v1/entities/:id/research', 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.shoal.xyz/v1/entities/:id/research",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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.shoal.xyz/v1/entities/:id/research"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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.shoal.xyz/v1/entities/:id/research")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.shoal.xyz/v1/entities/:id/research")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyReturns recent research-oriented items attached to one canonical Shoal entity.
This v1 surface is a projection over Shoal’s existing classified event stream.
It is meant to accumulate research, commentary, and analysis around the
canonical entity without requiring full historical backfill first.
Path Parameters
id(integer, required)
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
since | string | No | ISO 8601 timestamp; defaults to the last 30 days and cannot be older than 30 days |
limit | integer | No | Max results (default 25, max 25) |
offset | integer | No | Offset for the first page only (max 250) |
cursor | string | No | Shoal cursor for keyset pagination |
Request
cURL
curl -X GET "https://api.shoal.xyz/v1/entities/23151/research?limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
Response (200)
{
"entity": {
"id": 23151,
"canonicalName": "Ethereum",
"displayName": "Ethereum",
"entityType": "project",
"status": "active",
"aliases": ["Ethereum Foundation", "ETH"],
"references": []
},
"limit": 10,
"since": "2026-03-12T00:00:00Z",
"next_cursor": "eyJ0cyI6IjIwMjYtMDQtMTFUMTc6MjA6MDBaIiwiaWQiOjE4MjQsImNvbnRleHQiOnsic2luY2UiOiIyMDI2LTAzLTEyVDAwOjAwOjAwWiIsInNjb3BlIjoiZW50aXRpZXMvMjMxNTEvcmVzZWFyY2gifX0",
"data": [
{
"id": 1940,
"title": "Ethereum staking economics research note",
"eventCategory": "analysis",
"eventSubcategory": "research_report",
"summary": "A research note analyzed staking participation, validator concentration, and long-term token economics.",
"bullets": [
"Validator concentration remains a focus area.",
"Staking participation continues to support network security."
],
"owners": [
{
"id": 23151,
"label": "Ethereum",
"type": "project",
"aliases": ["ETH"]
}
],
"participants": [],
"evidence": [
{
"id": 778890,
"content": "Ethereum staking economics research note...",
"url": "https://example.com/post",
"timestamp": "2026-04-10T12:05:00Z"
}
],
"latestEvidenceTimestamp": "2026-04-10T12:05:00Z",
"significance": 6.2,
"sourceType": "classified_event",
"contentType": "research",
"eventSurface": "radar"
}
]
}
Notes
- This route is an operational surface.
- It is sourced from entity-linked events that Shoal already classifies as research, commentary, or analysis content.
- Shoal-authored long-form reports can be layered into this route later without changing the route contract.
Errors
- 400 if
idis missing - 400 if
sinceis older than 30 days - 404 if the entity does not exist
- 500 on internal server error
⌘I