研究及附來源簡報
讀取研究收集歷史
讀取有界限的 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,先讀取現有結果。僅在支援時重複使用冪等鍵;重試行為因操作而異,並不保證恰好傳送一次。
故障排查指南範例
這些範例使用已依結構描述檢查的虛構值。請將 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"
}
]
}