Signals

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

Endpoints

POST
POST
POST
POST
POST
POST
GET
GET
POST
GET
POST
GET
GET
GET
POST
GET
POST
POST
GET
POST

Create signals scout emit

The second emit channel: author a complete SignalReport directly instead of emitting a weak signal. The report passes the safety judge, then surfaces at the status the scout's actionability call implies (or is suppressed). Backing evidence is written as bound signals so the report behaves like a pipeline report. Safe to retry: resending an emission returns the report the first call authored (idempotent_replay true) rather than a second one, keyed on idempotency_key or, without one, on the report's content. Use reports to find a report from an earlier run and edit-report to update it instead of authoring a near-duplicate.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Request parameters

  • title
    string
  • summary
    string
  • evidence
    Click to open
    array
  • actionability_explanation
    string
  • actionability
  • already_addressed
    boolean
    Default: false
  • repository
    string | null
  • priority
  • priority_explanation
    string | null
  • suggested_reviewers
    Click to open
    array
  • charts
    Click to open
    array
  • metrics
    Click to open
    array
  • suggested_prompts
    array
  • links
    Click to open
    array
  • idempotency_key
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/emit-report
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/runs/:run_id/emit-report/\
-d title="string",\
-d summary="string",\
-d evidence="array",\
-d actionability_explanation="string",\
-d actionability=undefined

Example response

Status 200 Report authored (READY/PENDING_INPUT/suppressed), or skipped by a preflight gate.
RESPONSE
{
"report_id": "string",
"report_status": "string",
"emitted": true,
"skipped_reason": "string",
"safety_explanation": "string",
"remediation": "string",
"idempotent_replay": true
}
Status 400 Invalid report shape (empty title/summary/evidence, bad actionability).
Status 404 Run not found for this project.

Create signals scout emit

Fire emit_signal with source_product = signals_scout. The finding_id is baked into the deterministic Signal.source_id = run:<id>:finding:<id> for traceability, but this is NOT idempotent — a second call with the same finding_id emits a second signal, so do not retry an emit that may have already succeeded.

Required API key scopes

signal_scout_internal:write

Path parameters

  • run_id
    string

Request parameters

  • description
    string
  • evidence
    Click to open
    array
  • hypothesis
    string | null
  • severity
  • dedupe_keys
    array
  • tags
    array
  • time_range
  • mcp_trace_id
    string | null
  • finding_id
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/emit-signal
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/runs/:run_id/emit-signal/\
-d description="string",\
-d evidence="array"

Example response

Status 200 Finding emitted, or skipped by a preflight gate.
RESPONSE
{
"finding_id": "string",
"emitted": true,
"skipped_reason": "string",
"remediation": "string"
}
Status 400 Invalid emit shape (description, evidence cap).
Status 404 Run not found for this project.

Create signals scout lighthouse

Load one page in a real browser and return what makes it slow — most usefully the element the browser chose as the Largest Contentful Paint, and where the LCP time went. Field data says a route is slow; this says which element and why, so a finding can name it instead of guessing from source. Restricted to public PostHog pages: the browser signs in to nothing, so a page behind a login would report the login screen's numbers. One throttled cold load is not a p75 over real users — corroborate a field finding with it, never replace one. Capped at 5 audits per run.

Required API key scopes

signal_scout_internal:write

Path parameters

  • run_id
    string

Request parameters

  • url
    string
  • form_factor
    Default: desktop

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/lighthouse-audit
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/runs/:run_id/lighthouse-audit/\
-d url="string"

Example response

Status 200 The audit ran and the reduced report is attached.
RESPONSE
{
"requested_url": "string",
"final_url": "string",
"form_factor": "string",
"lighthouse_version": "string",
"performance_score": 0,
"metrics": {
"property1": 0.1,
"property2": 0.1
},
"lcp_element": {
"selector": "string",
"snippet": "string",
"node_label": "string"
},
"lcp_phases": [
{
"phase": "string",
"timing_ms": 0,
"percent": "string"
}
],
"lcp_checks_failed": [
{
"audit_id": "string",
"title": "string",
"savings_ms": 0
}
],
"opportunities": [
{
"audit_id": "string",
"title": "string",
"savings_ms": 0
}
],
"audits_remaining": 0
}
Status 400 The url is not on an allowed host, is not https, redirected off the allowed hosts (the login-wall case), the run is not in progress, or the run has spent its audit budget. Also returned when the page could not be loaded at all. Every message ends with how many audits the run has left, so a rejection is distinguishable from an exhausted budget.
Status 404 No such run in this project, or the run belongs to a different scout.
Status 429 Audit rate limit exceeded; retry later.
Status 501 Lighthouse audits are not configured on this deployment.
Status 503 The browser fleet is at capacity, so no audit ran and the run keeps the slot. Retry later.

