Brandfine Docs
REST API

Posts

GET /external/posts and GET /external/posts/:slug

Two endpoints — paginated list and single-post-by-slug.

List

GET /external/posts?type=services&locale=en&page=1&limit=50
X-Api-Key: bk_live_xxx
QueryTypeDefaultNotes
typestringblogPost type slug. * for every type.
localestring(no filter)BCP47 code. Omit to fetch every locale.
pageint11-indexed.
limitint50Max page size.
force_limitintOpt past the 50-cap. Up to 1000.
includestring(none)Pass content to inline contentHtml / contentMarkdown.
qstringCase-insensitive substring on title + slug.

Response

{
  "items": [
    {
      "postId": "p_2N4r",
      "slug": "schengen-visa",
      "canonicalSlug": "schengen-visa",
      "title": "Schengen Visa",
      "metaDescription": "...",
      "imageUrl": "...",
      "tags": ["europe"],
      "category": { "id": "c_1", "slug": "visas", "name": "Visas" },
      "authorName": "...",
      "customConfig": { /* free-form */ },
      "publishedAt": "2026-03-12T08:00:00.000Z",
      "contentHtml": null,
      "contentMarkdown": null,
      "jsonLd": null
    }
  ],
  "pageInfo": {
    "page": 1,
    "limit": 50,
    "total": 54,
    "totalPages": 2,
    "hasNext": true,
    "hasPrev": false
  }
}

SDK

const posts = await bf.posts.list({ type: 'services', locale: 'en' })
// Pagination handled internally; caller gets a flat array.

Get by slug

GET /external/posts/schengen-visa?locale=en
X-Api-Key: bk_live_xxx

Returns the single post + a translations array listing every published locale variant. Each entry includes publishedAt so consumers can compute a cross-locale sitemap <lastmod> (max(publishedAt) across siblings) when one URL represents the whole article family.

{
  "postId": "...",
  "slug": "schengen-visa",
  "title": "Schengen Visa",
  "...": "...",
  "translations": [
    { "locale": "en", "slug": "schengen-visa", "publishedAt": "2026-03-12T08:00:00.000Z" },
    { "locale": "pt", "slug": "visto-schengen", "publishedAt": "2026-04-02T10:15:00.000Z" }
  ]
}

404 when the slug doesn't exist in the requested locale.

SDK

const post = await bf.posts.getBySlug('schengen-visa')
// → BrandfinePost | null  (null on 404)

publishedAt semantics — read before building a sitemap

publishedAt is the time of the last publish that actually changed content, not the time of first publish. Brandfine re-stamps it whenever an editor republishes a post with a different contentHash, and skips the bump on no-op republishes (clicking Publish without edits). That makes it the right value to feed into a sitemap <lastmod>:

<url>
  <loc>https://example.com/services/schengen-visa</loc>
  <lastmod>{post.publishedAt}</lastmod>
</url>

Two corollaries worth noting:

  • Draft edits don't move publishedAt. Saving a typo fix to the draft does nothing to the public URL or to this timestamp — the change only becomes visible (and publishedAt only bumps) when the editor hits Publish.
  • Unpublish → republish bumps it. Even with identical content, re-publishing after an unpublish bumps publishedAt since consumers may have dropped the URL during the gap.

On this page