Daily Blog Post Docs

Public API — Articles

List and read your articles over the authenticated public API, including everything needed to build a sitemap on your own domain.

Public API — Articles

The public API lets your own site (custom CMS integration) list and read the articles Daily Blog Post generated for your organization.

Connecting a site for the first time? Start with the step-by-step API setup brief: it orders these endpoints into four steps with an acceptance checklist, and can be handed to an AI coding agent. This page is the reference.

Authentication

Every request needs your organization API token (create it in Integrations → Public API), sent in the X-API-Key header:

curl -H "X-API-Key: $DBP_API_TOKEN" \
  "https://dailyblogpost.app/api/public/articles"

Authorization: Bearer is not accepted on these routes (it is the header of the MCP server only): a request without X-API-Key answers 401.

List articles

GET /api/public/articles

Query parameterDescription
statusDefaults to published: without it you receive the articles published from Daily Blog Post, plus the ones already sent to your site by the API integration that your site has not confirmed yet (so a static site can render them, then confirm them). Those articles carry their real status (usually generated), so do not filter on status === "published" on your side. status=published returns published articles only (sitemaps). Any other value answers 400: this API serves what you published from Daily Blog Post, nothing else — articles are written and reviewed in the app or through the MCP server, never previewed through this API.
page / limitPagination. limit is capped at 100.
localeFilter by article language (e.g. fr).
qSearch in titles.
updated_sinceISO date — only articles updated after it. Handy for incremental rebuilds.
sort / ordercreatedAt (default), updatedAt or publishedAt / asc or desc.

Each article in the response includes (non-exhaustive):

  • slug — the SEO slug, to build the URL on your domain
  • title, metaTitle, metaDescription, content (HTML), keywords
  • coverImageUrl, featuredImage
  • publishedAt, updatedAt, createdAt (ISO dates)
  • locale, status

Single article: GET /api/public/articles/{id} or GET /api/public/articles/by-slug/{slug}. Same rule: a published article, or one sent to your site and awaiting your confirmation; 404 otherwise. Any status other than published answers 400.

Why published only? A site that builds its blog from this API would otherwise show an article the moment Plume generated it, before anyone in your team read it. Publishing from Daily Blog Post is what makes an article appear here.

Static sites — when to rebuild

Reading the API never notifies your site: a statically generated blog (Astro, Next.js export, Hugo, Eleventy…) shows a newly published article only after its next build. Two ways to make sure that build happens:

  • Rebuild on a schedule (for example every hour) and pass updated_since so the build can stop early when nothing changed since the last one.
  • Let publishing trigger the build: point the API integration at your deploy hook or revalidation URL. It receives dailyblogpost.publish each time an article is sent to your site; answer 2xx, and return remote_url once the page exists. Until then the article stays unpublished on our side and is not counted as delivered, but the read API already serves it to you by default, so your build can render it and then confirm it.

Either way, confirm each article once it is online with the acknowledgement call: that is what turns "received" into "delivered" in your dashboard.

Recipe — sitemap for articles published via the API

If your site consumes Daily Blog Post through the API on your own domain, expose a dedicated sub-sitemap built from the list endpoint, then reference it from your main sitemap index:

  1. Fetch all published articles (paginate with limit=100): GET /api/public/articles?status=published&sort=publishedAt&order=asc&limit=100&page=1
  2. For each article, emit one <url> entry:
    • <loc> — the article URL on your domain, built from slug (e.g. https://example.com/blog/{slug})
    • <lastmod> — updatedAt
  3. Serve the result as e.g. https://example.com/sitemap-blog.xml and add it to your sitemap index:
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap><loc>https://example.com/sitemap-main.xml</loc></sitemap>
  <sitemap><loc>https://example.com/sitemap-blog.xml</loc></sitemap>
</sitemapindex>

Rebuild the sub-sitemap on a schedule (or on your deploy hook) and use updated_since to detect changes cheaply between rebuilds.

Push mode — the API integration

Instead of pulling, you can let Daily Blog Post push each article to your site the moment it is published: configure an API integration (Integrations → API) with your endpoint URL and an optional auth header.

Your endpoint receives a JSON POST for two event types, and must answer with a 2xx status:

  • { "type": "dailyblogpost.test", "sent_at": "…" } — sent by the Test connection button. No article attached: just answer 200 so the integration can be validated and activated.
  • { "type": "dailyblogpost.publish", "sent_at": "…", "article": { "id", "title", "content", "seo_title", "seo_description", "seo_slug", "keywords", "cover_image_url", "cover_image_alt" } } — sent for each article pushed to your site. Answer with { "remote_id": "…", "remote_url": "…" } so Daily Blog Post can record where the article lives on your site and mark it published. The push follows a redirect only between your apex domain and its www. variant, and only on 307/308 (a 301/302 on a POST is refused): point the endpoint at the final host.

Handle the two types explicitly (early-return 200 on dailyblogpost.test), and upsert on article.id so a re-publish updates the existing entry instead of duplicating it.

What your answer proves

Your 2xx answerStatus recorded in Daily Blog Post
Body with remote_url (or url, permalink, link) and/or remote_id (or id, itemId, item_id) — first non-empty field winsPublished — counted as delivered, the URL is shown in the dashboard.
Empty body, or a body without those fieldsReceived, not confirmed — the article stays unpublished in the dashboard (the Publish button can send it again; upsert on article.id makes that harmless) and no article.published webhook fires. It becomes published and delivered when a later push returns the URL, your site acknowledges it with remote_url, or the weekly check through your read endpoint finds it online. A bare 2xx to a re-push of an article you already confirmed keeps it delivered.
Non-2xxFailed — shown with the HTTP status on the integration card. Background publications are retried up to two more times; a manual publish is not retried until you click Publish again.

A 200 only proves that your endpoint received the payload. Static sites must also trigger a rebuild (deploy hook, CI job, revalidation) when they receive dailyblogpost.publish, otherwise the article is stored but never rendered — the dashboard cannot detect this unless you expose a read endpoint.

Acknowledge a publication (pull mode)

If your site pulls articles and publishes them itself, tell Daily Blog Post once an article is live, so it is marked published in the app:

POST /api/public/articles/{id}/publish (scope publish:write)

{ "provider": "api", "remote_id": "123", "remote_url": "https://example.com/blog/my-article" }

remote_url is required for a published acknowledgement: it is the public http(s) address of the article on your site, the only thing that lets Daily Blog Post show, check and count the article as delivered. Without it the call answers 422 with code: "remote_url_required" and nothing is recorded. Optional fields: remote_id, status (published by default, or pending / failed with an error_message), request_payload, response_payload.

A published acknowledgement goes through the same checks as the Publish button in the app. It answers 422 with code and issues when the article cannot be published: invalid_status (archived, consolidated or still generating), missing_content, missing_seo_slug or language_mismatch (article not in the language of your site), and remote_url_required when the address is missing (whatever the provider you acknowledge for). Only acknowledge articles you read from this API's default listing: it already applies these checks. /api/public/articles/unpublished is reserved to the WordPress plugin and answers 403 (wordpress_plugin_only) to any other caller.