Feature: Integration page documents every route an API key can call Superseded in part by roles_permissions_enforcement: the owner and admin 403 clauses now answer 403 "missing_permission" with the header X-Missing-Permission, decided by the caller's role permissions. An Admin can now invite and write sites, and a role without the needed permission is refused on routes that were open to every verified user. As a developer building on RenewCMS I want the API reference to cover content types, entries, built-in types, sites, authors and media purge So that I can use every route my API key can call without reading the source Background: Given the SPA route /integration of the verified back-office (static page, no /v1 call, web/ only) And the page follows docs/design/screens/integration.md, sections "Custom content types round" and "Final round" And the boards are IntegrationPage.dc.html, IntegrationSearch.dc.html and states 8c, 8d, 8f and 9a to 9j of "RenewCMS Screens Back-office.dc.html" And endpoint rows, groups, index and session-only sub-groups come from the catalogue the board builds with A(...), G, IDX and sessGroups And every sample and count follows the real API, not the board's illustrative values And the components are Nuxt UI v4 with design tokens only And every state is drawn in light and dark at 1440x900 and 390x844 And no state is date dependent Rule: Section index and Jump to Scenario: Index order Given the viewport is 1440x900 Then the sticky index lists, in this order: | Authentication | Articles | Search and sharing | Content types | Entries | Built-in types | Media | | Sites and authors | Images and variants | Users and invites | Settings | Session only | Errors | Notes | And on 390x844 the "Jump to" list shows the same items in the same order Scenario: Scroll-spy on Content types (state 9j) Given the Content types group is the section nearest the top of the page Then its index item has aria-current "true" and the 2 px --ui-primary bar And on mobile the "Jump to" select reads "Content types" and its open list marks that item Rule: Endpoint groups Scenario Outline: Group contents Then the group "" shows "" with these routes and access chips Examples: | group | count | routes | | Articles | 8 routes | unchanged (the 7 article routes and POST /v1/article/{id}/seo/check) | | Search and sharing | 2 routes | unchanged | | Content types | 5 routes | GET /v1/content-type/ and GET /v1/content-type/{key} Verified user; POST /v1/content-type/, PUT and DELETE /v1/content-type/{key} Owner or admin | | Entries | 5 routes | GET and POST /v1/content-type/{key}/entry; GET, PUT and DELETE /v1/content-type/{key}/entry/{id}, all Verified user | | Built-in types | 2 routes | GET /v1/builtin-type/ and GET /v1/builtin-type/{key}, Owner or admin | | Media | 11 routes | the 7 existing (including GET /v1/media/{id}); GET and PATCH /v1/media/purge-settings, GET /v1/media/purge-preview, POST /v1/media/purge, Owner or admin | | Sites and authors | 2 routes | GET /v1/site/ and GET /v1/author/, Verified user (the former Sites and Authors groups, merged) | | Users and invites | 6 routes | unchanged | | Settings | 1 route | unchanged | And every route of these groups carries the chip "API key OK" And the new groups appear in the order of the index Scenario: Group descriptions Then "Content types" reads "Define your own kind of content, like events or recipes. An owner or admin creates a type made of 1 to 50 ordered fields; the type then has its own entry routes." And "Entries" reads "Read and write the content of a custom type. Any verified user can write entries." And "Built-in types" says they are read-only through the API and that the keys are article, author, site, media and user Scenario: Field types reference above the Content types routes Then an anchor "ct-fields" sits above the first Content types route and is not an index item And a "Field types" table with columns Type, Value in an entry and Rules lists text, richtext, number, boolean, date, select, media and relation And a sample field object shows key capacity, label Capacity, type number, required true, unique false, default null, min 1, max 5000, options null, relation null Scenario: PUT badge Then the PUT method badge uses the PATCH colours Scenario Outline: Expanded cards show their request fields and errors (states 9a and 9c) When I expand "" Then the request table or query table shows "" And the Errors list shows "" Examples: | route | fields | errors | | POST /v1/content-type/ | key, name, icon, fields | 400, 401, 403 "Only owners and admins can do this.", 409 content_type_key_taken | | PUT /v1/content-type/{key} | name, icon, fields | 400, 401, 403, 404 content_type_not_found, 409 schema_incompatible | | DELETE /v1/content-type/{key} | No request body. | 401, 403, 404 content_type_not_found, 409 content_type_has_entries, 409 content_type_referenced | | GET /v1/content-type/{key}/entry | page, size (5, 25, 50 or 100), sort (id, created_at or updated_at, then :asc or :desc) | 400 "Invalid page, size or sort.", 401, 404 content_type_not_found | | POST /v1/content-type/{key}/entry | data | 400, 401, 404 content_type_not_found, 409 invalid_entry: title must be unique, 422 invalid_entry: capacity must be at most 5000 | | GET /v1/content-type/{key}/entry/{id} | No request body. | 400 "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).", 401, 404 entry_not_found, 404 content_type_not_found | | PUT /v1/content-type/{key}/entry/{id} | data | 400, 401, 404 entry_not_found, 404 content_type_not_found, 409 and 422 invalid_entry: | | GET /v1/builtin-type/{key} | No request body. | 401, 403, 404 builtin_type_not_found | And code-style captions show the literal body Scenario: Response samples follow the real API Then POST cards show only the JSON body, with no status line And the entries list Response is an object with items, total, page and size, not a bare array And an entry sample has id, content_type, data, created_by, updated_by, created_at, updated_at, media and relations And the entry media sample is keyed by the field key, for example cover And a built-in type sample has only key, name and fields, with no icon And 409 on an entry only happens when a unique field clashes; any other field error is 422 Scenario: GET /v1/media/ is paginated When I expand "GET /v1/media/" Then a "Query parameters" table lists page and size (5, 25, 50 or 100, default 25) next to q, hash, filter, sort and variants And the Response is an object with items, total, page, size and counts And the Errors list has a 400 row "The media query is invalid." Scenario: Media purge routes Then GET and PATCH /v1/media/purge-settings use the keys auto_purge_enabled, auto_purge_interval_days (1 to 365), last_purge_at and last_purge_merged And POST /v1/media/purge takes an optional fingerprint taken from purge-preview And its Response sample has exactly groups_total, groups_purged, merged, articles_updated, sites_updated, authors_updated and failed_groups And its description says failed_groups counts groups that could not be purged and the others were still purged And no sample uses articlesUpdated or count for the purge response Scenario: Sites and authors lists Then GET /v1/site/ lists sites And GET /v1/author/ has Query parameters page and size and returns an object with items, total, page and size Rule: Session only Scenario: Thirty-seven routes in six sub-groups (state 9e) Then the heading reads "Session only" and the count reads "37 routes, not available to API keys", derived from the data And the sub-groups are, in order: "System · owner only", "Sign in and account", "API key management", "Sites and authors writes", "Image variants", "Activity" And every /v1/system route is in "System · owner only", with PATCH /v1/settings And "Sign in and account" holds DELETE /v1/auth/register And each row is dashed, muted and cannot expand And each row that answers 403 to a key has the lock icon and the "Session only" chip; Log in, Log out, Register and Reset password keep their caption "Made for the browser. A key is ignored here, with no 403." and no chip And the banner is unchanged Rule: Errors table (state 9d) Scenario: Rows and copy Then the table has rows 400, 401, 403, 404, 409, 422, 429 and 500 And the 403 row lists "This action needs a real session.", "Only owners and admins can do this.", "Only the owner can do this." and "You must verify your account to access this resource." And the 403 row keeps its muted note about site SEO defaults And the 404 row adds content_type_not_found, entry_not_found and builtin_type_not_found And the 409 row lists content_type_key_taken, content_type_has_entries, content_type_referenced, schema_incompatible, a unique-value clash and the existing media and user examples And the 422 row lists "invalid_entry: " And a note says code-style text is the literal body And the old sentence saying there is no 409 or 422 row is gone Rule: Authentication copy Scenario: Key rights Then the API key card says requests act as the user who created the key, with that user's role And the page says a key can manage articles, media and users, and manage content types and entries, without the back-office And Note 1 gains the sentence "Owner and admin routes answer 403 to a key whose creator is neither." And the other authentication notes are unchanged Rule: Search covers the new routes Scenario: Index content Then the search index holds 85 endpoints: 42 documented, 37 session-only and 6 public auth And it includes the new endpoints, their body fields and query parameters, the events sample keys under data (title, starts_on, capacity, online, category, cover) as "Body field", and the new error codes and messages Scenario Outline: Queries and counts When I type "" in the palette Then the count and live region read "" And the notes are "" Examples: | query | announced | notes | | media | 17 results, showing 7 | Section Media reads "11 routes" | | 404 | 24 results, showing 7 | rows show an "Error" second line | | login | 2 results | Session only section reads "37 routes, not available to API keys" | | entry | 8 results, showing 7 | also matches "entries" | | capacity | 2 results | second line "Body field capacity" on POST and PUT entry | | schema_incompatible | 1 result | second line "Error" on PUT /v1/content-type/{key} | | content type | 12 results, showing 8 | Sections group lists Content types and Entries | Scenario: Cap line is singular for one Given exactly one endpoint is beyond the cap Then the line reads "1 more endpoint. Keep typing to narrow the list." And with several it reads "N more endpoints. Keep typing to narrow the list." Scenario: Selecting a new endpoint When I select PUT /v1/content-type/{key} Then the palette closes, the card is scrolled to, expanded and focused, and flashes for 1.5 s And the URL hash is #ep-ct-update And the index and "Jump to" read "Content types" Rule: Existing states stay Scenario: Unchanged behaviour Then states 1 to 7, 8a to 8h, the Images and variants section and the "Manage API keys" link behave as before And figures in the existing specs (media routes, result counts, session-only count, the 409 and 422 sentence) are corrected to this feature