Create signals scout record

The structured-output channel: record schema-validated records this run produced. Opt-in via the scout config's structured_output_schema (a JSON Schema describing one record) — without it the call fails closed, as it does for a dry-run scout (emit off). All-or-nothing: any invalid record fails the whole call with nothing written, so fix and resubmit the batch. Each accepted record lands in the project's event stream as a $scout_structured_output event — query them like any event (insights, SQL over events). Recording is idempotent: event ids are deterministic, so resubmitting an identical batch (e.g. retrying after a 503) cannot double-count.

Required API key scopes

signal_scout_internal:write

Path parameters

  • run_id
    string

Request parameters

  • records
    Click to open
    array

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/record-output
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/runs/:run_id/record-output/\
-d records="array"

Example response

Status 200 All records validated against the configured schema and recorded as events.
RESPONSE
{
"recorded_count": 0,
"record_ids": [
"497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}
Status 400 No structured_output_schema configured for this scout, the channel is off (dry-run scout, org AI-processing consent missing, or the signals_scout source disabled), a record failed schema validation (nothing written), or a batch/size cap was exceeded.
Status 404 Run not found for this project.
Status 503 The records validated but event delivery failed; nothing was recorded. Retry the same call — delivery is idempotent, so a retry cannot double-count.

Create signals scout report check

Stop a check that is no longer worth running — the claim it re-measures has changed, or a better check replaces it. Results it already recorded stay on the report. A check that has already finished cannot be cancelled.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Request parameters

  • check_id
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/report-check-cancel
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/runs/:run_id/report-check-cancel/\
-d check_id="string"

Example response

Status 200 Check cancelled.
RESPONSE
{
"check_id": "051490c8-9abf-480a-9348-72c146208cd5",
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"title": "string",
"kind": "string",
"status": "string",
"next_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "string",
"run_state": "string",
"waiting_on_run": true,
"dispatched_run_id": "0d40720c-3ac9-4b33-96ee-ba348f818515",
"dispatched_at": "2019-08-24T14:15:22Z"
}
Status 400 The check does not exist for this project, or already finished and cannot be cancelled.
Status 404 Run not found for this project.

Create signals scout report check

Schedule a re-measurement of a report's claim, so whether the fix held becomes a stored fact instead of something a future run has to remember to look for. A metric_threshold check runs one bounded Trends query and compares the result. An agent check runs a scout instead, for a claim no single number settles.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Request parameters

  • title
    string
  • rationale
    string
  • kind
  • config
  • next_run_at
    string
  • run_interval_minutes
    integer | null
  • runs_remaining
    integer
  • expires_at
    string
  • report_id
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/:run_id/report-check-create
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/runs/:run_id/report-check-create/\
-d title="string",\
-d kind=undefined,\
-d config=undefined,\
-d report_id="string"

Example response

Status 200 Check written on the report.
RESPONSE
{
"check_id": "051490c8-9abf-480a-9348-72c146208cd5",
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"title": "string",
"kind": "string",
"status": "string",
"next_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "string",
"run_state": "string",
"waiting_on_run": true,
"dispatched_run_id": "0d40720c-3ac9-4b33-96ee-ba348f818515",
"dispatched_at": "2019-08-24T14:15:22Z"
}
Status 400 The report does not exist for this project, the config does not match the kind, the named metric is not on the report, or the report is already at its check limit.
Status 404 Run not found for this project.

List all signals scout report checks

Every check on one report, newest first. Read this before writing one: a report already carrying a check for the same claim needs no second one, and a report holds at most five open checks at a time.

Required API key scopes

signal_scout_report:write

Path parameters

  • run_id
    string

Query parameters

  • report_id
    string

Example request

GET /api/projects/:project_id/signals/scout/runs/:run_id/report-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/scout/runs/:run_id/report-checks/

Example response

Status 200 The report's checks, newest first.
RESPONSE
{
"check_id": "051490c8-9abf-480a-9348-72c146208cd5",
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"title": "string",
"kind": "string",
"status": "string",
"next_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "string",
"run_state": "string",
"waiting_on_run": true,
"dispatched_run_id": "0d40720c-3ac9-4b33-96ee-ba348f818515",
"dispatched_at": "2019-08-24T14:15:22Z"
}
Status 400 The report does not exist for this project.
Status 404 Run not found for this project.

Retrieve signals scout runs

Return what every scout on this project spent on model calls over the last window_days, with how many runs it started, how many of those had spend attributed, and how many inbox reports it filed or added to. Cost per day, per run, and per report are derived from those numbers by the caller, so the endpoint stays a fact table and the definitions live in one place. Spend is summed from the $ai_generation events the runs' sandboxes produced and joined to the run rows by task run id, because a team-authored scout's generations all carry the same stage tag and so cannot name it. Cached per project for 15 minutes: the window's trailing edge moves and the newest runs may still be settling, so this is a roughly current number, not a live one. available is false where the internal AI observability project holding those events can't be read, so an unknown spend never reads as zero. Staff-only, same gate as the per-run cost read. Strictly team-scoped.

Required API key scopes

signal_scout:read

Query parameters

  • window_days
    integer

Response


Example request

GET /api/projects/:project_id/signals/scout/runs/costs
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/runs/costs/

Example response

Status 200 Model spend and output per scout over the window.
RESPONSE
{
"window_days": 0,
"scouts": [
{
"skill_name": "string",
"spend_usd": 0.1,
"run_count": 0,
"priced_run_count": 0,
"reports_touched": 0
}
],
"available": true
}
Status 403 Caller is not PostHog staff.

Create signals scout runs emissions

Batched form of the per-run emissions endpoint: return the findings every requested SignalScoutRun emitted, flattened newest-first, in a single request. Each row carries its run_id, so the caller can regroup by run. The findings UI uses this to load the whole recent window in one round-trip instead of one request per run. Strictly team-scoped — run ids belonging to another team contribute no rows (no per-run 404; one stale id never fails the batch).

Required API key scopes

signal_scout:read

Request parameters

  • run_ids
    array

Example request

POST /api/projects/:project_id/signals/scout/runs/emissions/batch
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/runs/emissions/batch/\
-d run_ids="array"

Example response

Status 200 Findings emitted across all requested runs, newest first.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"run_id": "string",
"finding_id": "string",
"description": "string",
"severity": "P0",
"tags": [
"string"
],
"source_id": "string",
"emitted_at": "2019-08-24T14:15:22Z"
}

Retrieve signals scout runs recent

Return the team's recently emitted scout findings across every run, newest first — the cross-run counterpart to the per-run emissions action. Each row carries its run_id, so you can regroup by run without first listing runs and fanning out one emissions call each. Pass skill_name to scope to a single scout, and date_from / date_to (a half-open window on emitted_at) to bound or paginate — set date_to to the oldest emission's emitted_at to walk back past the limit. Pure Postgres, no ClickHouse round-trip. Capped at 200 rows (default 50).

Required API key scopes

signal_scout:read

Query parameters

  • date_from
    string
  • date_to
    string
  • limit
    integer
  • skill_name
    string

Example request

GET /api/projects/:project_id/signals/scout/runs/emissions/recent
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/runs/emissions/recent/

Example response

Status 200 Recent emitted findings across every run on the team, newest first.
RESPONSE
{
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"run_id": "string",
"finding_id": "string",
"description": "string",
"severity": "P0",
"tags": [
"string"
],
"source_id": "string",
"emitted_at": "2019-08-24T14:15:22Z"
}

Create signals scout runs emission reports

Batched form of the per-run emission-reports endpoint. For every finding the requested runs emitted, resolve the inbox SignalReport (if any) its signal grouped into — all in a single ClickHouse round-trip rather than one query per run, which is what made the findings page slow to open. report is null when a finding hasn't grouped yet, was de-duplicated, or its signal was deleted. Strictly team-scoped — run ids belonging to another team contribute no rows.

Required API key scopes

signal_scout:readtask:read

Request parameters

  • run_ids
    array

Example request

POST /api/projects/:project_id/signals/scout/runs/emissions/reports/batch
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/runs/emissions/reports/batch/\
-d run_ids="array"

Example response

Status 200 Per-finding inbox report links across all requested runs, newest finding first.
RESPONSE
{
"finding_id": "string",
"source_id": "string",
"report": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"title": "string",
"status": "string"
}
}

