Signals

For instructions on how to authenticate to use this endpoint, see API overview.

Endpoints

GET
PATCH
DELETE
GET
GET
GET
DELETE
POST
POST
GET
POST
GET
POST
POST
GET
POST
POST
POST
GET
POST

Retrieve signals report artefacts

Get one artefact by id, content parsed (and reviewers enriched) the same way as the list. A ranking_score keeps its full model metadata.

Required API key scopes

task:read

Path parameters

  • id
    string
  • report_id
    string

Response


Example request

GET /api/projects/:project_id/signals/reports/:report_id/artefacts/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/artefacts/:id/

Example response

Status 200
RESPONSE
{
"claim_id": "6ed32748-64af-4d95-94ea-a78b6397033c",
"pull_request_id": "5c951947-9b15-4693-a43b-42f8e37fd0d1",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"type": "video_segment",
"content": {},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"actor_kind": "user",
"actor_agent": "string",
"created_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"first_name": "string",
"last_name": "string",
"email": "user@example.com"
},
"task_id": "736fde4d-9029-4915-8189-01353d6982cb"
}

Update signals report artefacts

Replace the content of an existing artefact, addressed by id. The new content is validated against the artefact's type schema. Editing the latest row of a status type changes the report's canonical status (latest-wins); to re-assess while keeping history, append a new artefact instead. Attribution is creation-time only — edits don't reassign it.

Required API key scopes

task:write

Path parameters

  • id
    string
  • report_id
    string

Request parameters

  • content

Response


Example request

PATCH /api/projects/:project_id/signals/reports/:report_id/artefacts/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X PATCH \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/artefacts/:id/\
-d content=undefined

Example response

Status 200 Artefact updated.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"claim_id": "6ed32748-64af-4d95-94ea-a78b6397033c",
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"type": "string",
"content": null,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"task_id": "736fde4d-9029-4915-8189-01353d6982cb"
}
Status 400 Content does not match the artefact type's schema.
Status 404 Artefact not found for this report / project.

Delete signals report artefacts

Delete an artefact, addressed by id. Deleting the latest row of a status type reverts the report's canonical status to the previous version (latest-wins over what remains). task_run artefacts are an append-only work log and cannot be deleted. Neither can the types this API cannot write, which the pipeline owns: autostart_skip, check_cancelled, check_expired, check_observation, check_result, check_scheduled, code_review, impact_measurement_plan, implementation_decision, implementation_dispatch, implementation_handover, implementation_replacement, pull_request, ranking_score, report_link, reviewer_corrections, summary_change, task_run, title_change, video_segment, work_claim, work_release.

Required API key scopes

task:write

Path parameters

  • id
    string
  • report_id
    string

Example request

DELETE /api/projects/:project_id/signals/reports/:report_id/artefacts/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X DELETE \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/artefacts/:id/

Example response

Status 204 Artefact deleted.
Status 400 Artefact type cannot be deleted through the API.
Status 404 Artefact not found for this report / project.

Retrieve signals report artefacts

Fetch the unified diff for a commit artefact via the team's GitHub integration. A commit linked to a report pull request uses GitHub's durable pull request diff. A commit without that link compares the branch's current tip with the default branch.

Required API key scopes

task:read

Path parameters

  • id
    string
  • report_id
    string

Response


Example request

GET /api/projects/:project_id/signals/reports/:report_id/artefacts/:id/diff
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/artefacts/:id/diff/

Example response

Status 200 The pull request diff, or the branch diff when no pull request is linked.
RESPONSE
{
"diff": "string",
"truncated": true
}
Status 400 Artefact is not a commit, or is missing repository/branch.
Status 404 Artefact not found, or no GitHub integration can access the repository.
Status 502 GitHub could not produce the diff (branch not found, fetch failed).

List all signals report checks

List the forward-looking checks on a report. A check says what must stay true after the report was acted on, and the coordinator records each verdict as a check_result artefact on the report.

Required API key scopes

task:read

Path parameters

  • report_id
    string

Query parameters

  • limit
    integer
  • offset
    integer

Response


Example request

GET /api/projects/:project_id/signals/reports/:report_id/checks
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/checks/

Example response

