set_chapter_intro

Set the structured front matter of an intro chapter.

PUT/v1/chapters/{collectionId}/intro
MCP tool set_chapter_introScope: writeStableSince 2026-09-17
Markdown

Editorial sections the viewer renders as the front matter: { coverKicker?, coverTitle? (default: the guide name), coverAuthor? (byline name, default: the creator), coverAuthorPhotoStorageId?, sections: [{ kind?: prose|chapters|collections, kicker?, title, deck?, paragraphs? (lines starting with "- " render as a list), cells?: [{ title, body }], photoStorageId?, photoCredit?, items? }] }. items only on chapters/collections sections, one per collectionId: chapters rows take { line?, color? (#rrggbb) }, collections cards take { title?, photoStorageId?, photoCredit? }. Rows and cards still derive from the guide; items only dress them. Photo ids come from the media upload endpoint with target=blob. Null clears. Chapters only.

curl -X PUT "https://sceniq.earth/api/v1/chapters/kn7q65ntqkryzm6y45h5dyxqt0p454y8/intro" \
  -H "Authorization: Bearer $SCENIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "intro": {
    "coverKicker": "A photographer'\''s field guide",
    "sections": [
      {
        "kind": "prose",
        "kicker": "How to use this guide",
        "title": "Timed for the light",
        "deck": "Every spot says when to be there and where to park, so the light and the crowds work for you.",
        "paragraphs": [
          "Each spot lists its best time of day, how crowded it gets and how far it is from the car. Most are short walks; the hikes are marked.",
          "- One day per park? Start with Top picks.\n- Check the park road status before a sunrise drive."
        ],
        "photoStorageId": "kg2gsfxz27kpg15n437vtmc3zj91qz34"
      },
      {
        "kind": "prose",
        "kicker": "Plan",
        "title": "Before you go",
        "cells": [
          {
            "title": "Passes",
            "body": "Each park charges 35 USD per vehicle for 7 days. An annual pass covers both."
          },
          {
            "title": "Seasons",
            "body": "Late May to September suits both parks. Some roads close from November."
          },
          {
            "title": "Driving",
            "body": "Yellowstone to Yosemite is about 1,400 km by road: two long days."
          },
          {
            "title": "Drones",
            "body": "Banned in every US national park."
          }
        ]
      },
      {
        "kind": "chapters",
        "kicker": "The parks",
        "title": "Two parks, a long drive apart",
        "items": [
          {
            "collectionId": "kn7e5r9t3y7v1j5p9p3a7s1d5f9g3h7j",
            "line": "Hot springs, geysers and bison",
            "color": "#b45309"
          },
          {
            "collectionId": "kn73r7x6mp88mxa9swcbshwd3e7zvr39",
            "line": "Granite walls and the valley from above",
            "color": "#1d4ed8"
          }
        ]
      },
      {
        "kind": "collections",
        "title": "Short on time",
        "items": [
          {
            "collectionId": "kn7a2s4d6f8g0h2j4k6k8z0x2c4v6b8n",
            "photoStorageId": "kg29fadcmt160qtrce3h3rm82yc6hhtb"
          }
        ]
      }
    ]
  },
  "expectedUpdatedAt": 1789895640000
}'

Path parameters

  • collectionIdstring · chapter idrequired

    Id of the chapter.

Body parameters

  • introChapterIntro or nullrequired

    The front matter object, or null to clear.

    Show 5 fieldsof ChapterIntro
    • coverKickerstringoptional

      The cover's eyebrow line, at most 120 characters (A Patagonia Field Guide).

    • coverTitlestringoptional

      The cover title, at most 160 characters. Absent means the guide's name.

    • coverAuthorstringoptional

      The byline name, shown as By <name>, at most 120 characters. Absent means the creator's display name.

    • coverAuthorPhotoStorageIdstring · stored file idoptional

      The byline photo, a storageId from an upload with target=blob. Absent means the creator's avatar.

    • sectionsarray of IntroSectionrequired

      Up to 20 sections in reading order.

      Show 9 fieldsof IntroSection
      • kindstringoptional

        prose (the default), chapters (a row for each other chapter of the guide) or collections (a card for each collection that has spots). The rows and cards derive from the guide; items only restyle them.

        prosechapterscollections
      • kickerstringoptional

        The eyebrow above the title, at most 120 characters.

      • titlestringrequired

        The section title, at most 160 characters. Required.

      • deckstringoptional

        The standfirst under the title, at most 500 characters.

      • paragraphsarray of stringsoptional

        Prose sections only: up to 30 paragraphs of at most 10,000 characters. Lines starting with "- " inside a paragraph render as a bulleted list.

      • cellsarray of objectsoptional

        Prose sections only: up to 8 numbered cells (a plan in steps). A section with cells carries no paragraphs and no photo.

        Show 2 fields
        • titlestringrequired

          The cell's title, at most 120 characters. Required unless the whole cell is empty, which drops it.

        • bodystringrequired

          The cell's text, at most 600 characters.

      • photoStorageIdstring · stored file idoptional

        Prose sections only: the side photo, a storageId from an upload with target=blob.

      • photoCreditstringoptional

        The side photo's credit, at most 80 characters, shown on the photo. Kept only with a photo; absent means the creator's own shot.

      • itemsarray of IntroItemoptional

        Chapters and collections sections only: up to 60 entries, each restyling one row or card.

        Show 6 fieldsof IntroItem
        • collectionIdstring · chapter idrequired

          The chapter (chapters section) or plain collection (collections section) of this guide the entry dresses, once per section.

        • titlestringoptional

          The name on the row or card, at most 120 characters. Absent means the chapter's or collection's name.

        • linestringoptional

          Chapters sections only: the short line under the name, at most 200 characters. Absent means the chapter's description.

        • colorstringoptional

          Chapters sections only: the row's color bar as #rrggbb (stored lower case).

        • photoStorageIdstring · stored file idoptional

          Collections sections only: the card photo, a storageId from an upload with target=blob. Absent means the collection's cover.

        • photoCreditstringoptional

          The card photo's credit, at most 80 characters. Kept only with a photo.

  • expectedUpdatedAtnumberoptional

    Optional staleness guard: the chapter's updatedAt you last read (list_chapters). The write is refused with stale_editor when the chapter changed since.

Returns

200 OK with this object.

  • okbooleanrequired

    Always true: the write went through.

    Always true

  • collectionIdstring · chapter idrequired

    The chapter's or collection's id.

Response 200
{
  "ok": true,
  "collectionId": "kn7q65ntqkryzm6y45h5dyxqt0p454y8"
}

Errors

Every error is { error: { code, message } }. Act on the code.

  • 400invalid_argumentA required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message).
  • 400invalid_requestA writer refused a value: a map link on a host that is not allowed, a title that is too long, a date that does not exist, too many items in a list. The message is the writer's own sentence.
  • 409stale_editorThe row changed after the expectedUpdatedAt you sent (update_chapter, save_sales_page_draft).
  • 401unauthenticatedThe request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key).
  • 401invalid_api_keyThe key is unknown, revoked or expired.
  • 403api_scope_requiredA read-only key called a write operation, or a key without the publish option called publish_changes.
  • 403forbiddenThe key belongs to a creator account that is no longer active.
  • 404not_foundThe id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists.
  • 413payload_too_largeA JSON body over 2 MB, an image over 6 MB, a batch upload over 19 MB, or an MCP message over 2 MB.
  • 429rate_limitedOver a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour.
  • 500internal_errorAn unexpected failure. The message is hidden on purpose.