Structured data

Learn about new Public API v1 fields for Article/FAQ structured data, FAQ extraction rules, and sitemap lastmod freshness behavior for Leafpad integrations.


This release adds SEO-focused enhancements to /api/public/v1 with an API-first approach so both Leafpad and external customers get the same behavior.

What Changed

1) Richer Article fields on post responses

Post endpoints now include fields that support stronger schema generation:

  • wordCount

  • articleSection

  • inLanguage

  • isAccessibleForFree

2) FAQ extraction and FAQPage schema support

For single-post responses, Leafpad now parses post HTML and detects FAQ candidates from h2/h3 headings ending with ?. Valid Q/A pairs are returned as faqEntries, and JSON-LD is returned under structuredData.faqPage when eligible.

3) Sitemap freshness hardening

Sitemap endpoints continue using updatedAt as primary freshness signal and now fall back to createdAt when needed, avoiding stale or invalid lastmod values.

Endpoints Affected

  • GET /api/public/v1/post/{organizationSlug}

  • GET /api/public/v1/post/{organizationSlug}/{slug}

  • GET /api/public/v1/post/{organizationSlug}/sitemap

  • GET /api/public/v1/sitemap/{organizationSlug}

Response Additions

List posts: GET /api/public/v1/post/{organizationSlug}

{
  "posts": [
    {
      "id": 123,
      "name": "Example",
      "slug": "example",
      "wordCount": 1387,
      "articleSection": "SEO",
      "inLanguage": "en-US",
      "isAccessibleForFree": true
    }
  ]
}

Single post: GET /api/public/v1/post/{organizationSlug}/{slug}

{
  "id": 123,
  "name": "Example",
  "slug": "example",
  "wordCount": 1387,
  "articleSection": "SEO",
  "inLanguage": "en-US",
  "isAccessibleForFree": true,
  "faqEntries": [
    {
      "question": "What is programmatic SEO?",
      "answer": "Programmatic SEO is ..."
    }
  ],
  "structuredData": {
    "article": {
      "@context": "https://schema.org",
      "@type": "Article",
      "headline": "Example",
      "wordCount": 1387,
      "articleSection": "SEO",
      "inLanguage": "en-US",
      "isAccessibleForFree": true,
      "speakable": {
        "@type": "SpeakableSpecification",
        "cssSelector": [
          ".blog-post-title",
          ".blog-post-description",
          ".blog-post-content p"
        ]
      }
    },
    "faqPage": {
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {
          "@type": "Question",
          "name": "What is programmatic SEO?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Programmatic SEO is ..."
          }
        }
      ]
    }
  }
}

FAQ Extraction Rules

  • Only h2/h3 headings ending in ? are treated as FAQ questions.

  • Answer text is collected from sibling content until the next heading.

  • Duplicate questions are de-duplicated (case-insensitive).

  • structuredData.faqPage is emitted only when at least 2 valid Q/A pairs are found.

Sitemap Freshness Behavior

  • lastmod uses updatedAt when available.

  • If updatedAt is missing/invalid, it falls back to createdAt.

  • The root sitemap entry uses the latest valid post timestamp (or current time when no posts exist).

Backward Compatibility

These are additive changes. Existing fields and endpoint contracts are preserved. Consumers that do not use the new properties can continue unchanged.

Implementation Guidance for Integrators

  • Prefer structuredData.article for Article JSON-LD rendering.

  • Render structuredData.faqPage only when present.

  • If you generate your own schema, keep it consistent with visible page content.

  • Continue using sitemap endpoints for crawler recrawl signals.

Versioning Note

No path/version bump is required. This update is non-breaking under /api/public/v1.

Published with LeafPad