Status 200
RESPONSE
{
"count": 123,
"next": "http://api.example.org/accounts/?offset=400&limit=100",
"previous": "http://api.example.org/accounts/?offset=200&limit=100",
"results": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"rationale": "string",
"kind": "metric_threshold",
"status": "pending",
"config": {
"metric_id": null,
"query": null,
"monitoring": null,
"comparison": {
"operator": "lte",
"value": null,
"bounds": null
},
"baseline_value": null,
"metric_kind": null,
"value_format": null,
"unit": null
},
"monitoring_timing": {
"state": "scheduled",
"started_at": "2019-08-24T14:15:22Z",
"ends_at": "2019-08-24T14:15:22Z",
"next_measurement_at": "2019-08-24T14:15:22Z"
},
"approved_at": "2019-08-24T14:15:22Z",
"next_run_at": "2019-08-24T14:15:22Z",
"soak_minutes": 0,
"run_interval_minutes": 0,
"runs_remaining": 0,
"expires_at": "2019-08-24T14:15:22Z",
"last_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "passed",
"last_outcome_reason": "awaiting_data",
"dispatched_at": "2019-08-24T14:15:22Z",
"consecutive_errors": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
]
}

Retrieve signals report checks

Checks attached to a signal report: read, approve, replace metrics, and cancel.

There is no create here. A check is authored by a scout run or by the research pipeline, both through report_check_authoring.create_check. An agent check puts its author's prose in front of a privileged scout run, and task:write does not authorize that, so no caller-facing endpoint accepts one. Anyone who can read the report can read its checks, and a person can still stop one.

There is no in-place update: a check is a claim about the future, and editing its threshold after a result would make the recorded verdict unreadable. Replacing an open metric check cancels the old row and creates a new one in one transaction.

Required API key scopes

task:read

Path parameters

  • id
    string
  • report_id
    string

Response


Example request

GET /api/projects/:project_id/signals/reports/:report_id/checks/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/checks/:id/

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"rationale": "string",
"kind": "metric_threshold",
"status": "pending",
"config": {
"metric_id": null,
"query": null,
"monitoring": null,
"comparison": {
"operator": "lte",
"value": null,
"bounds": null
},
"baseline_value": null,
"metric_kind": null,
"value_format": null,
"unit": null
},
"monitoring_timing": {
"state": "scheduled",
"started_at": "2019-08-24T14:15:22Z",
"ends_at": "2019-08-24T14:15:22Z",
"next_measurement_at": "2019-08-24T14:15:22Z"
},
"approved_at": "2019-08-24T14:15:22Z",
"next_run_at": "2019-08-24T14:15:22Z",
"soak_minutes": 0,
"run_interval_minutes": 0,
"runs_remaining": 0,
"expires_at": "2019-08-24T14:15:22Z",
"last_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "passed",
"last_outcome_reason": "awaiting_data",
"dispatched_at": "2019-08-24T14:15:22Z",
"consecutive_errors": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Delete signals report checks

Stop a check that is still open — active, or pending its report resolving. Its recorded results stay on the report.

Required API key scopes

task:write

Path parameters

  • id
    string
  • report_id
    string

Response


Example request

DELETE /api/projects/:project_id/signals/reports/:report_id/checks/:id
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl -X DELETE \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/checks/:id/

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"rationale": "string",
"kind": "metric_threshold",
"status": "pending",
"config": {
"metric_id": null,
"query": null,
"monitoring": null,
"comparison": {
"operator": "lte",
"value": null,
"bounds": null
},
"baseline_value": null,
"metric_kind": null,
"value_format": null,
"unit": null
},
"monitoring_timing": {
"state": "scheduled",
"started_at": "2019-08-24T14:15:22Z",
"ends_at": "2019-08-24T14:15:22Z",
"next_measurement_at": "2019-08-24T14:15:22Z"
},
"approved_at": "2019-08-24T14:15:22Z",
"next_run_at": "2019-08-24T14:15:22Z",
"soak_minutes": 0,
"run_interval_minutes": 0,
"runs_remaining": 0,
"expires_at": "2019-08-24T14:15:22Z",
"last_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "passed",
"last_outcome_reason": "awaiting_data",
"dispatched_at": "2019-08-24T14:15:22Z",
"consecutive_errors": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Create signals report checks approve

Record a person's quality signal. Approval does not affect scheduling or execution.

Required API key scopes

task:write

Path parameters

  • id
    string
  • report_id
    string

Response


Example request

