---
name: et-platform-agent-guide
description: "Use when: an AI agent needs to operate RealEye ET Platform - choosing between the public api2 HTTP API and the web UI, authenticating with X-AUTH-TOKEN, creating/configuring/running studies, uploading stimuli, exporting collected data, managing study participants, or working with Retail/Shelf and mockup studies. States which operations the public API cannot do and the exact UI path (or documented coverage gap) for each."
---

# RealEye ET Platform Agent Guide

This skill is for an AI agent (or a human directing one) that must operate the
RealEye ET Platform. It exists to stop two recurring mistakes:

- reverse-engineering the public API page and the support corpus every time, and
- proposing manual UI work where the public `api2` API already does the job, or
  calling an `api2` endpoint that does not exist.

Everything here is grounded in two sources: the public API contract
`public/doc/api/index_v2.0.md` (the ET Platform source of record) and the
`projects/et_platform/doc/user_support/**` support corpus that the website
publishes at `/support/{slug}`. Do not invent endpoints, request fields, or UI
steps that are not in them. The version/date this skill was written against is
declared once, below.

## The deciding question: `api2` or the web UI?

Answer this first, before writing any request or telling a user to click
anything.

1. **Is the operation in the API-only list below?** Use the public API. Do not
   script the browser UI.
2. **Is the operation in the "Not available via the public API" list?** Use the
   web UI. Do not invent an endpoint for it.
3. **Otherwise, prefer the public API** for repeatable, scriptable work
   (creating studies, exporting data, setting tags), and the UI for one-off
   visual work (designing the stimuli flow, reading heatmaps).

The public API is the `api2` surface on `https://app.realeye.io/api2`. Only
routes under `/api2` accept the `X-AUTH-TOKEN` header. The rest of the app
(`/api/**`, `/dashboard/**`, `/admin/**`) is the session-authenticated web UI,
not part of the public contract - an agent must not treat those paths as API.

## Authentication (public `api2` only)

- Every `api2` request must send a private token in the `X-AUTH-TOKEN` header,
  for example:
  `curl --header "X-AUTH-TOKEN: <token>" https://app.realeye.io/api2/studies`.
- Getting and enabling a token is a support action: the account's license must
  include the API module, and RealEye support issues or enables the token.
- `api2` is stateless and scoped to the authenticated company/user: never add a
  `companyId`/`accountId` path segment to a standard endpoint.
- `api2` is the only public HTTP API. There is no session login for it; do not
  send cookies.

## Error handling (`api2`)

The API uses standard HTTP status codes plus JSON error payloads (some older
endpoints return a simpler `{"message": "..."}` or `{"error": "..."}` body).

- `400 Bad Request` - request shape, UUID format, or parameter validation.
- `401 Unauthorized` - missing, empty, invalid, or disabled `X-AUTH-TOKEN`.
- `403 Forbidden` - authenticated but not entitled, or not allowed to access
  the resource.
- `404 Not Found` - the resource does not exist in the authenticated scope.
- `409 Conflict` - business-state conflict, for example an invalid study state
  transition or an archived-state restriction.
- `500 Internal Server Error` - unexpected backend error.

### License without API access

A **valid** token on a license **without** the API module returns HTTP `403`
with the documented `license_no_api_access` code:

```json
{
  "status": "error",
  "error": {
    "code": 403,
    "error_code": "license_no_api_access",
    "message": "Your API token is valid, but your current license does not include API access. Please upgrade your plan or contact support at support@realeye.io."
  }
}
```

Do not retry this; the fix is a license/entitlement change (contact
[support@realeye.io](mailto:support@realeye.io)).

## Which surface for each workflow

