---
title: "Move a page to the surface registry"
method: POST
path: "/corroborations/{id}/convert-to-surface"
tags: ["Corroborations"]
---

# Move a page to the surface registry

`POST /corroborations/{id}/convert-to-surface`

## Request

- Base URL: `https://api.epovest.com/v1`
- URL: `https://api.epovest.com/v1/corroborations/{id}/convert-to-surface`
- Auth: HTTP bearer

When the customer has, or takes, the final say on it: their own profile filed on the wrong
side, or a source that became a reliable channel. Nothing is retyped: `url`, `label` and
`notes` travel, the publication date is copied into the notes, the type derives from the
address. A replay finds the same line instead of duplicating it (`201` on creation, `200`
when the page already slept in the surface registry and was brought back). Manager or above.

## Response `200`

The surface already existed and was brought back.

- SurfaceEnvelope
  - `surface` Surface, required
    - `id` string, uuid, required
    - `project_id` string, uuid, required
    - `type` 'website' | 'github' | 'linkedin' | 'x' | 'youtube' | 'wikidata' | 'directory' | 'app_store' | 'other', required: Derived from the address when a surface is registered: a page whose registrable domain is the canon website is `website`, a known place carries its own kind, and any other host is `other`, which carries the generic checklist.
    - `url` string, required
    - `label` string, nullable, required
    - `languages` string[], required: Short language codes. They ARE the columns of the checklist.
    - `notes` string, nullable, required
    - `status` 'aligned' | 'needs_update' | 'never_aligned', required: Derived on read from the checklist cells that hold it, the ones listed in `checklist.required`: `aligned` (every required cell not set aside is verified at the current wording), `needs_update` (a verification is missing or stale), `never_aligned` (none exists yet).
    - `alignment` object, nullable, required: The last journal line.
      - `canon_version` integer
      - `aligned_at` string, date-time
      - `author` string, nullable
    - `checklist` Checklist, required
      - `items` string[], required: The template of the type, with stable keys such as `title_tag` or `llms_txt`, followed by the checks the customer added of their own.
      - `site_items` string[], required: The items that are site-wide, one cell for the whole site, under the `site` column.
      - `kinds` object, required: The kind of each item.
      - `required` string[], required: What HOLDS the status: the canon items of the template plus every check of the customer, whatever its kind. Read this list rather than deducing from `kinds`.
      - `custom` CustomCheck[], required: The definitions of the checks of the customer, the ones taken out included.
        - `key` string, required
        - `label` string, required
        - `scope` 'language' | 'site', required: `language` is one cell per language of the surface, `site` one cell for the whole site.
        - `restates_canon` boolean, required
        - `deleted` boolean, required
        - `deleted_at` string, date-time, nullable, required
        - `created_at` string, date-time, required
      - `state` object, required: The flat view of the verified items, per column.
      - `cells` object, required: The detail of each cell, per column then per item.
      - `progress` object, required: What holds at the current wording, over the cells that are not set aside, with the set-aside ones counted apart.
        - `done` integer, required
        - `total` integer, required
        - `dismissed` integer, required
    - `domain_authority` DomainAuthority, required: The join with the Atlas: what the AIs grant the DOMAIN the page sits on. An AI absent from `engines` has not cited the domain lately, and a `source_id` of null says the domain is not on the map of this account, which grows as you measure more.
      - `domain` string, required: The registrable domain read from the address by the same normalisation as the map.
      - `source_id` string, uuid, nullable, required
      - `engines` EngineAuthority[], required
        - `engine` 'chatgpt' | 'claude' | 'gemini' | 'perplexity' | 'mistral' | 'grok', required: The AI assistants the questions are asked to.
        - `aa` integer, required
      - `last_detected_on` string, date, nullable, required
    - `deleted` boolean, required
    - `deleted_at` string, date-time, nullable, required
    - `created_at` string, date-time, required

## Other responses

- `201`: The surface, registered.
- `401`: `unauthenticated`: missing, unknown or revoked key.
- `403`: `insufficient_scope`: the credential may not do this, either because the key lacks the scope, or, on a one-click connection, because the person lacks the role the action needs (manager, or owner to start, pause and top up). On that path, read it as "this person may not do this" and tell them which role the action needs.
- `404`: `not_found`: unknown for this account.
- `429`: `rate_limited`: 120 requests per minute per credential, sliding window. Retry after `Retry-After` seconds.

---

[API](https://skmtc.dev/epovest/apis/epovest-api.md) · [All operations](https://skmtc.dev/epovest/apis/epovest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/epovest/apis/epovest-api/revisions/7a78ee27ecbb?raw)
