Skip to content

Pool, Results and Pages

Suggestions waiting on a decision, the results that say what the work changed, and the page registry underneath both.

Requires authentication
60 req/min reads, 30 req/min writes

How the three fit together

Every recommendation Trakkr makes lands in one pool. A person or an agent decides what to do with each one, and committing freezes how that change will be measured. When the window closes, the pipeline measures it and writes a result. Pages are what all of it hangs on: one row per URL, keyed the same way everywhere.

/get-opportunity-pool is not the same thing as /get-opportunities. The older endpoint lists citation outreach targets and keeps working exactly as it does today. This one is the unified pool that every recommendation system writes to.

Pool

GET/get-opportunity-pool

Suggestions waiting on a decision. The order is deterministic: impact bands first, then each family's freshest items in turn, so one high-volume source cannot crowd out everything else. Nothing here is committed work yet.

Only two statuses ever come back: new and seen. Anything committed, dismissed, snoozed or expired has left the pool, so there is no filter that brings those rows back here.

Query Parameters

brand_idstringrequired

The brand to read.

familystring

fix, refresh, create, earn, discuss, optimize, setup or play.

kindstring

Comma-separated kinds, e.g. 'search_gap,audit_fix'.

impactstring

low, medium or high.

limitint

1-200.

Default: 50

cursorstring

Opaque cursor from meta.next_cursor.

Commit, dismiss or snooze

POST/commit-opportunity

One explicit verb per call. Committing creates tracked work and freezes its measurement plan, which is what makes a before/after result possible later. Dismissing takes a reason. Snoozing hides a suggestion and brings it back.

This endpoint cannot grant an agent permission to do anything. Autonomy is set per brand inside the product, never over the API.

Parameters

brand_idstringrequired

Query parameter. The brand that owns the suggestion.

opportunity_idstringrequired

Body. The suggestion to decide on.

actionstring

Body. commit, dismiss or snooze.

Default: 'commit'

reasonstring

Body. Why it was dismissed. Recommended for action='dismiss'.

snooze_daysint

Body. 1-90.

Default: 7

A commit returns status, opportunity_id, action_id and the frozen measurement_plan. Dismiss and snooze return only status and opportunity_id. Setup work is never measured, so its plan comes back null, and committing something already committed returns already_accepted with the existing action id.

snooze_days is validated, not just documented: anything outside 1-90 is rejected with 422 before the call runs. An action other than commit, dismiss or snooze returns 400, and an opportunity_id that belongs to another brand returns 404.

Results

GET/get-results

What completed work actually changed. Every row is computed by Trakkr's pipeline from real before/after data over the window that was frozen at commit time. Nothing here is self-reported.

A result never claims causation. It says a metric moved during the window, which is a different and more honest statement. Four verdicts are possible: earned (the metric cleared the bar the plan set), no_change (it held steady), harm (it fell, reported as "coincided with a drop"), and couldnt_measure (the data needed was not there, and the reason says which).

Query Parameters

brand_idstringrequired

The brand to read.

verdictstring

earned, no_change, harm or couldnt_measure.

familystring

Narrow to one verb family.

daysint

Only results measured in the last 1-3650 days.

limitint

1-200.

Default: 50

cursorstring

Opaque cursor from meta.next_cursor.

/get-proof remains available as a deprecated compatibility alias for existing integrations.

Pages

GET/get-pages

One row per URL the brand owns or appears on. Because everything is keyed on one canonical URL form, a page here is the same page across crawler data, citations, audits and search. Rows carry the page's bottleneck, meaning the first stage of its funnel that is stuck.

Rows come back newest last_seen_at first. Each one carries id, url, slug, ownership, title, tracked, bottleneck, verdict and last_seen_at. The bottleneck is a funnel stage name (available, reached, understood, relevant, selected or visited) and the verdict is the plain sentence that goes with it. Both are null until there is enough data to name one.

Query Parameters

brand_idstringrequired

The brand to read.

ownershipstring

owned, competitor, editorial, social, video or other.

trackedbool

True for pages someone chose to watch.

limitint

1-200.

Default: 50

cursorstring

Opaque cursor from meta.next_cursor.

Pagination