| Workflow | Public `api2` path | Web UI path |
| --- | --- | --- |
| **Create a study** | `POST /studies` (Studies Collection) | Dashboard → create study: [/support/getting-started-with-realeye](/support/getting-started-with-realeye) |
| **Configure a study** | `PATCH /studies/{studyId}` (Single Study) | Study settings: [/support/study-settings](/support/study-settings) |
| **Launch / finish a study** | `PATCH /studies/{studyId}` with `status` `running` (launch) or `finished` (finish) | Launch/finish or add participants to a running study: [/support/finishing-study](/support/finishing-study), [/support/adding-testers-to-running-study](/support/adding-testers-to-running-study) |
| **List / read studies** | `GET /studies`, `GET /studies/{studyId}`, `GET /studies-by-external-id/{externalId}` | Dashboard studies list |
| **Delete a study** | `DELETE /studies/{studyId}` | [/support/how-to-delete-a-study](/support/how-to-delete-a-study) |
| **Image stimuli: list / add / delete** | `GET /studies/{studyId}/stimuli`, `POST /studies/{studyId}/stimuli` (image only), `DELETE /studies/{studyId}/stimuli/{stimulusId}` | Upload items and item settings: [/support/uploading-items](/support/uploading-items), [/support/items-settings](/support/items-settings) |
| **Participation links** | `GET /studies/{studyId}` returns `participationLinks` | Participation link parameters/tags: [/support/add-parameters-and-tags-to-the-participation-link](/support/add-parameters-and-tags-to-the-participation-link), [/support/for-study-participants](/support/for-study-participants) |
| **Study flow (read)** | `GET /studies/{studyId}/flow` | Study preview: [/support/study-preview](/support/study-preview) |
| **Eye-tracking export** | `GET /studies/{studyId}/collected-data/eye-tracking/gazes/raw`, `.../gazes/raw-denoises-normalized-split`, `.../fixations`, `.../aois-all/overall-stats`, `.../aois-all/fixations-stats`, `.../aois-all/fixations-order`, `.../aois-all/clicks-stats` | Data export to CSV: [/support/data-export-to-csv](/support/data-export-to-csv), [/support/data-export-csv-files](/support/data-export-csv-files) |
| **Keyboard and mouse export** | `GET /studies/{studyId}/collected-data/keyboard-and-mouse/overall-per-participant` | [/support/csv-file-reaction-time-click-keypress](/support/csv-file-reaction-time-click-keypress) |
| **Facial coding export** | `GET /studies/{studyId}/collected-data/facial-coding/raw` | [/support/csv-file-raw-facial-coding](/support/csv-file-raw-facial-coding) |
| **Survey export** | `GET /studies/{studyId}/collected-data/survey` | [/support/csv-file-survey-results](/support/csv-file-survey-results) |
| **Quality stats export** | `GET /studies/{studyId}/collected-data/quality-stats` | [/support/csv-file-quality-stats](/support/csv-file-quality-stats), [/support/participant-quality-stats-explained](/support/participant-quality-stats-explained) |
| **Drop-rate export** | `GET /studies-all/drop-rate` | [/support/drop-rate-csv](/support/drop-rate-csv) |
| **Participant counts** | `GET /studies/{studyId}/participants-count` | Results → Participant List: [/support/how-to-analyze-heatmaps](/support/how-to-analyze-heatmaps) |
| **Participant tags** | `POST /studies/{studyId}/participants-list` | Import tags/ignore from CSV: [/support/import-additional-information-for-participants](/support/import-additional-information-for-participants) |
| **Shopper metrics (Virtual Shelf)** | `GET /studies/{studyId}/participants/{participantId}/shopper-metrics` | UI path not documented in the support corpus - documented coverage gap (see below) |
| **Interaction flow (Virtual Shelf)** | `GET /participants/interaction-flow?participantIds=...` | UI path not documented in the support corpus - documented coverage gap (see below) |
| **Retail / Shelf study authoring** | Not available - author in the UI, then read the data via `shopper-metrics` / `interaction-flow` | Shelf workbook import: [/support/shelf-testing-spreadsheet-upload-guide](/support/shelf-testing-spreadsheet-upload-guide) |
| **Mockup studies** | Not available - author in the UI | [/support/mockup-studies](/support/mockup-studies) |

Notes that change how you act:

- **Stimuli are image-only through the API.** `POST /studies/{studyId}/stimuli`
  accepts `type=image` only; website and video stimuli are not supported there.
- **Launches and finishes go through `PATCH /studies/{studyId}`**, not a
  dedicated endpoint. `status = running` validates the launch and
  `status = finished` validates the finish. `draft` and `reverted` are not
  supported through the API.
- **Archiving is a `PATCH`** (`isArchived`); an archived study must be
  unarchived before any other non-archive change.
- **Shopper metrics need study context.** Use
  `/studies/{studyId}/participants/{participantId}/shopper-metrics` - there is
  no flattened participant-only shortcut.

