# MIA SEO Agent contract Contract: `mia-seo-agent/v1`. Deployment origin: `https://mia-seo-sit.ambr.io`. Platform account page: `https://mia-platform-sit.ambr.io/account`. These URLs come from this deployment's explicit configuration; never replace a SIT origin with production. All API paths below are relative to the deployment origin. `/agent`, `/llms.txt` and `/skill.md` are generated from this single source. SEO owns website observations, all seven workflows and all 132 catalog checks, original citations, review receipts, jobs and reports. SEO never modifies or publishes a website. Actual AI citations belong to GEO. Unknown, failed, partial, unconfigured and not-run results remain distinct from passed checks. Inferred questions and publisher-authored questions are not observed user searches. ## Quick start Give the following instruction to an Agent whose runtime already holds the correct environment's credential. Never paste a token into a prompt or URL. ```text Read https://mia-seo-sit.ambr.io/llms.txt and use MIA SEO with the credential already configured in this runtime. Keep the intended Account and environment. Start with read-only capabilities and saved work; establish the scope and Mia Points budget before any billable operation. Recover an uncertain request by its original request ID. Do not request or print raw credentials. ``` ```text 读取 https://mia-seo-sit.ambr.io/llms.txt,使用运行环境已配置的凭证调用 MIA SEO。保持指定的 Account 和环境,先读取能力与已保存任务;付费操作前确定范围和 Mia Points 预算。请求结果不确定时使用原 request_id 恢复。不要索取或输出原始凭证。 ``` An Account-bound PAT is created in this environment's Platform account page. Confirm the exact Account before issuance and permit the `mia-seo` Product (or the Platform's all-Products mode). The PAT's bound Account supplies authority; adding an Account selector to a PAT request is rejected. Browser cookies, local Codex credentials and tokens from another environment are not substitutes. The following read-only HTTP requests are independent examples. Replace only the PAT placeholder in a private HTTP client, never in this document or a chat. ```http GET https://mia-seo-sit.ambr.io/api/seo/agent/v1/capabilities Authorization: Bearer GET https://mia-seo-sit.ambr.io/api/seo/agent/v1/sites?offset=0&limit=20 Authorization: Bearer ``` For existing work, use the returned site UUID to read its runs, reports and records before creating anything. Reuse a saved task; do not create a replacement site, rerun an interrupted scan or charge another request just to restore access. Creating a new scan below requires an agreed scope and budget. Placeholders are returned IDs; generate one fresh UUID for `request_id`, then retain it durably. ```http POST https://mia-seo-sit.ambr.io/api/seo/agent/v1/sites//runs Authorization: Bearer Content-Type: application/json {"request_id":"","continue_from":null} ``` On HTTP 202, retain `id`, `Location` and `Retry-After` and poll `GET /api/seo/agent/v1/runs/`. After an uncertain submission, first read `GET /api/seo/agent/v1/sites//runs/by-request/`. The source-tested HTTP flow below exercises these same real paths, with synthetic data and no external model call; it is not live semantic acceptance. ## Authentication and ownership Every `/api/seo/agent/v1` request requires Platform authority resolved by the SEO application using the official SDK. A human presents an Account-bound PAT in `Authorization: Bearer `. A first-party Service presents its own Platform Key in the same header and selects the exact `Mia-Account-Id`; optional `Mia-Initiated-By-User-Id` is attribution, never authority. Human credentials are never forwarded between Services. The Service Account Context is validated by Platform. Every site, run and report is looked up under the resolved owner. Absent or invalid authority fails closed; client JSON cannot select an owner. Cross-Account and missing resources both return 404. Local preview identities and saved local sessions are not Platform credentials or cloud Accounts. Service requests use `Authorization: Bearer ` with `Mia-Account-Id: `; `Mia-Initiated-By-User-Id` is optional. Do not send these selectors with a PAT. Personal funding fallback, delegated email headers and client-selected owner fields are not accepted by SEO. ## Available operations Call `GET /api/seo/agent/v1/capabilities` before writing. Its `capabilities.scan` indicates that the configured runner and admission path exist; the admission path can still reject policy, funding, budget or provider unavailability. `semantic_review` reports configured execution support, not successful review. The response lists unsupported features. Never invent prices, free allowances, completed checks or a site health score from UI prototypes. - `GET /sites?offset=0&limit=20` lists authorized sites. Pagination returns `items`, `offset`, `limit`, `total`; limit is 1–100. Site creation is available only when `site_creation` is enabled; see the binding operation below. - `POST /sites/{site_id}/runs` admits asynchronous work. Body: `{"request_id":"","continue_from":null}`. A 202 is acceptance, not completion. Retain the generated run `id`, `Location` and original `request_id`. - `GET /runs/{run_id}` reads current progress and terminal evidence references. - `GET /sites/{site_id}/runs/by-request/{request_id}` recovers an uncertain POST. After a network timeout, query this first and retry only the original request. - `POST /runs/{run_id}/cancel` requests cooperative cancellation. Poll until terminal; `cancel_requested=true` alone does not mean the worker has stopped. - `GET /reports/{report_id}?section=summary&offset=0&limit=20` reads frozen customer evidence. Sections are `summary`, `checks`, `pages`, `actions`, `unresolved`. Pages return `{id,site_id,status,section,items,offset,limit,total}`. Checks are paged by catalog point, with `instance_count` and `instances_url`. Read `GET /reports/{report_id}/checks/{check_id}?offset=0&limit=20` for paged literal instances; its section is `instances` and it includes `check_id`. No instance is silently treated as absent or passed when it is on another page. Each report-section envelope also exposes nullable `delivery_scope` when the report recorded an admitted scope. Its `subject_kind`, `review_workflows`, `page_capacity` and `external_research` describe that frozen admission, not completed work. Additional evidence/version fields may be retained. Null means the historical report did not record scope; never infer it from current policy, all-catalog check inventory or the saved site's requested checks. Unresolved items with category `out_of_scope` were not admitted in that report; they are not promises of later execution or reasons to resubmit paid work. All original check states and evidence remain available. - `GET /reports/{report_id}/export?format=json` downloads the whole customer report. `format=md`, `pdf` or `zip` reads the same complete public frozen snapshot. PDF renders all human report sections, catalog checks and literal evidence; its exact `report.json` attachment retains the complete public machine snapshot without printing that snapshot again as a second appendix. Markdown retains the full JSON appendix. Report ZIP contains only `report.json`, `report.md`, `report.pdf` and their SHA-256 `manifest.json`. Exports do not run a scan, fetch citations, call a model or incur new Points. Existing JSON-only Agent tools must retain their supported format until their consumer implements binary downloads; provider availability alone adds no tool. Exports do not apply the current page or filter. PDF/ZIP preparation returns HTTP 503 with `detail.error` of `seo_export_preparing` or `seo_export_busy` and `Retry-After: 2`; retry the same URL with a finite wait budget and save only HTTP 200 file responses. Other `seo_export_*` errors and `seo_pdf_unavailable` stop automatic retries; retain JSON/Markdown as complete alternatives. Preparation reads no source URLs and creates no scan or billed operation. All listed paths after the first are relative to `/api/seo/agent/v1`. IDs are UUID strings. Request objects reject unknown fields. Responses can gain optional evidence fields; consumers must preserve citations and provenance. ## Lifecycle, retries and limits Jobs progress through `queued`, `running`, then one of `completed`, `partial`, `failed`, `interrupted`. A completed job does not prove all semantic checks passed; read the report's per-check execution, readiness and verdict. Job fields include `id`, `site_id`, `request_id`, `continue_from`, `mode`, `status`, `stage`, `progress`, `report_id`, timestamps, `cancel_requested`, `can_continue` and a safe `error`. Poll no faster than `Retry-After` (currently 2 seconds). Clients should use a bounded wait and return the recoverable run ID when their wait budget expires. The same request ID and payload replays the same owned job. Reusing it with a changed continuation returns 409; a different request while that site already has active work returns `active_run`. Continuation requires an owned terminal parent with `can_continue=true`, the same site and a fresh request ID. Parent reports remain immutable. Cancellation and restart preserve available evidence; interrupted work is never silently resubmitted. Server-configured scan limits bound crawl size, elapsed time and bytes; limit exhaustion remains explicit. Missing runner or admission returns 503 (`seo_runner_unavailable` or `seo_admission_unavailable`). Other failures include 401 authentication, 403 Account authority, 404 `seo_resource_not_found`, 409 scan conflict, and 422 invalid input. Never retry 401/403/422 without correcting the cause; use the original request ID for a safe transport retry. No alternate provider is selected. ## Points, models and safety The SEO admission owner governs Points and consumption. Agent calls do not add a second charge. Unconfigured prices, budgets or billing must reject affected work with an explicit reason. No price or monthly allowance is promised here. Provider costs, credentials and strategy knowledge are internal and omitted from public responses. Customer Points receipts, when available from the admission owner, are the only basis for displaying charges. Jobs and report-section envelopes expose an optional `billing` receipt. It contains `operation_ref`, `operation`, `policy_version`, `unit`, `units`, `maximum_points`, `points_per_unit`, `reserved_points`, `released_points`, `points_consumed`, `final_units`, `state` and `pending`. Null amounts remain unconfirmed; never display them as zero or infer a charge from job completion. Financial confirmation can arrive after a terminal job. Read the same job or report again to obtain the current receipt without submitting new work. Reports' observed evidence remains frozen. These receipt fields carry no provider cost. Local Codex CLI review is a local-only transport. Its login and session files must never be placed in a cloud image. Cloud semantic execution must use an explicit configured formal transport and bounded budget; absent execution leaves semantic results unconfigured or not run. Google and Collector access is read-only and requires the actual owner's connection. Do not infer access from Account membership or copy another user's grants. Scheduling, callbacks, price estimates and website mutations are not supported by this facade. Scope and budget must be established before a live scan; synthetic source tests do not establish real semantic acceptance. ## Tested flow Discover capabilities and sites; retain the selected site UUID. Submit a fresh request UUID once. Poll or recover by that original UUID. Follow the returned report ID, page through all checks, and download full evidence when needed. The offline contract suite exercises this flow using synthetic HTML, isolation, idempotent replay, cancellation, unknown semantics and private-field redaction. Live acceptance must separately verify the released origin, Platform identity, Account isolation, bounded work and real evidence receipts. ## Website and improvement workflows These operations use the same prefix. Check `site_creation`, `business_records`, `draft_review` and `task_actions` in capabilities; absent admission returns 503. - `POST /sites` binds an explicit website. Supply a durable `request_id` UUID, `name`, public `url`, and optional `business`, `market`, `language`. The application's binding callback validates and durably replays the request. This creates an empty site; it does not import another user's data or start work. - `GET /sites/{site_id}/runs` and `/sites/{site_id}/reports` locate existing jobs and reports. Both use the same offset/limit pagination as site listing. - `GET /sites/{site_id}/business?section=findings` pages the actual business projection. Sections are demands/findings/records/page_plans/unresolved/pages/links; items retain the owner-generated `key` used as task `source_key`. The envelope includes site_id, section, latest_report_id, current_run and result_scope. Report action keys are also valid source keys; never invent one. - `GET /sites/{site_id}/records` pages existing planning, task, artifact and verification records. `GET /business/{identifier}` reads one owned record. - `POST /sites/{site_id}/tasks` creates an evidence-linked improvement task: `request_id`, `source_key`, `title`, `area` (research/technical/architecture/content), `plan`, `acceptance`, optional `target_url`, and `criteria` (field title/description/text/link with an exact expected value). The source is resolved against owned evidence. - `PATCH /tasks/{identifier}` supplies the current `version`, `status` and optional `implementation`. Status is proposed/ready/in_progress/implemented/paused/dismissed. `implemented` records a claim, never verification. `PUT /tasks/{identifier}/requirements` uses the same version guard to edit plan, acceptance, target URL and criteria. - `POST /tasks/{identifier}/artifacts` saves a supplied brief or draft with `request_id`, `format`, `title`, `body`, and optional `parent_id`. Draft history remains retained. Saving content does not publish it. - `POST /sites/{site_id}/draft-review` accepts `request_id`, `text`, optional `title`, `description`, `has_counterpart`, `is_revision`, `counterpart_text`, `before_text`. Unknown applicability remains unknown unless explicitly stated. It returns a job; read all W07 results (20 draft checks plus the current rule checks) in its resulting report. - `POST /tasks/{identifier}/actions` accepts `request_id`, current `version`, and `action` brief/draft/recheck. Recheck uses the existing exact-page verification owner and requires an implemented task with a target and acceptance criteria. Its verification record supplies observed evidence. Generated content remains an unpublished draft. Missing model or funding configuration must reject work. All writes require the same Account authority as reads. Immutable request IDs protect create operations; optimistic versions protect edits. A 409 requires reading current state, never silently replacing someone else's work. Site binding, paid execution, per-job budget and settlement belong to the application-injected controllers; this facade cannot bypass their gates.