Retrieve signals scout runs findings

Return a cheap fleet-wide tally of the output the scout troop produced in the recent window — the finding count, the distinct reports authored/edited via the report channel, the number of distinct scouts behind them, and the latest output time. Backs the 'Scout findings' callout so it renders from one query instead of the client paging through the whole runs window. Counts runs that emitted at least one finding (emitted_count > 0) or authored/edited an inbox report within the last window_hours (default 72), capped to the most recent 120 such runs so the count matches what the findings list renders. Strictly team-scoped.

Required API key scopes

signal_scout:read

Query parameters

  • window_hours
    integer

Response


Example request

GET /api/projects/:project_id/signals/scout/runs/findings/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/scout/runs/findings/summary/

Example response

Status 200 Fleet-wide tally of recent scout output — findings and report activity.
RESPONSE
{
"count": 0,
"scout_count": 0,
"authored_report_count": 0,
"edited_report_count": 0,
"run_count": 0,
"latest_at": "2019-08-24T14:15:22Z"
}

Retrieve signals scout runs recent per

Return the most recent per_scout_limit runs of every configured scout on the project (default 25), newest-first across the fleet. The per-scout probe is the point: a fleet-wide time window has to serve hourly and weekly scouts from one result cap, so the busy scouts crowd out the sparse ones and a scout's visible history shrinks as the rest of the fleet gets busier. Probing each skill_name gives every scout the same depth of history whatever its schedule, and bounds the response at scouts x per_scout_limit rather than at the fleet's run rate. Only scouts that still have a config are covered, so runs left behind by a deleted or renamed scout are excluded. Runs older than the staleness guard are excluded too, so a scout that stopped running reads as stale instead of healthy — max_age_days (default 30) is that guard's floor, which each scout's own cadence extends. Use list instead when you want a literal time window or a text/emitted filter. Strictly team-scoped.

