Skip to main content

Developer Page Specifications

API Contracts

5 GET endpoints — /editorial/home · /industries/{slug} · /insights/{slugOrId} · /topics/{slug} · /authors/{slug}. Locale-aware, CDN-cacheable.

Complete

Five GET endpoints (listing, details, category, topic, author) + one POST (subscription). All cacheable at the CDN, all locale-aware, all returning consistent { items, meta, seo } envelope shapes.

1 · GET /api/editorial

  • Query: category? · topic? · author? · q? · sort (latest|most-read|editor-picks|long-reads|short-reads) · page · pageSize · lang.
  • Response: { featured: ArticleListItem[3], items: ArticleListItem[], mostRead: ArticleListItem[5], categories: CategoryItem[], topics: TopicItem[20], totalCount, pagination, seo }.
  • ArticleListItem: { id, slug, type, title, dek, excerpt, coverImageUrl, category{slug, name}, topics[], author{slug, displayName, role, avatarUrl}, publishedAt, readingTimeMinutes, isFeatured, isEditorPick, isPractical, viewCount }.
  • Cache: 300s public + 900s s-maxage. Invalidate on article publish/update.

2 · GET /api/editorial/{slug}

  • Response: { article: full EditorialArticle + bodyHtml, author: full EditorialAuthor, category: full EditorialCategory, topics[], images[], relatedArticles[<=6], mostRead[5], connectedSignals[<=8], translation?: { exists: bool, slug?, lang? }, seo: { metaTitle, metaDescription, canonicalUrl, ogImage, jsonLd, hreflang[] } }.
  • connectedSignals capped at 8 server-side. Full list available via /api/editorial/{slug}/signals?offset=8.
  • Cache: 600s public + 1800s s-maxage. Invalidate on article OR linked-entity update.
  • Errors: 404 unknown slug; 410 Gone when IsActive=false AND deliberately retired; 503 with retry-hint on infra failure (NEVER 500 to client).

3 · GET /api/editorial/categories/{slug}

  • Query: topic? · sort · page · pageSize · lang.
  • Response: { category: full EditorialCategory, featured?: ArticleListItem, items: ArticleListItem[], relatedCategories[3], totalCount, pagination, seo }.
  • 404 when unknown categorySlug (no fallback to full listing).

4 · GET /api/editorial/topics/{slug}

  • Response: { topic: full EditorialTopic, items: ArticleListItem[], mostReadInTopic[5], connectedEcosystem: { opportunities[<=4], files[<=4], startups[<=4] }, pagination, seo }.
  • connectedEcosystem is topic-specific: surfaces non-Editorial entities tagged with the same topic slug, capped at 4 per type.

5 · GET /api/editorial/authors/{slug}

  • Response: { author: full EditorialAuthor, stats: { totalArticles, articlesByType: {news, analysis, ...}, joinedDate }, latestArticles: ArticleListItem[], mostReadByAuthor[5], topicsCovered[], pagination, seo }.

6 · POST /api/subscriptions/editorial-digest

  • Body: { email, preferredLang, interestCategories[], consentPlatform (true), consentPartners?, source: 'listing'|'category'|'topic'|'article', articleIdContext? }.
  • Server: writes EditorialSubscription row + queues welcome email. Rate-limited 5/IP/hour.