Use the private automation API to run the same evidence loop from CI or your own scripts. Each bearer token is bound to one project.
Private alpha
Preview host: https://heyeo-preview.mayurupadhyaya1.workers.dev. Confirm with the team before wiring production automation.
On this page
API overview
Bearer-token automation, signed-in management, and public read-only surfaces.
Automation API — /api/v1/*, authenticated with a project-bound bearer token. Read scans, baselines, comparisons, management KPIs, recommendation actions and observations; create scans and drive recommendation work.
Token management — /api/projects/:id/automation-tokens, using your signed-in session to list, create and revoke tokens.
Recommendation observations — /api/projects/:id/recommendation-observations, using your signed-in session to review tracked recommendations that look actioned.
Site changes — /api/projects/:id/site-changes, using your signed-in session for page-level corroboration and existing deep links.
Onboarding assist — POST /api/onboarding/assist, using your signed-in session for the optional AI-assisted setup.
Public API — /api/public/*, unauthenticated and read-only, exposes only heyEO's configured public evidence projections.
Private and session-authenticated responses use no-store. Errors share the stable { error: { code, message } } envelope.
Authentication
Automation calls use a bearer token; management calls use your signed-in session.
An automation token looks like heyeo_v1_<12-char selector>_<43-char secret> and is sent as a bearer token:
Create one under Settings → Automation tokens → Create. The full value is shown once, so store it in your secret manager. heyEO retains only a hash; if you lose the token, revoke it and create another.
API quickstart
Create a token in the app, start a scan, then poll its recorded state.
1 · Environment
# Preview origin (private alpha). Confirm with the team before production wiring.
export HEYEO_API="https://heyeo-preview.mayurupadhyaya1.workers.dev"
export PROJECT_ID="123" # sample numeric project id — use yours
export HEYEO_TOKEN="heyeo_v1_XXXXXXXXXXXX_..." # Settings → Automation tokens
The response includes a runId and credit price. Reusing the same Idempotency-Key with the same body returns the original run with replayed: true and no extra charge.
Every failure returns the same envelope with a stable code:
{
"error": {
"code": "insufficient_credits",
"message": "You don't have enough credits to start this scan."
}
}
Rate limiting
Automation tokens allow 60 requests per 60 seconds. Onboarding assist separately allows 5 requests per 60 seconds per signed-in user. A limited request returns 429 rate_limit_exceeded with a Retry-After header.
Idempotency
POST /scans requires an Idempotency-Key. The same key and body replay the original run; the same key with a different body returns 409 idempotency_conflict.
Pagination
List endpoints return an opaque nextCursor; pass it back as the cursor query parameter.
Project isolation
A token can see only its project. Unknown and out-of-scope resources return 404 not_found, so resources outside the project are not distinguishable.
Full status / code catalogue
Status
Code
When
400
invalid_request
A field, query param, or the request body failed validation.
400
invalid_cursor
The pagination cursor is invalid.
401
invalid_token
The automation token is missing, malformed, unknown, expired or revoked.
401
authentication_required
A management endpoint was called without a signed-in session.
402
insufficient_credits
Not enough credits to start the scan.
404
not_found
The resource does not exist, or belongs to another project (isolation).
404
no_baseline
No baseline is selected for the project (comparisons).
409
idempotency_conflict
The same Idempotency-Key was reused with a different payload.
409
prompt_set_changed
The monitored prompt set changed between quote and reservation; re-quote.
409
run_not_complete
A run referenced by a comparison is not complete yet.
409
token_limit_reached
The project already has the maximum number of active tokens.
409
assistance_exhausted
The one funded AI-assisted setup has already been used for this request.
409
assistance_in_progress
An AI suggestion is already being prepared (lease in progress).
405
method_not_allowed
HTTP method not allowed for this endpoint.
413
request_too_large
The request body exceeds 64 KiB.
415
json_required
A write request was not sent as application/json.
429
rate_limit_exceeded
Per-token rate limit exceeded (Retry-After: 60).
502
website_unreachable
The website could not be read (crawl failed).
502
upstream_unavailable
AI model or upstream service is temporarily unavailable (may return 503).
503
service_unavailable
Wiring, rate limiter or auth backend is unavailable.
503
queue_unavailable
The scan queue is unavailable (scan create).
503
evidence_unavailable
Comparison evidence is unavailable for a corrupt run.
503
unavailable
Service is temporarily unavailable (generic unavailability).
500
internal_error
Unexpected server error, or a response failed its own schema.
Reference · Public API
Unauthenticated, read-only projections for heyEO's configured public project.
The auto-latest report returns the newest completed scan. The evidence endpoint returns only approved before-and-after cycles. Neither surface accepts a project, owner or run selector from the caller.
Cookies and Authorization headers do not change the representation or trigger a Set-Cookie response. Missing configuration or evidence fails closed with a 503.
Success responses use public, max-age=60, s-maxage=300; failures use no-store.
GET
/api/public/report
Get public report
Auto-latest public scan report for the configured heyEO project. Returns the newest completed scan with audit summary, inferred ICP, AEO visibility aggregates, and up to 25 recommendations. No per-scan approval—auto-published per ADR 0002. Fails closed (503) when HEYEO_PUBLIC_REPORT_PROJECT_ID is unbound.
Non-GET request (POST, PUT, PATCH, DELETE). Response includes Allow: GET header.
503
service_unavailable
Public report is temporarily unavailable (config unbound, no completed runs, or projection failure).
GET
/api/public/evidence
Get public evidence
Approval-gated public evidence cycles for the configured heyEO project. Returns 1–10 published before/after cycles, each with a recommendation, intervention, baseline/current run provenance, and a full comparison result. Fails closed (503) when HEYEO_PUBLIC_EVIDENCE_PROJECT_ID is unbound or no cycles are approved.
Reserve credits and queue a new scan. Idempotent: reusing the same Idempotency-Key with the same body replays the original run (replayed: true) without charging again.
Auth: Bearer automation token
Headers
Field
Type
Notes
Content-Typerequired
application/json
—
Idempotency-Keyrequired
string
Trimmed, 1–120 chars. Use a unique key per logical request.
Request body
Field
Type
Notes
measurerequired
boolean
Measure the monitored prompts against the providers.
expectedPromptCountrequired
integer
0–10. Must be > 0 when measure=true, exactly 0 when false (staleness guard).
providerIdsrequired
string[]
Non-empty subset of openai | gemini | perplexity.
limits
object
Optional crawl limits. maxPages must be an exact crawl tier: 25, 50, 100, 150, 200, or 250 (default 25). Other values return invalid_request (Unsupported crawl tier). Crawl credits for those tiers are 1–6 on the crawl_audit line. Other optional positive ints: maxResponseBytes, maxSitemapBytes, maxSitemaps, maxSitemapUrls, maxExtractedTextChars, requestTimeoutMs, maxRedirects, maxDurationMs.
Select a completed project scan as the active comparison baseline.
Auth: Bearer automation token
Request body
Field
Type
Notes
baselineRunIdrequired
uuid
—
idempotencyKeyrequired
string
—
Response · 200
The persisted baseline selection.
GET
/api/v1/projects/{projectId}/comparisons
Compare runs
Compare a run against the baseline (or an explicit baseline run). Site, AI and ICP sections compare independently; a prompt/provider mismatch now returns the matching sections as partial instead of hiding every difference.
Auth: Bearer automation token
Query parameters
Field
Type
Notes
currentRunIdrequired
uuid
—
baselineRunId
uuid
Optional. Defaults to the project's active baseline.
Attach an eligible completed scan as the action's follow-up evidence.
Auth: Bearer automation token
Request body
Field
Type
Notes
followUpRunIdrequired
uuid
—
idempotencyKeyrequired
string
—
Response · 200
The intervention with its attached follow-up scan.
GET
/api/v1/projects/{projectId}/management-report
Get management KPIs
Return the latest evidence-backed founder scorecard and movement. The comparison basis selects a completed run at least 7 days older, else the previous completed run, else the active baseline, else none. The comparisonBasis field reports which was used: weekly_anchor | previous_run | active_baseline | none. If the current evidence is bad, returns 503. If the baseline evidence is bad, degrades to current-only (comparisonBasis: none) instead of failing.
List tracked-recommendation evidence observations for a project. Primary founder inbox for Gate 7: candidates that look actioned after a later comparable scan. Retitled tracked copies of the same site findings collapse into one candidate (fingerprint: familyKey + materialSignature + URL); siblings already confirmed for the project (any observing run) are omitted. Page-level site changes remain corroboration only and are not required for confirmation.
One-click confirm that a candidate_actioned observation was intentional. Atomically records an intervention (creating one when absent), advances the recommendation through accepted → implementing → implemented with append-only events, and marks the observation confirmed. Detection alone never transitions action state. Idempotent.
Auth: Signed-in session
Headers
Field
Type
Notes
Content-Typerequired
application/json
—
Request body
Field
Type
Notes
idempotencyKeyrequired
string
Trimmed, 1–120 chars. Use a unique key per logical request.
expectedVersionrequired
integer
Optimistic-lock version. 409 invalid_state if stale.
changeUrl
string (URL)
Optional override; defaults from observation evidence / affected URLs.
implementedAt
string (ISO-8601)
Optional override; defaults to observation detectedAt.
Response · 200
The updated RecommendationObservation.
Endpoint-specific errors
Status
Code
When
400
invalid_request
Body validation failed, or observationId is not a UUID.
404
not_found
The observation was not found, or belongs to another project.
409
idempotency_conflict
Same idempotencyKey, different payload.
409
invalid_state
expectedVersion was stale, observation is not pending, or status is not candidate_actioned.
Mark a pending observation as Not this change. Suppresses only that observation; does not dismiss the recommendation or transition action state. Idempotent.
Auth: Signed-in session
Headers
Field
Type
Notes
Content-Typerequired
application/json
—
Request body
Field
Type
Notes
idempotencyKeyrequired
string
Trimmed, 1–120 chars. Use a unique key per logical request.
expectedVersionrequired
integer
Optimistic-lock version. 409 invalid_state if stale.
Response · 200
The updated RecommendationObservation.
Endpoint-specific errors
Status
Code
When
400
invalid_request
Body validation failed, or observationId is not a UUID.
404
not_found
The observation was not found, or belongs to another project.
409
idempotency_conflict
Same idempotencyKey, different payload.
409
invalid_state
expectedVersion was stale, or observation is not pending.
Reference · Site changes
Signed-in page-level corroboration and existing change deep links.
GET
/api/projects/{projectId}/site-changes
List site changes
List material page changes detected between consecutive scans. Optionally filter by verification state or scope to a detecting scan via afterRunId. Returns change metadata, summary labels, unresolved count, and detecting-interval projection status when afterRunId is set.
Query param validation failed (invalid limit, verificationState, or afterRunId UUID).
400
invalid_cursor
The pagination cursor is invalid.
GET
/api/projects/{projectId}/site-changes/{changeId}
Get site change
Full detail for one detected site change: the change record, verification events, link events, suggested recommendation associations, and outcome history (later scans with comparisons).
Record a founder verification (intentional_expected, intentional_unexpected, not_mine, unsure). Updates verificationState and appends a verification event. Idempotent.
Remove the association between a site change and its linked recommendation action. Clears recommendationActionId and appends an unlink event. Idempotent.
Auth: Signed-in session
Headers
Field
Type
Notes
Content-Typerequired
application/json
—
Request body
Field
Type
Notes
idempotencyKeyrequired
string
Trimmed, 1–120 chars. Use a unique key per logical request.
expectedVersion
integer
Optional optimistic-lock version. When supplied, 409 invalid_state if stale.
Response · 200
The updated SiteChange record (same shape as list items).
Endpoint-specific errors
Status
Code
When
400
invalid_request
Body validation failed, or changeId is not a UUID.
404
not_found
The site change was not found, or belongs to another project.
409
idempotency_conflict
Same idempotencyKey, different payload.
409
invalid_state
expectedVersion was stale.
Reference · Onboarding assist
Signed-in optional setup assistance with a separate per-user rate limit.
POST
/api/onboarding/assist
AI-assisted onboarding
One platform-funded website analysis per signed-in founder. Crawls up to 5 pages and drafts selected onboarding sections (declared ICP, competitors, markets/topics). Founder reviews and confirms suggestions before project creation.
Auth: Signed-in session
Headers
Field
Type
Notes
Content-Typerequired
application/json
—
Authorizationrequired
Bearer token
Signed-in Supabase session token.
Accept
string
Optional: application/x-ndjson for streamed progress after lease acquisition.