Schemas

These schemas describe the current JSON responses returned by the Trident Public API (/api/v1/public).

Copy/paste TypeScript types

If you’re integrating without @trident/client, these types are a good starting point for strongly typed HTTP clients.

Common

export type ISODateTimeString = string;

export type PublicApiErrorResponse = {
  error: string;
};

// Returned when query params fail validation (400)
export type PublicApiValidationErrorResponse = {
  error: "Invalid query parameters";
  // Zod issues (subset)
  details: Array<{
    path: Array<string | number>;
    message: string;
    code?: string;
  }>;
};

Articles

export type PublicArticleProduct = {
  name: string;
  slug: string;
};

export type PublicArticleTerritory = {
  code: string;
  languageCode: string;
  locale: string;
};

export type PublicArticleSeoSummary = {
  title: string;
  metaDescription: string | null;
  targetKeyword: string | null;
  secondaryKeywords: string[];
};

// The API returns the article's structuredContent JSON as "content".
// It can be either the rich schema (preferred) or the legacy schema, or null.
export type PublicArticleContent =
  | StructuredArticleContent
  | LegacyStructuredArticleContent
  | null;

export type PublicArticleSummary = {
  id: string;
  title: string;
  slug: string;
  excerpt: string | null;
  content: PublicArticleContent;
  seo: PublicArticleSeoSummary;
  publishedAt: ISODateTimeString | null;
  product: PublicArticleProduct;
  territory: PublicArticleTerritory;
};

export type PublicPagination = {
  total: number;
  limit: number;
  offset: number;
  hasMore: boolean;
};

export type PublicArticlesListResponse = {
  data: PublicArticleSummary[];
  pagination: PublicPagination;
};

Single article

export type PublicArticleSource = {
  title: string;
  url: string;
  citationIndex: number;
};

export type PublicArticleSeoDetail = PublicArticleSeoSummary & {
  // JSON-LD or other schema markup stored for the article
  schemaMarkup: unknown | null;
};

export type PublicArticleTerritoryDetail = PublicArticleTerritory & {
  name: string;
};

export type PublicArticleDetail = {
  id: string;
  title: string;
  slug: string;
  excerpt: string | null;
  content: PublicArticleContent;
  seo: PublicArticleSeoDetail;
  wordCount: number | null;
  publishedAt: ISODateTimeString | null;
  updatedAt: ISODateTimeString;
  product: PublicArticleProduct;
  territory: PublicArticleTerritoryDetail;
  sources: PublicArticleSource[];
};

export type PublicArticleDetailResponse = {
  data: PublicArticleDetail;
};

Sitemap

export type PublicSitemapEntry = {
  slug: string;
  productSlug: string;
  languageCode: string;
  territoryCode: string;
  publishedAt: ISODateTimeString | null;
  updatedAt: ISODateTimeString;
};

export type PublicSitemapResponse = {
  entries: PublicSitemapEntry[];
};

Structured content schema (rich)

The rich schema is designed for rendering with block-aware components (paragraphs, lists, tables, code, images, etc).

export interface FormattedText {
  text: string;
  bold?: boolean;
  italic?: boolean;
  link?: string;
  code?: boolean;
}

export interface RichParagraph {
  segments: FormattedText[];
}

export interface ListItem {
  content: FormattedText[];
  children?: ListItem[];
}

export interface ContentList {
  listType: "ordered" | "unordered";
  items: ListItem[];
}

export interface ContentTable {
  caption?: string;
  headers: string[];
  rows: Array<{ cells: Array<{ content: FormattedText[]; header?: boolean }> }>;
}

export interface CodeBlock {
  language?: string;
  code: string;
}

export interface ContentImage {
  src: string;
  alt: string;
  caption?: string;
}

export interface BlockQuote {
  content: RichParagraph[];
  attribution?: string;
}

export interface Callout {
  type: "tip" | "warning" | "note" | "example";
  content: string;
}

export interface ContentBlock {
  blockType: "paragraph" | "list" | "table" | "code" | "image" | "quote" | "callout";
  paragraph?: RichParagraph;
  list?: ContentList;
  table?: ContentTable;
  codeBlock?: CodeBlock;
  contentImage?: ContentImage;
  quote?: BlockQuote;
  callout?: Callout;
}

export interface CallToAction {
  text: string;
  buttonText?: string;
  targetUrl?: string;
}

export interface SourceCitation {
  title: string;
  url: string;
  citationIndex: number;
}

export interface ArticleSection {
  heading: string;
  headingLevel: 2 | 3;
  content: ContentBlock[];
  keyPoints?: ContentList;
}

export interface RichFAQItem {
  question: string;
  answer: RichParagraph;
}

export interface StructuredArticleContent {
  title: string;
  metaDescription: string;
  sections: ArticleSection[];
  callToAction: CallToAction;
  sources: SourceCitation[];
  faq?: RichFAQItem[];
}

Structured content schema (legacy)

Older articles may use a legacy shape (string paragraphs + key points). Your renderer should support both.

export interface LegacyArticleSection {
  heading: string;
  headingLevel: 2 | 3;
  paragraphs: string[];
  keyPoints: string[];
  callouts?: Callout[];
}

export interface LegacyFAQItem {
  question: string;
  answer: string;
}

export interface LegacyStructuredArticleContent {
  title: string;
  metaDescription: string;
  sections: LegacyArticleSection[];
  callToAction: CallToAction;
  sources: SourceCitation[];
  faq?: LegacyFAQItem[];
}