POST /api/projects/:project_id/signals/reports/:report_id/checks/:id/approve
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/checks/:id/approve/

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"rationale": "string",
"kind": "metric_threshold",
"status": "pending",
"config": {
"metric_id": null,
"query": null,
"monitoring": null,
"comparison": {
"operator": "lte",
"value": null,
"bounds": null
},
"baseline_value": null,
"metric_kind": null,
"value_format": null,
"unit": null
},
"monitoring_timing": {
"state": "scheduled",
"started_at": "2019-08-24T14:15:22Z",
"ends_at": "2019-08-24T14:15:22Z",
"next_measurement_at": "2019-08-24T14:15:22Z"
},
"approved_at": "2019-08-24T14:15:22Z",
"next_run_at": "2019-08-24T14:15:22Z",
"soak_minutes": 0,
"run_interval_minutes": 0,
"runs_remaining": 0,
"expires_at": "2019-08-24T14:15:22Z",
"last_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "passed",
"last_outcome_reason": "awaiting_data",
"dispatched_at": "2019-08-24T14:15:22Z",
"consecutive_errors": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Create signals report checks replace

Atomically replace an open metric check. The old check stays live if the new one is invalid.

Required API key scopes

task:writequery:read

Path parameters

  • id
    string
  • report_id
    string

Request parameters

  • title
    string
  • rationale
    string
  • config

Response


Example request

POST /api/projects/:project_id/signals/reports/:report_id/checks/:id/replace
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/:report_id/checks/:id/replace/\
-d title="string",\
-d config=undefined

Example response

Status 200
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"rationale": "string",
"kind": "metric_threshold",
"status": "pending",
"config": {
"metric_id": null,
"query": null,
"monitoring": null,
"comparison": {
"operator": "lte",
"value": null,
"bounds": null
},
"baseline_value": null,
"metric_kind": null,
"value_format": null,
"unit": null
},
"monitoring_timing": {
"state": "scheduled",
"started_at": "2019-08-24T14:15:22Z",
"ends_at": "2019-08-24T14:15:22Z",
"next_measurement_at": "2019-08-24T14:15:22Z"
},
"approved_at": "2019-08-24T14:15:22Z",
"next_run_at": "2019-08-24T14:15:22Z",
"soak_minutes": 0,
"run_interval_minutes": 0,
"runs_remaining": 0,
"expires_at": "2019-08-24T14:15:22Z",
"last_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "passed",
"last_outcome_reason": "awaiting_data",
"dispatched_at": "2019-08-24T14:15:22Z",
"consecutive_errors": 0,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Retrieve signals reports available reviewers

Required API key scopes

task:read

Query parameters

  • query
    string

Example request

GET /api/projects/:project_id/signals/reports/available_reviewers
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/available_reviewers/

Example response

Status 200 Candidate reviewers keyed by user UUID.

Create signals reports bulk state

Transition many reports to a new state in one call.

Each id is processed independently: a report whose transition isn't allowed from its current status is reported as skipped (a 409 on the single-report endpoint) and the rest still go through. Returns one result per requested id (in request order, after de-duplication) plus per-outcome counts. The whole call is 200 even on partial failure — inspect results / the counts to see what happened.

Required API key scopes

task:write

Request parameters

  • state
  • dismissal_reason
  • dismissal_note
    string
  • corrected_repository
    string
  • snooze_for
    integer
  • ids
    array

Response


Example request

POST /api/projects/:project_id/signals/reports/bulk-state
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/bulk-state/\
-d state=undefined,\
-d ids="array"

Example response

Status 200
RESPONSE
{
"results": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"outcome": "string",
"status": "string",
"detail": "string"
}
],
"transitioned_count": 0,
"skipped_count": 0,
"failed_count": 0,
"not_found_count": 0
}

Retrieve signals reports pr ci

Resolve the coarse CI rollup of the pull requests several reports opened, so a list of reports can show which pull requests are red without opening each report. One GitHub call covers the whole batch, and the answers are cached briefly and shared across callers. A report is left out when it has no open implementation pull request, and also when GitHub could not answer for it (no integration reaches the repository, a rate limit, an upstream failure), so a caller shows no CI state for it rather than an error. For the individual checks behind the rollup, use pr_checks.

Required API key scopes

task:read

Query parameters

  • report_ids
    string

Response


Example request

GET /api/projects/:project_id/signals/reports/pr_ci_statuses
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/pr_ci_statuses/

Example response

Status 200 The CI rollup of each requested report's implementation pull request.
RESPONSE
{
"statuses": [
{
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"ci_status": "passing"
}
]
}
Status 400 `report_ids` is missing, not a list of UUIDs, or over the cap.

Create signals reports read state

Required API key scopes

task:read

Request parameters

  • report_ids
    array
  • read
    boolean

Response


Example request

POST /api/projects/:project_id/signals/reports/read_state
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/read_state/\
-d report_ids="array"

Example response

Status 200
RESPONSE
{
"states": {
"property1": true,
"property2": true
}
}

Create signals reports refresh metrics