These endpoints use cursors, not offsets. Read meta.next_cursor and pass it back as cursor to get the next page. A null cursor means you have reached the end. Older endpoints such as /get-actions keep their existing offset pagination unchanged.

Code example

Pool
Code language
1curl -H 'Authorization: Bearer $TRAKKR_API_KEY' \
2 'https://api.trakkr.ai/get-opportunity-pool?brand_id=00000000-0000-4000-8000-81f286d10c3c&family=fix&limit=20'
Response example
1{
2 "opportunities": [
3 {
4 "id": "e1f2a3b4-...",
5 "kind": "audit_fix",
6 "family": "fix",
7 "title": "Add a meta description to /help/returns",
8 "impact": "high",
9 "status": "new",
10 "evidence": [
11 {
12 "kind": "signal",
13 "source": "site_audit",
14 "observed_at": "2026-07-28T06:00:00Z",
15 "payload": { "label": "Missing since", "value": "12 days" },
16 "deep_link": "https://app.trakkr.ai/optimize"
17 }
18 ],
19 "page_id": "9a8b...",
20 "page_url": "https://example.com/help/returns",
21 "dedup_key": "audit_fix:meta_description:https://example.com/help/returns",
22 "expires_at": "2026-08-18T06:00:00Z",
23 "created_at": "2026-07-28T06:00:00Z"
24 }
25 ],
26 "meta": { "total": 137, "limit": 20, "next_cursor": "o:20" }
27}
Commit
Code language
1curl -X POST 'https://api.trakkr.ai/commit-opportunity?brand_id=00000000-0000-4000-8000-81f286d10c3c' \
2 -H 'Authorization: Bearer $TRAKKR_API_KEY' \
3 -H 'Content-Type: application/json' \
4 -d '{"opportunity_id": "e1f2...", "action": "commit"}'
Response example
1{
2 "status": "committed",
3 "opportunity_id": "e1f2a3b4-...",
4 "action_id": "a1b2c3d4-...",
5 "measurement_plan": {
6 "subject": { "page_id": "9a8b7c6d-..." },
7 "primary": { "metric": "bot_fetches", "source": "crawler_logs" },
8 "secondary": [],
9 "window_days": 14,
10 "moved_if": "after >= max(before*1.25, before+min_gain)",
11 "harm_if": "after <= before*0.75",
12 "rollback_ref": null
13 }
14}
Results
Code language
1curl -H 'Authorization: Bearer $TRAKKR_API_KEY' \
2 'https://api.trakkr.ai/get-results?brand_id=00000000-0000-4000-8000-81f286d10c3c&verdict=earned&limit=20'
Response example
1{
2 "results": [
3 {
4 "id": "r1...",
5 "action_id": "a1...",
6 "verdict": "earned",
7 "family": "fix",
8 "summary": "Citations went from 2 to 6 over 14 days.",
9 "primary_metric": {
10 "label": "Citations",
11 "before": 2,
12 "after": 6,
13 "source": "citations"
14 },
15 "window_days": 14,
16 "reason": null,
17 "measured_at": "2026-07-28T06:00:00Z",
18 "rolled_back": false,
19 "page_url": "https://example.com/help/returns"
20 }
21 ],
22 "meta": { "total": 41, "limit": 20, "next_cursor": null },
23 "verdict_counts": {
24 "earned": 12,
25 "no_change": 9,
26 "couldnt_measure": 20
27 }
28}
Pages
Code language
1curl -H 'Authorization: Bearer $TRAKKR_API_KEY' \
2 'https://api.trakkr.ai/get-pages?brand_id=00000000-0000-4000-8000-81f286d10c3c&ownership=owned&limit=50'
Response example
1{
2 "pages": [
3 {
4 "id": "9a8b7c6d-...",
5 "url": "https://example.com/help/returns",
6 "slug": "/help/returns",
7 "ownership": "owned",
8 "title": "Returns and refunds",
9 "tracked": true,
10 "bottleneck": "reached",
11 "verdict": "This page is available but AI crawlers aren't fetching it.",
12 "last_seen_at": "2026-07-28T06:00:00Z"
13 }
14 ],
15 "meta": { "total": 812, "limit": 50, "next_cursor": "o:50" }
16}
Press ? for keyboard shortcuts