Required API key scopes

signal_scout:read

Query parameters

  • max_age_days
    integer
  • per_scout_limit
    integer

Example request

GET /api/projects/:project_id/signals/scout/runs/recent-per-scout
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/runs/recent-per-scout/

Example response

Status 200 Each scout's most recent runs, newest-first across the fleet.
RESPONSE
{
"run_id": "string",
"skill_name": "string",
"skill_version": 0,
"status": "not_started",
"created_at": "string",
"started_at": "string",
"completed_at": "string",
"task_id": "string",
"task_run_id": "string",
"task_url": "string",
"summary": "string",
"error": "string",
"failure_reason": "string",
"emitted_count": 0,
"emitted_finding_ids": [
"string"
],
"emitted_report_ids": [
"string"
],
"edited_report_ids": [
"string"
],
"metadata": {
"harness_prompt_version": "string",
"report_channel": "string",
"skill_origin": "string",
"github_guidance": true,
"business_knowledge_maintained": true,
"model": "string",
"runtime_adapter": "string",
"reasoning_effort": "string",
"service_tier": "string",
"network_access": "string",
"write_scopes": [
"string"
],
"triggered_by": "string",
"run_note": "string",
"derived": {
"has_emit_report": true,
"has_edit_report": true,
"has_self_improvement": true,
"has_chart": true,
"has_self_validation": true,
"has_structured_output": true
}
}
}

List all signals scout report check

Every check on one report, newest first. The report_id is the only input. Read this before writing one: a report already carrying a check for the same claim needs no second one, and a report holds at most five open checks at a time.

Required API key scopes

signal_scout_report:write

Query parameters

  • report_id
    string

Example request

GET /api/projects/:project_id/signals/scout/runs/report-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/scout/runs/report-checks/

Example response

Status 200 The report's checks, newest first.
RESPONSE
{
"check_id": "051490c8-9abf-480a-9348-72c146208cd5",
"report_id": "5ed7905a-4735-4cf7-b1ab-521e066fb971",
"title": "string",
"kind": "string",
"status": "string",
"next_run_at": "2019-08-24T14:15:22Z",
"last_outcome": "string",
"run_state": "string",
"waiting_on_run": true,
"dispatched_run_id": "0d40720c-3ac9-4b33-96ee-ba348f818515",
"dispatched_at": "2019-08-24T14:15:22Z"
}
Status 400 The report does not exist for this project.

Create signals scout runs token

Return what each requested SignalScoutRun spent on model calls, summed from the $ai_generation events its sandbox produced. One query for the whole batch, cached per run: a settled run's total is final, a run still in progress reports what it has spent so far. available is false where the internal AI observability project holding those events can't be read, so an unknown cost never reads as zero. Staff-only — fleet spend is an internal operating number, and the events sit outside the project in the path. Strictly team-scoped — run ids belonging to another project contribute no rows.

Required API key scopes

signal_scout:read

Request parameters

  • run_ids
    array

Response


Example request

POST /api/projects/:project_id/signals/scout/runs/token-costs
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/runs/token-costs/\
-d run_ids="array"

Example response