Re-run the stored metric queries of the given reports through the query cache and save the newest values as their snapshots. Call it when a person opens the inbox list or a report, with the ids on screen. Report titles and summaries are point-in-time text and never change here; only value, value_at, and series do, and legacy comparisons are cleared. A snapshot measured in the last 15 minutes is served as is. Each call runs at most 40 source series inside a 20-second budget, row metrics first; the rest keep their previous snapshot until the next open. Returns snapshot-only metrics for every requested report the caller can read whose status is ready or pending_input. A report in any other status is left out of the response, and its saved snapshots stay as they are.

Required API key scopes

task:read

Request parameters

  • report_ids
    array

Response


Example request

POST /api/projects/:project_id/signals/reports/refresh_metrics
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/refresh_metrics/\
-d report_ids="array"

Example response

Status 200
RESPONSE
{
"reports": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"metrics": [
{
"metric_id": "string",
"title": "string",
"kind": "affected_users",
"role": "supporting",
"value": 0,
"value_at": "2019-08-24T14:15:22Z",
"series": [
0.1
],
"value_format": "number",
"unit": "string",
"caption": "string",
"goal_value": 0,
"goal_direction": "at_most",
"goal_grain": "whole_window",
"decision_window_days": 1,
"minimum_data_points": 1
}
]
}
]
}

Retrieve signals reports refund summary

Aggregate credited-path refunds across the whole organization for the current billing period — counts only, no per-team detail. The billing usage widget needs this because billing usage is org-wide while reports (and their refunds) are team-scoped: subtract the refunded credits from billing usage to show the net PR count. Excluded-path refunds never reach billing usage, so no adjustment is needed for them. Also carries the org's live billable credits for the period (billing's recorded usage lags by up to a day), so the widget can count just-created PRs and react to same-day refunds.

Required API key scopes

task:read

Response


Example request

GET /api/projects/:project_id/signals/reports/refund-summary
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/refund-summary/

Example response

Status 200 Org-wide credited-refund totals for the current billing period.
RESPONSE
{
"credited_refund_count": 0,
"credited_credits": 0,
"period_billable_credits": 0,
"quota_limited": true
}
Status 404 Refunds are not enabled for this organization.

Create signals reports source metadata

Read which source products contributed signals to each given report, and which scout authored it. These values come from ClickHouse, so the inbox list skips them (include_source_metadata=false) and calls this after the rows render. Returns one entry per requested id. An id with no signals in this project gets empty values.

Required API key scopes

task:read

Request parameters

  • report_ids
    array

Response


Example request

POST /api/projects/:project_id/signals/reports/source_metadata
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/reports/source_metadata/\
-d report_ids="array"

Example response

Status 200
RESPONSE
{
"reports": [
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"source_products": [
"string"
],
"scout_name": "string"
}
]
}

Create signals scout

Create a scout skill and its runnable config atomically. Give it a display_name — the label people read, kept exactly as written — and the scout's permanent skill name is generated from it, with a numeric suffix when that name is taken, so two scouts may share a label without sharing an identity. Pass name instead to pick that identifier yourself; any valid skill name works, since the config row is what makes a skill a scout. The skill always receives the report-channel tools. The optional config controls schedule, enablement, dry-run posture, network access, and typed destinations such as Slack. Repeating the same definition is safe and applies any supplied config fields; reusing an explicit name for a different definition returns 409.

Required API key scopes

llm_skill:writesignal_scout:write

Request parameters

  • display_name
    string
  • name
    string
  • description
    string
  • body
    string
  • files
    Click to open
    array
  • config
  • suggestion_id
    string

Response


Example request

POST /api/projects/:project_id/signals/scout
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/\
-d description="string",\
-d body="string"

Example response

Status 200 The scout definition already existed; the requested config fields were applied.
RESPONSE
{
"created": true,
"skill": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"name": "string",
"description": "string",
"version": 0,
"allowed_tools": [
"string"
]
},
"config": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
}
Status 201 The scout skill, config, or both were created.
RESPONSE
{
"created": true,
"skill": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"name": "string",
"description": "string",
"version": 0,
"allowed_tools": [
"string"
]
},
"config": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
}
Status 400 The scout definition, config, or destination is invalid.
Status 409 A scout with this name already exists with a different definition.

Create signals scout chat tasks

Create and run a cloud task for one of the fixed scout chat templates (suggest a scout, fleet overview, recent signals). The prompt is server-owned; an author_scout chat can carry the user's request, which the server fences inside that prompt. The response carries the task id to navigate to.

Required API key scopes

task:write

