研究及附来源简报
读取研究收集历史
读取有界限的 UTC 群组观察;未知不等于零。部分 HN 样本不适合用来判断动能或预测。需要 agent:research。
POST /research-api/collection-history/query契约审核日期: · sha256:ab393e91e9b7f18a
概览
读取有界限的 UTC 群组观察;未知不等于零。部分 HN 样本不适合用来判断动能或预测。需要 agent:research。
成功 HTTP 响应可能表示请求已接受,并非已完成。背景工作请存储返回 ID,持续检查同一操作直到完成。已排程或已接受的帖子,只有平台确认后才算已发布;客户端逾时无法证明结果。
验证与权限
令牌只能使用其所有者持有的权利。每次请求会检查工作区成员资格、资源拥有权、所选工作区及已授予能力。core 与 full 配置只变更显示的工具,不会授予访问权限。
请求字段
「必填」是指在其父对象及所选分支内必填。必填子字段不会使可选父对象变成必填。下列规则与字段名称均复制自契约。
| 字段 / 分支 | 类型 / 必填 | 约束 |
|---|---|---|
$ | object在父对象中必填 |
|
workspace_id | string在父对象中必填 |
|
project_id | string在父对象中必填 |
|
project_revision | integer在父对象中必填 |
|
corpus_snapshot_id | string在父对象中必填 |
|
bucket | string可选/项目 |
|
since | string在父对象中必填 |
|
until | string在父对象中必填 |
|
完整 JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"workspace_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"project_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"project_revision": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"corpus_snapshot_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"bucket": {
"default": "day",
"type": "string",
"enum": [
"hour",
"day"
]
},
"since": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"until": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
}
},
"required": [
"workspace_id",
"project_id",
"project_revision",
"corpus_snapshot_id",
"since",
"until"
],
"additionalProperties": false
}响应与完成
成功 HTTP 状态:200。操作完成时: current authorized aggregate collection history for one exact source cohort; collection counts are not publication volume, market growth, momentum or forecasts.
成功 HTTP 响应可能表示请求已接受,并非已完成。背景工作请存储返回 ID,持续检查同一操作直到完成。已排程或已接受的帖子,只有平台确认后才算已发布;客户端逾时无法证明结果。
「必填」是指在其父对象及所选分支内必填。必填子字段不会使可选父对象变成必填。下列规则与字段名称均复制自契约。
| 字段 / 分支 | 类型 / 必填 | 约束 |
|---|---|---|
$ | object在父对象中必填 | — |
workspace_id | string在父对象中必填 |
|
project_id | string在父对象中必填 |
|
project_revision | integer在父对象中必填 |
|
corpus_snapshot_id | string在父对象中必填 |
|
bucket | string在父对象中必填 |
|
since | string在父对象中必填 |
|
until | string在父对象中必填 |
|
generated_at | string在父对象中必填 |
|
status | string在父对象中必填 |
|
reason | string | null在父对象中必填 | — |
reasonanyOf 1 | string在父对象中必填 |
|
reasonanyOf 2 | null在父对象中必填 | — |
cohort | object | null在父对象中必填 | — |
cohortanyOf 1 | object在父对象中必填 | — |
cohort.sourceanyOf 1 | string在父对象中必填 |
|
cohort.query_revisionanyOf 1 | integer在父对象中必填 |
|
cohort.generationanyOf 1 | integer在父对象中必填 |
|
cohort.method_versionanyOf 1 | string在父对象中必填 |
|
cohort.selected_listening_refsanyOf 1 | integer在父对象中必填 |
|
cohort.excluded_selected_itemsanyOf 1 | integer在父对象中必填 |
|
cohort.scopeanyOf 1 | string在父对象中必填 |
|
cohortanyOf 2 | null在父对象中必填 | — |
method_version | string在父对象中必填 |
|
time_basis | string在父对象中必填 |
|
deduplication | string在父对象中必填 |
|
count_meaning | string在父对象中必填 |
|
momentum_eligible | boolean在父对象中必填 |
|
forecast_eligible | boolean在父对象中必填 |
|
qualification_reason | string在父对象中必填 |
|
observed_bins | integer在父对象中必填 |
|
unknown_bins | integer在父对象中必填 |
|
bins | array在父对象中必填 |
|
bins[] | object可选/项目 | — |
bins[].start | string在父对象中必填 |
|
bins[].end | string在父对象中必填 |
|
bins[].period_partial | boolean在父对象中必填 | — |
bins[].state | string在父对象中必填 |
|
bins[].counts | object | null在父对象中必填 | — |
bins[].countsanyOf 1 | object在父对象中必填 | — |
bins[].counts.source_itemsanyOf 1 | integer在父对象中必填 |
|
bins[].counts.matched_itemsanyOf 1 | integer在父对象中必填 |
|
bins[].counts.removed_itemsanyOf 1 | integer在父对象中必填 |
|
bins[].counts.unavailable_itemsanyOf 1 | integer在父对象中必填 |
|
bins[].countsanyOf 2 | null在父对象中必填 | — |
bins[].runs | object在父对象中必填 | — |
bins[].runs.total | integer在父对象中必填 |
|
bins[].runs.completed | integer在父对象中必填 |
|
bins[].runs.successful | integer在父对象中必填 |
|
bins[].runs.succeeded | integer在父对象中必填 |
|
bins[].runs.partial | integer在父对象中必填 |
|
bins[].runs.failed | integer在父对象中必填 |
|
bins[].runs.cancelled | integer在父对象中必填 |
|
bins[].runs.pending | integer在父对象中必填 |
|
bins[].source_windows | object | null在父对象中必填 | — |
bins[].source_windowsanyOf 1 | object在父对象中必填 | — |
bins[].source_windows.sinceanyOf 1 | string在父对象中必填 |
|
bins[].source_windows.untilanyOf 1 | string在父对象中必填 |
|
bins[].source_windows.distinct_windowsanyOf 1 | integer在父对象中必填 |
|
bins[].source_windowsanyOf 2 | null在父对象中必填 | — |
bins[].gaps | array在父对象中必填 |
|
bins[].gaps[] | string可选/项目 |
|
bins[].coverage | string在父对象中必填 |
|
完整 JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"workspace_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"project_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"project_revision": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"corpus_snapshot_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"bucket": {
"type": "string",
"enum": [
"hour",
"day"
]
},
"since": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"until": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"generated_at": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"status": {
"type": "string",
"enum": [
"available",
"insufficient_history",
"not_applicable",
"incomparable"
]
},
"reason": {
"anyOf": [
{
"type": "string",
"enum": [
"no_listening_sources",
"mixed_sources",
"mixed_cohorts",
"mixed_methods",
"method_unavailable",
"unsupported_method",
"no_completed_observations",
"history_limit"
]
},
{
"type": "null"
}
]
},
"cohort": {
"anyOf": [
{
"type": "object",
"properties": {
"source": {
"type": "string",
"const": "hacker_news"
},
"query_revision": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"generation": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"method_version": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"selected_listening_refs": {
"type": "integer",
"minimum": 1,
"maximum": 500
},
"excluded_selected_items": {
"type": "integer",
"minimum": 0,
"maximum": 499
},
"scope": {
"type": "string",
"const": "selected_listening_stream_cohort"
}
},
"required": [
"source",
"query_revision",
"generation",
"method_version",
"selected_listening_refs",
"excluded_selected_items",
"scope"
]
},
{
"type": "null"
}
]
},
"method_version": {
"type": "string",
"const": "listening-collection-history/v1"
},
"time_basis": {
"type": "string",
"const": "collection_completed_at_or_requested_at"
},
"deduplication": {
"type": "string",
"const": "latest_observation_per_source_per_bin"
},
"count_meaning": {
"type": "string",
"const": "bounded_collection_observations"
},
"momentum_eligible": {
"type": "boolean",
"const": false
},
"forecast_eligible": {
"type": "boolean",
"const": false
},
"qualification_reason": {
"type": "string",
"enum": [
"hn_partial_overlapping_sample_unqualified",
"no_qualified_cohort"
]
},
"observed_bins": {
"type": "integer",
"minimum": 0,
"maximum": 24
},
"unknown_bins": {
"type": "integer",
"minimum": 0,
"maximum": 24
},
"bins": {
"maxItems": 24,
"type": "array",
"items": {
"type": "object",
"properties": {
"start": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"end": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"period_partial": {
"type": "boolean"
},
"state": {
"type": "string",
"enum": [
"observed",
"unknown"
]
},
"counts": {
"anyOf": [
{
"type": "object",
"properties": {
"source_items": {
"type": "integer",
"minimum": 0,
"maximum": 10240
},
"matched_items": {
"type": "integer",
"minimum": 0,
"maximum": 10240
},
"removed_items": {
"type": "integer",
"minimum": 0,
"maximum": 10240
},
"unavailable_items": {
"type": "integer",
"minimum": 0,
"maximum": 10240
}
},
"required": [
"source_items",
"matched_items",
"removed_items",
"unavailable_items"
]
},
{
"type": "null"
}
]
},
"runs": {
"type": "object",
"properties": {
"total": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"completed": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"successful": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"succeeded": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"partial": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"failed": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"cancelled": {
"type": "integer",
"minimum": 0,
"maximum": 512
},
"pending": {
"type": "integer",
"minimum": 0,
"maximum": 512
}
},
"required": [
"total",
"completed",
"successful",
"succeeded",
"partial",
"failed",
"cancelled",
"pending"
]
},
"source_windows": {
"anyOf": [
{
"type": "object",
"properties": {
"since": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"until": {
"type": "string",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"format": "date-time"
},
"distinct_windows": {
"type": "integer",
"minimum": 1,
"maximum": 512
}
},
"required": [
"since",
"until",
"distinct_windows"
]
},
{
"type": "null"
}
]
},
"gaps": {
"maxItems": 5,
"type": "array",
"items": {
"type": "string",
"enum": [
"unobserved",
"incomplete_collection",
"failed_collection",
"cancelled_collection",
"partial_period"
]
}
},
"coverage": {
"type": "string",
"const": "partial_indexed_sample"
}
},
"required": [
"start",
"end",
"period_partial",
"state",
"counts",
"runs",
"source_windows",
"gaps",
"coverage"
]
}
}
},
"required": [
"workspace_id",
"project_id",
"project_revision",
"corpus_snapshot_id",
"bucket",
"since",
"until",
"generated_at",
"status",
"reason",
"cohort",
"method_version",
"time_basis",
"deduplication",
"count_meaning",
"momentum_eligible",
"forecast_eligible",
"qualification_reason",
"observed_bins",
"unknown_bins",
"bins"
]
}错误与安全重试
检查 HTTP 状态和响应正文。400 验证错误可能包含 ZodError;处理程序错误使用 error、message 和 code 字段。保留 request_id 或 x-request-id 以便诊断,但不要保留凭证。先解决 401/403 访问错误再重试,并在收到 429 时遵循 Retry-After。如写入结果不确定或返回 5xx,先读取现有结果。仅在支持时复用幂等键;重试行为因操作而异,并不保证恰好交付一次。
故障排查指南示例
这些示例使用已依schema检查的虚构值。请将 ID 替换为你有权使用的 ID、将媒体替换为已就绪素材,并将日期替换为已确认的发布时间。提交写入前,请检查账号资格。本页不会发送 API 请求。
在服务器上将 SOSOAPI_ACCESS_TOKEN 设为此操作接受的凭证,且不要放入浏览器代码。AI 智能代理 请使用 sosoapi auth login 通过浏览器登录,并由 CLI 更新凭证。
request.json
{
"workspace_id": "11111111-1111-4111-8111-111111111111",
"project_id": "30000000-0000-4000-8000-000000000001",
"project_revision": 1,
"corpus_snapshot_id": "30000000-0000-4000-8000-000000000002",
"bucket": "day",
"since": "2026-11-01T00:00:00Z",
"until": "2026-11-02T00:00:00Z"
}cURL
curl --request POST \
"https://gqeshlawtcexsapabaui.supabase.co/functions/v1/research-api/collection-history/query" \
-H "Authorization: Bearer $SOSOAPI_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @request.jsonJavaScript
// Server-side JavaScript. Do not print tokens or credential-bearing responses.
const token = process.env.SOSOAPI_ACCESS_TOKEN;
if (!token) throw new Error("Set an accepted credential for this operation");
const response = await fetch("https://gqeshlawtcexsapabaui.supabase.co/functions/v1/research-api/collection-history/query", {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: "Bearer " + token },
body: JSON.stringify({
"workspace_id": "11111111-1111-4111-8111-111111111111",
"project_id": "30000000-0000-4000-8000-000000000001",
"project_revision": 1,
"corpus_snapshot_id": "30000000-0000-4000-8000-000000000002",
"bucket": "day",
"since": "2026-11-01T00:00:00Z",
"until": "2026-11-02T00:00:00Z"
})
});
const result = await response.json();
// Check response.ok, the operation-specific body and completion state before continuing.CLI
npx sosoapi api post /research-api/collection-history/query < request.json合成响应示例
{
"workspace_id": "11111111-1111-4111-8111-111111111111",
"project_id": "30000000-0000-4000-8000-000000000001",
"project_revision": 1,
"corpus_snapshot_id": "30000000-0000-4000-8000-000000000002",
"bucket": "day",
"since": "2026-11-01T00:00:00Z",
"until": "2026-11-02T00:00:00Z",
"generated_at": "2026-11-03T00:00:00Z",
"status": "insufficient_history",
"reason": "no_completed_observations",
"cohort": {
"source": "hacker_news",
"query_revision": 1,
"generation": 1,
"method_version": "hn-indexed-literal-sample/v1",
"selected_listening_refs": 1,
"excluded_selected_items": 0,
"scope": "selected_listening_stream_cohort"
},
"method_version": "listening-collection-history/v1",
"time_basis": "collection_completed_at_or_requested_at",
"deduplication": "latest_observation_per_source_per_bin",
"count_meaning": "bounded_collection_observations",
"momentum_eligible": false,
"forecast_eligible": false,
"qualification_reason": "hn_partial_overlapping_sample_unqualified",
"observed_bins": 0,
"unknown_bins": 1,
"bins": [
{
"start": "2026-11-01T00:00:00Z",
"end": "2026-11-02T00:00:00Z",
"period_partial": false,
"state": "unknown",
"counts": null,
"runs": {
"total": 0,
"completed": 0,
"successful": 0,
"succeeded": 0,
"partial": 0,
"failed": 0,
"cancelled": 0,
"pending": 0
},
"source_windows": null,
"gaps": [
"unobserved"
],
"coverage": "partial_indexed_sample"
}
]
}