Status 200 Model spend for each requested run that exists on this project.
RESPONSE
{
"costs": [
{
"run_id": "string",
"token_cost_usd": 0
}
],
"available": true
}
Status 403 Caller is not PostHog staff.

Retrieve signals scout scratchpad

Return SignalScratchpad entries for this project, newest-first. ILIKE matches on content and key; pass key instead for an exact single-entry lookup. date_from / date_to are a half-open window on updated_at (>= date_from, < date_to); pass date_to (the updated_at of the oldest entry seen) on subsequent calls to walk past the cap. Entries whose expires_at has passed are excluded unless include_expired=true, and are hard-deleted by a daily janitor once their expiry is more than two weeks in the past. Pass keys_only=true to scan keys without pulling entry bodies, or content_max_chars to cap each content to a preview — both keep a wide orientation scan from returning every entry's full prose. Results capped at 1000.

Required API key scopes

signal_scout:read

Query parameters

  • content_max_chars
    integer
  • date_from
    string
  • date_to
    string
  • include_expired
    boolean
    Default: false
  • key
    string
  • keys_only
    boolean
  • limit
    integer
  • text
    string

Example request

GET /api/projects/:project_id/signals/scout/scratchpad
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/scratchpad/

Example response

Status 200 Matching memory entries newest-first.
RESPONSE
{
"key": "string",
"content": "string",
"created_at": "string",
"updated_at": "string",
"expires_at": "string",
"created_by_run_id": "string",
"created_by_skill": "string",
"created_by_run_url": "string"
}

Create signals scout scratchpad

Upsert a memory keyed on (team, key). Re-using a key updates the existing entry in place. A write carries the entry's whole state, so expires_at is set when passed and cleared when omitted.

Required API key scopes

signal_scratchpad_internal:write

Request parameters

  • key
    string
  • content
    string
  • run_id
    string | null
  • expires_at
    string | null

Response


Example request

POST /api/projects/:project_id/signals/scout/scratchpad
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/scratchpad/\
-d key="string",\
-d content="string"

Example response

Status 200 Memory entry written or refreshed.
RESPONSE
{
"key": "string",
"content": "string",
"created_at": "string",
"updated_at": "string",
"expires_at": "string",
"created_by_run_id": "string",
"created_by_skill": "string",
"created_by_run_url": "string"
}
Status 400 Invalid memory shape (empty key/content, key too long, or an `expires_at` on a `followup:` entry). An unparseable or past `expires_at` is dropped, not rejected.

Create signals scout scratchpad

Delete an entry by key. Returns deleted=false if no row matched.

Required API key scopes

signal_scratchpad_internal:write

Request parameters

  • key
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/scratchpad/forget
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/scratchpad/forget/\
-d key="string"

Example response

Status 200 Whether a row was removed.
RESPONSE
{
"deleted": true
}

List all signals scout suggestions

Return the pre-computed scout suggestions for this project: up to five picks, best first, each either a PostHog-authored scout to turn on or a drafted custom scout. Dismissed and already-created suggestions are omitted. An empty items with status empty means no batch has been generated yet; the interactive scout-chat-tasks path still works.

Required API key scopes

signal_scout:read

Response


Example request

GET /api/projects/:project_id/signals/scout/suggestions
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/suggestions/

Example response

Status 200 The current batch.
RESPONSE
{
"status": "fresh",
"generated_at": "2019-08-24T14:15:22Z",
"model": "string",
"fleet_snapshot": [
"string"
],
"items": [
{
"id": "string",
"kind": "canonical",
"skill_name": "string",
"title": "string",
"why_here": "string",
"description": "string",
"draft_body": "string",
"proposed_config": {
"run_cron_schedule": "string",
"run_interval_minutes": 0,
"emit": true
},
"gap": true,
"confidence": "low"
}
]
}

Create signals scout suggestions

Hide one suggestion from this project's batch. Dismissal is remembered across refreshes by skill name, so the same suggestion is not shown again.

Required API key scopes

signal_scout:write

Path parameters

  • id
    string

Response


Example request

POST /api/projects/:project_id/signals/scout/suggestions/:id/dismiss
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/suggestions/:id/dismiss/

Example response

Status 200 The dismissed suggestion.
RESPONSE
{
"id": "string",
"kind": "canonical",
"skill_name": "string",
"title": "string",
"why_here": "string",
"description": "string",
"draft_body": "string",
"proposed_config": {
"run_cron_schedule": "string",
"run_interval_minutes": 0,
"emit": true
},
"gap": true,
"confidence": "low"
}
Status 404 No suggestion with that id in this project's batch.