Signals
For instructions on how to authenticate to use this endpoint, see API overview.
Endpoints
POST | |
GET | |
POST | |
GET | |
GET | |
GET | |
POST | |
GET | |
POST | |
POST | |
GET | |
POST | |
POST | |
GET | |
POST | |
GET | |
PATCH | |
DELETE |
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:readRequest parameters
- run_idsarray
Example request
POST /api /projects /:project_id /signals /scout /runs /emissions /batchExample response
Status 200 Findings emitted across all requested runs, newest first.
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:readQuery parameters
- date_fromstring
- date_tostring
- limitinteger
- skill_namestring
Example request
GET /api /projects /:project_id /signals /scout /runs /emissions /recentExample response
Status 200 Recent emitted findings across every run on the team, newest first.
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:readRequest parameters
- run_idsarray
Example request
POST /api /projects /:project_id /signals /scout /runs /emissions /reports /batchExample response
Status 200 Per-finding inbox report links across all requested runs, newest finding first.
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:readQuery parameters
- window_hoursinteger
Response
Example request
GET /api /projects /:project_id /signals /scout /runs /findings /summaryExample response
Status 200 Fleet-wide tally of recent scout output — findings and report activity.
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. Pass skill_name to probe one scout only. Strictly team-scoped.
Required API key scopes
signal_scout:readQuery parameters
- max_age_daysinteger
- per_scout_limitinteger
- skill_namestring
Example request
GET /api /projects /:project_id /signals /scout /runs /recent-per-scoutExample response
Status 200 Each scout's most recent runs, newest-first across the fleet.
Status 304 The runs match the `ETag` sent in `If-None-Match`, so the body is left out.
Status 412 The runs do not match the `ETag` sent in `If-Match`.
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:writeQuery parameters
- report_idstring
Example request
GET /api /projects /:project_id /signals /scout /runs /report-checksExample response
Status 200 The report's checks, newest first.
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:readRequest parameters
- run_idsarray
Response
Example request
POST /api /projects /:project_id /signals /scout /runs /token-costsExample response
Status 200 Model spend for each requested run that exists on this project.
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, and skill_name to keep the entries one scout (or pipeline:* stage) created. 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:readQuery parameters
- content_max_charsinteger
- date_fromstring
- date_tostring
- include_expiredbooleanDefault:
false - keystring
- keys_onlyboolean
- limitinteger
- skill_namestring
- textstring
Example request
GET /api /projects /:project_id /signals /scout /scratchpadExample response
Status 200 Matching memory entries newest-first.
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:writeRequest parameters
- keystring
- contentstring
- run_idstring | null
- expires_atstring | null
Response
Example request
POST /api /projects /:project_id /signals /scout /scratchpadExample response
Status 200 Memory entry written or refreshed.
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:writeRequest parameters
- keystring
Response
Example request
POST /api /projects /:project_id /signals /scout /scratchpad /forgetExample response
Status 200 Whether a row was removed.
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:readResponse
Example request
GET /api /projects /:project_id /signals /scout /suggestionsExample response
Status 200 The current batch.
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:writePath parameters
- idstring
Response
Example request
POST /api /projects /:project_id /signals /scout /suggestions /:id /dismissExample response
Status 200 The dismissed suggestion.
Status 404 No suggestion with that id in this project's batch.
Create signals scout suggestions
Re-run the suggestion scan for this project now instead of waiting for the scheduled refresh. Runs headlessly; poll the list endpoint for the new batch (generated_at advances). Capped per project per day.
Required API key scopes
signal_scout:writeResponse
Example request
POST /api /projects /:project_id /signals /scout /suggestions /refreshExample response
Status 202 Refresh dispatched.
Status 403 Organization has not approved AI data processing, or suggestions are off for this project.
Status 409 A refresh is already running for this project.
Status 429 Daily refresh cap reached.
List all signals source configs
Required API key scopes
task:readQuery parameters
- limitinteger
- offsetinteger
Response
Example request
GET /api /projects /:project_id /signals /source_configsExample response
Status 200
Create signals source configs
Required API key scopes
task:writeRequest parameters
- source_product
- source_type
- enabledboolean
- configobject
Response
Example request
POST /api /projects /:project_id /signals /source_configsExample response
Status 201
Retrieve signals source configs
Required API key scopes
task:readPath parameters
- idstring
Response
Example request
GET /api /projects /:project_id /signals /source_configs /:idExample response
Status 200
Update signals source configs
Required API key scopes
task:writePath parameters
- idstring
Request parameters
- source_product
- source_type
- enabledboolean
- configobject
Response
Example request
PATCH /api /projects /:project_id /signals /source_configs /:idExample response
Status 200
Delete signals source configs
Required API key scopes
task:writePath parameters
- idstring
Example request
DELETE /api /projects /:project_id /signals /source_configs /:id










