curl --request POST \
--url https://developer.synq.io/api/overlays/v1/coverage \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"publicQuery": {
"parts": [
{
"entityIds": {
"entityIds": [
"<string>"
]
}
}
]
}
},
"pagination": {
"cursor": "<string>",
"pageSize": 1
}
}
'import requests
url = "https://developer.synq.io/api/overlays/v1/coverage"
payload = {
"selection": { "publicQuery": { "parts": [{ "entityIds": { "entityIds": ["<string>"] } }] } },
"pagination": {
"cursor": "<string>",
"pageSize": 1
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
selection: {publicQuery: {parts: [{entityIds: {entityIds: ['<string>']}}]}},
pagination: {cursor: '<string>', pageSize: 1}
})
};
fetch('https://developer.synq.io/api/overlays/v1/coverage', 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://developer.synq.io/api/overlays/v1/coverage",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'publicQuery' => [
'parts' => [
[
'entityIds' => [
'entityIds' => [
'<string>'
]
]
]
]
]
],
'pagination' => [
'cursor' => '<string>',
'pageSize' => 1
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://developer.synq.io/api/overlays/v1/coverage"
payload := strings.NewReader("{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://developer.synq.io/api/overlays/v1/coverage")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://developer.synq.io/api/overlays/v1/coverage")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}"
response = http.request(request)
puts response.read_body{
"entities": [
{
"entityId": "<string>",
"ownerEntityIds": [
"<string>"
],
"dataproductEntityIds": [
"<string>"
]
}
],
"totalCount": 123,
"pageInfo": {
"totalCount": 123,
"count": 123,
"lastId": "<string>"
},
"renderedResolverQl": "<string>",
"membersComputedAt": "2023-01-15T01:30:15.01Z"
}ListEntityCoverage
List the candidate assets together with the overlays claiming each, and narrow them to what is or is not covered.
This is the question behind a governance audit: of the assets you care
about, which belong to no data product, and which have nobody responsible
for them. You give the candidate set as a query — every asset, one
platform, one folder, one domain — and each row comes back carrying the
same owner and data-product lists BatchGetEntityOverlays returns, so a
single call is both the count and the worklist.
total_count is how many candidates match filter across every page, so
you can say “312 of 4,190 tables are in no data product” without paging to
the end.
Freshness. By default this reads the same periodically recomputed
membership the rest of this service reads, and tells you how old it is in
members_computed_at. Ask for FRESHNESS_LIVE when the answer has to
reflect every definition as of now — it re-resolves them, which is far
slower and far more expensive, so keep it for a one-off audit rather than a
page that refreshes.
Returns PERMISSION_DENIED if your credential can read neither data products
nor owners, and also if filter names a kind it may not read: an empty list
must not be the answer to both “nothing is uncovered” and “you may not
look”. A kind you may not read still comes back as an empty list on each
row, as it does elsewhere in this service.
Returns INVALID_ARGUMENT if the selection resolves to more assets than one
call will report on — see CoverageSelection for the limit and for how to
choose a candidate set worth reading.
curl --request POST \
--url https://developer.synq.io/api/overlays/v1/coverage \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"publicQuery": {
"parts": [
{
"entityIds": {
"entityIds": [
"<string>"
]
}
}
]
}
},
"pagination": {
"cursor": "<string>",
"pageSize": 1
}
}
'import requests
url = "https://developer.synq.io/api/overlays/v1/coverage"
payload = {
"selection": { "publicQuery": { "parts": [{ "entityIds": { "entityIds": ["<string>"] } }] } },
"pagination": {
"cursor": "<string>",
"pageSize": 1
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
selection: {publicQuery: {parts: [{entityIds: {entityIds: ['<string>']}}]}},
pagination: {cursor: '<string>', pageSize: 1}
})
};
fetch('https://developer.synq.io/api/overlays/v1/coverage', 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://developer.synq.io/api/overlays/v1/coverage",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'publicQuery' => [
'parts' => [
[
'entityIds' => [
'entityIds' => [
'<string>'
]
]
]
]
]
],
'pagination' => [
'cursor' => '<string>',
'pageSize' => 1
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://developer.synq.io/api/overlays/v1/coverage"
payload := strings.NewReader("{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://developer.synq.io/api/overlays/v1/coverage")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://developer.synq.io/api/overlays/v1/coverage")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"publicQuery\": {\n \"parts\": [\n {\n \"entityIds\": {\n \"entityIds\": [\n \"<string>\"\n ]\n }\n }\n ]\n }\n },\n \"pagination\": {\n \"cursor\": \"<string>\",\n \"pageSize\": 1\n }\n}"
response = http.request(request)
puts response.read_body{
"entities": [
{
"entityId": "<string>",
"ownerEntityIds": [
"<string>"
],
"dataproductEntityIds": [
"<string>"
]
}
],
"totalCount": 123,
"pageInfo": {
"totalCount": 123,
"count": 123,
"lastId": "<string>"
},
"renderedResolverQl": "<string>",
"membersComputedAt": "2023-01-15T01:30:15.01Z"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
The assets to report on. Required.
- public_query
- resolver_ql
Show child attributes
Show child attributes
Which coverage state to keep. Defaults to all candidates.
A filter naming a kind your credential may not read is PERMISSION_DENIED rather than an empty list.
COVERAGE_FILTER_UNSPECIFIED, COVERAGE_FILTER_WITHOUT_DATAPRODUCT, COVERAGE_FILTER_WITHOUT_OWNER, COVERAGE_FILTER_WITHOUT_ANY, COVERAGE_FILTER_WITH_DATAPRODUCT, COVERAGE_FILTER_WITH_OWNER Where the answer is computed from. Defaults to the recomputed membership.
FRESHNESS_UNSPECIFIED, FRESHNESS_CACHED, FRESHNESS_LIVE Pagination over the candidates matching filter.
Show child attributes
Show child attributes
Response
Success
One page of matching candidates, each with the overlays claiming it.
The same message BatchGetEntityOverlays returns: a row under
COVERAGE_FILTER_WITHOUT_DATAPRODUCT has an empty
dataproduct_entity_ids and may still name owners, which is how "owned but
in no product" reads without a second call.
Show child attributes
Show child attributes
How many candidates match filter across every page. Independent of
pagination — the number to show beside a list, not the length of it.
Pagination cursor for the next page.
Show child attributes
Show child attributes
The candidate selection rendered back to canonical resolver query language, whichever form it was sent in. Useful to log what was actually asked, and to lift a query built with the structured form into one you can hand-edit.
Empty when the selection has no resolver-QL representation; the answer is unaffected.
When the recomputation behind this answer last ran to completion — the start of the most recent successful pass over the workspace's overlays. Every overlay is recomputed on each pass, so this is the age of the whole answer rather than of any one overlay in it.
This is the number to alert on: it stops advancing as soon as the recomputation stops succeeding, whether or not any membership has changed.
Absent under FRESHNESS_LIVE (nothing was read from an index), and absent
when no overlay of a readable kind exists in the workspace, or none has
been computed yet (there is no membership to be stale).
"2023-01-15T01:30:15.01Z"
"2024-12-25T12:00:00Z"