Request parameters

  • chat_type
  • suggestion_id
    string
  • user_prompt
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/chat_tasks
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/chat_tasks/\
-d chat_type=undefined

Example response

Status 201 Chat task created and run started
RESPONSE
{
"task_id": "736fde4d-9029-4915-8189-01353d6982cb"
}
Status 403 Organization has not approved AI data processing
Status 429 Team is over its posthog_code usage limit

List all signals scout config

List the per-(team, skill) scout configs for this project. Each row includes its display_name (the label people read), its skill_name (the permanent identifier), its schedule (rolling run_interval_minutes, or a project-local run_cron_schedule when set), enabled, emit posture, and tags. A freshly authored scout skill appears here once its config is registered, either explicitly via create or by the coordinator's next tick. Pass tags to narrow the fleet to the scouts carrying at least one of the given labels, and search to narrow it to the scouts matching a substring of either name.

Required API key scopes

signal_scout:read

Query parameters

  • search
    string
  • tags
    string

Example request

GET /api/projects/:project_id/signals/scout/configs
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl \
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/

Example response

Status 200 Per-scout configs for this project, ordered by the name each scout displays under.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}

Create signals scout config

Register the config for a skill immediately, without waiting for the coordinator to auto-register it — and the way to make a skill without the signals-scout- prefix a scout at all. The same call can optionally set run_interval_minutes, a cron run_cron_schedule, enabled, emit, network_access, and output destinations. The skill must already exist on this project. Upsert: if a config already exists for the skill, the provided fields are applied to it. Registering puts the skill's body on the schedule as the scout's prompt, so this call needs llm_skill:write and editor access to skills on top of signal_scout:write, like creating a scout.

Required API key scopes

signal_scout:writellm_skill:write

Request parameters

  • model
    string | null
  • tags
    array
  • structured_output_schema
    object | null
  • mcp_gateway_server_ids
    array
  • repositories
    array
  • write_scopes
    array
  • lifecycle_locked
    boolean
  • allowed_mcp_tools
    array | null
  • tool_preset
  • precheck_query
    string | null
  • enabled
    boolean
  • emit
    boolean
  • run_interval_minutes
    integer
  • output_destinations
  • network_access
  • auto_pause_exempt
    boolean
  • run_cron_schedule
    string | null
  • display_name
    string
  • skill_name
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/configs
export POSTHOG_PERSONAL_API_KEY=[your personal api key]
curl
-H 'Content-Type: application/json'\
-H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
<ph_app_host>/api/projects/:project_id/signals/scout/configs/\
-d skill_name="string"

Example response

Status 200 A config already existed for this skill; the provided fields were applied to it.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
Status 201 Created config.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"skill_name": "string",
"description": "string",
"display_name": "string",
"scout_origin": "canonical",
"scout_role": "specialist",
"deprecation": {
"phase": "announced",
"reason": "string",
"superseded_by": "string",
"sunset_at": "2019-08-24T14:15:22Z"
},
"owners": [
{
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
}
],
"enabled": true,
"status": "active",
"pause_reason": "no_output",
"managed_by": "team",
"emit": true,
"run_interval_minutes": 30,
"run_cron_schedule": "string",
"output_destinations": {
"slack": {
"integration_id": 1,
"channel": "string",
"users": [
"string"
],
"thread_reports": true
},
"webhook": {
"hog_function_id": "string"
},
"inbox": true
},
"structured_output_schema": {},
"network_access": "trusted",
"model": "string",
"mcp_gateway_server_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
],
"repositories": [
"string"
],
"write_scopes": [
"string"
],
"lifecycle_locked": true,
"allowed_mcp_tools": [
"string"
],
"tool_preset": "string",
"precheck_query": "string",
"precheck_disabled": true,
"effective_precheck_query": "string",
"precheck_query_source": "config",
"last_precheck_at": "2019-08-24T14:15:22Z",
"last_precheck_outcome": "run",
"last_precheck_row_count": 0,
"last_run_at": "2019-08-24T14:15:22Z",
"consecutive_failure_count": 0,
"status_changed_at": "2019-08-24T14:15:22Z",
"status_changed_by": {
"id": 0,
"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
"distinct_id": "string",
"first_name": "string",
"last_name": "string",
"email": "user@example.com",
"is_email_verified": true,
"hedgehog_config": {},
"role_at_organization": "engineering"
},
"auto_pause_exempt": true,
"tags": [
"string"
],
"source_product": "string",
"source_id": "string",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
}
Status 400 No such skill on this project, the name is reserved by the inbox, or the project is already at its enabled-scouts maximum.
Status 403 The caller lacks editor access to skills on this project.