Documentation/Liveblog Headless CMS

Liveblog — Introduction & Key Points (headless)

Render your own Liveblog front-end from the Timepath data API — consume the Introduction block, key points, and update stream as structured JSON.

Headless / APIFor editors & developers

Introduction

Timepath Liveblog delivers real-time event coverage. In headless mode you render your own front-end from our API instead of using the Timepath embed — you fetch the structured content and build your own components around it.

This page is for two audiences: editors who author the Liveblog Introduction, and developers who consume the data and render their own components. It applies to every Timepath client — the schema and endpoint are the same for all organizations.

The Liveblog Introduction is the header block that appears above the update stream. It is composed of four movable sections:

  1. 1

    Media header

    Image, video, or embed shown at the top of the block.

  2. 2

    Introduction

    A short rich-text intro paragraph.

  3. 3

    Summary title

    The heading above the key points.

  4. 4

    Key points

    Short takeaways ("Kernpunten" / "Hoofdpunten" in Dutch), each of which can optionally link to a liveblog update or to an external article.

For editors: adding key points

  1. 1

    Open the Introduction editor

    Open the liveblog and click the Introduction editor (Cover Studio).

  2. 2

    Open the Key points block

    In the rail, open the Key points block.

  3. 3

    Add a key point

    Click Add key point and type the text. Wrapping text in **double asterisks** renders it bold.

  4. 4

    Choose the link target

    Use the toggle on the key point to pick where it links (see the two options below).

  5. 5

    Reorder, remove, and save

    Reorder or remove key points with the row controls. Save to publish.

The two link targets:

Update

Search and pick an existing liveblog update. Clicking the key point scrolls the reader to that update. If the linked update is later deleted, the editor shows an "Update deleted" warning and the key point falls back to plain text.

External link

Paste a URL to another article (e.g. https://…). Clicking the key point opens that URL in a new tab. Invalid URLs show a warning and are not linked.

A key point with no link chosen renders as plain (non-clickable) text.

(Screenshots: the Key points block, the Update picker, and the External-link input — add the ones from the walkthrough here.)

For developers: consuming the data

Everything below describes the headless data contract. Because you render your own components, the structured fields are the source of truth.

The data endpoint

Use the data endpoint, not metadata. The metadata endpoint omits all cover / intro fields — only data returns the Introduction block and key points.
Header auth — x-api-key
http
GET https://embed.timepath.co/api/external/liveblog/data
      ?liveblogId={liveblogId}
      &eventsToShow={n}     # optional, default 25
      &offset={n}           # optional, default 0

Header:  x-api-key: <your organization API key>

Example request:

bash
curl "https://embed.timepath.co/api/external/liveblog/data?liveblogId=abc123&eventsToShow=25&offset=0" \
  -H "x-api-key: YOUR_ORGANIZATION_API_KEY"

Query parameters:

ParameterRequiredDefaultNotes
liveblogIdYesThe liveblog to fetch.
eventsToShowNo25Number of updates to return per page.
offsetNo0Number of updates to skip (pagination).

Response shape

A single response returns the liveblog object (the Introduction block plus styling), the paginated liveblogevents array (the update stream), and pagination metadata.

jsonc
{
  "liveblog": {
    "id": "abc123",

    // ── INTRODUCTION ──────────────────────────────
    "cover_media": {                 // header media, nullable
      "type": "image",              // "image" | "video" | "embed"
      "url": "https://…",
      "caption": "…",
      "credits": "…"
    },
    "cover_intro_body": "<p>…</p>",  // introduction, rich-text HTML
    "cover_summary_title": "…",      // heading shown above the key points

    // ── KEY POINTS ────────────────────────────────
    "cover_summary_items": [
      {
        "id": "cuid…",
        "text": "**bold** supported markdown",
        "link_type": "update",       // "update" | "external"  ← authoritative
        "event_id": "evt789",        // set when link_type = "update"; else null
        "event_title": "…",          // ⚠ internal display cache — do NOT rely on it
        "external_url": null          // set (string) when link_type = "external"
      }
    ],

    // ── LAYOUT & STYLING (optional to consume) ────
    "cover_section_order": ["media","intro","summary_title","key_points"],
    "cover_section_order_v": 2,      // honour cover_section_order only when >= 2
    "color_header_keypoints": "#000000",             // text / link colour
    "color_header_keypoints_background": "#eef2ff",  // box background
    "header_keypoints_background_opacity": 100,      // 0–100
    "header_keypoints_padding": 20,  // px
    "header_keypoints_radius": 14,   // px

    // ── CONVENIENCE (optional) ────────────────────
    "cover_body": "<…pre-rendered HTML of the whole intro…>"
  },

  "liveblogevents": [
    {
      "id": "evt789",                // matches cover_summary_items[].event_id
      "title": "…",
      "date":    { "seconds": 1720345678 },  // Firestore timestamp
      "created": { "seconds": 1720345600 },
      "body": "<…>", "pinned": false
    }
  ],
  "totalEvents": 42, "offset": 0, "limit": 25, "hasMore": true
}

Relative time per key point ("2 hours ago")

Relative time is not stored on the item. Resolve event_id against liveblogevents, take the linked event's date.seconds (fallback created.seconds), and compute the relative time yourself.

External-linked key points have no associated time.

Fields to treat as internal (do not depend on)

  • event_title

    A denormalized display cache. It can go stale (it is not cleaned when an update is deleted). Resolve the real title from liveblogevents using event_id.

  • cover_body

    A pre-rendered HTML snapshot, baked when the editor saves. Convenient, but it can lag the structured fields. For custom rendering prefer the structured fields (cover_intro_body, cover_summary_items).

  • Key-points box heading label

    The box label ("Key points" / "Hoofdpunten") is derived from the liveblog's language, not a payload field. cover_summary_title is a separate, editor-set heading. Supply and localize the box label yourself.

Field reference — a key point

Each entry in cover_summary_items[]:

FieldTypeNotes
idstringStable client id.
textstring**bold** markdown supported.
link_type"update" | "external"Authoritative. Absent on legacy items ⇒ treat as "update".
event_idstring | nullLinked update id (when link_type = update). Resolve against liveblogevents.
event_titlestring | nullInternal display cache — do not rely on it.
external_urlstring | nullExternal article URL (when link_type = external).

FAQ

Questions or need an absolute update URL / a pinned, versioned payload schema? Visit the support centre or contact us.

Subscribe for updates

Stay up to date by subscribing to our newsletter