## Not available via the public API

These operations have no `api2` endpoint. Do them in the UI, using the path
below. If a path says "coverage gap", the support corpus has no article for it -
say so rather than inventing UI steps.

| Operation | UI path |
| --- | --- |
| Clone a study | Dashboard → duplicate study: [/support/how-to-clone-a-study](/support/how-to-clone-a-study) |
| Add a video stimulus | Upload items: [/support/uploading-items](/support/uploading-items) |
| Add a website stimulus | Website study types: [/support/which-study-type-for-website-research](/support/which-study-type-for-website-research), [/support/embedded-website-tests-for-aggregated-results](/support/embedded-website-tests-for-aggregated-results) |
| Add a mockup stimulus | Mockup studies: [/support/mockup-studies](/support/mockup-studies) |
| Edit the stimuli flow (groups, order, `reio-stimuli-flow`) | [/support/how-to-run-test-with-specified-items](/support/how-to-run-test-with-specified-items) |
| Configure a survey | [/support/connecting-study-with-external-survey](/support/connecting-study-with-external-survey), [/support/connecting-realeye-study-with-qualtrics-survey](/support/connecting-realeye-study-with-qualtrics-survey), [/support/survey-routing-and-parameters](/support/survey-routing-and-parameters) |
| Inspect the participant list | Results → Participant List: [/support/how-to-analyze-heatmaps](/support/how-to-analyze-heatmaps), [/support/how-to-download-the-recording](/support/how-to-download-the-recording) |
| Ignore participants | Import tags/ignore from CSV: [/support/import-additional-information-for-participants](/support/import-additional-information-for-participants) |
| Confirm participants | UI path not documented in the support corpus - documented coverage gap |
| Order panelists | [/support/ordering-study-participants-best-practices](/support/ordering-study-participants-best-practices), [/support/how-to-order-participants-from-prolific-for-your-realeye-study](/support/how-to-order-participants-from-prolific-for-your-realeye-study), [/support/how-to-order-participants-from-cint-for-your-realeye-study](/support/how-to-order-participants-from-cint-for-your-realeye-study) |
| Author a Retail/Shelf study | Shelf workbook import: [/support/shelf-testing-spreadsheet-upload-guide](/support/shelf-testing-spreadsheet-upload-guide) |
| Download a heatmap | [/support/how-to-analyze-heatmaps](/support/how-to-analyze-heatmaps), [/support/sharing-results](/support/sharing-results) |
| Download a recording | [/support/how-to-download-the-recording](/support/how-to-download-the-recording), [/support/what-are-recordings](/support/what-are-recordings) |
| Generate a study report | Dashboard Results panels: [/support/analyzing-study-results](/support/analyzing-study-results) - the exact non-shelf report steps are not documented in the support corpus (coverage gap) |

### Documented coverage gaps

The support corpus has no grounding article for these UI paths. Tell the user
the UI path is not documented rather than guessing steps:

- Confirming participants.
- The Virtual Shelf **shopper-metrics** view in the dashboard.
- The Virtual Shelf **interaction-flow** view in the dashboard.
- The exact steps of generic (non-shelf) study **report generation**.

## Staying current (detecting a stale skill)

The first line of this section is the skill's machine-readable source of record:

- Source of record: `public/doc/api/index_v2.0.md` (version `2.8.0`, last updated `2026-05-13`)

Before trusting the `api2` paths above, compare them with the current
`public/doc/api/index_v2.0.md`. If its "Latest documented release" or
"Document last update" value differs from the version/date on the line above,
this skill may be stale - re-read the source of record and prefer it. The
repository's CI guard (`bin/check_agent_skill_sync.py`) also fails when this
declared version/date drifts from the source of record, or when the published
copy of this skill diverges from this file.

## Related support articles

Do not restate these; link to them.

- [/support/realeye-api](/support/realeye-api) - the customer-facing API article.
- [/support/eye-tracking-glossary](/support/eye-tracking-glossary) - terminology if the user is new to eye-tracking.
- [/support/fixation-filter](/support/fixation-filter) - fixation-filter parameters used by the export endpoints.
- [/support/data-export-all-csv-files-available](/support/data-export-all-csv-files-available) - the full CSV export inventory.
- [/support/licenses-pricing](/support/licenses-pricing) - license types, including the API module.
