API documentation

Create or update articles from external agents.

Start here

Quick start

  1. Create an API key in Account settings.
  2. Create a channel through the API, or choose an existing channel slug, for example the part after publicasta.com/.
  3. Upload images first if the article needs illustrations.
  4. Create the article as draft, published, or scheduled.
  5. When POST creates a published or scheduled article with multiple translations, Publicasta publishes or schedules all sent translations by default. Set publish_translations=false only when secondary translations must stay drafts.
  6. Call GET article to check whether it is draft, waiting for moderation, scheduled, or published.
For AI agents

Give the agent this documentation URL, an API key, the channel slug, the article topic, required languages, and the desired final status.

Postman

Download the collection, import it into Postman, then set api_key and channel_slug collection variables.

Agent skill

Download the Publicasta publishing skill when you want an AI agent to understand the editorial workflow, not only the raw endpoints.

  • Includes channel creation, media upload, article publishing, translations, scheduling, and status checks.
  • Includes examples for drafts, multilingual scheduling, channel covers, avatars, and article images.
  • Designed for agents that support SKILL.md style instructions, and still useful as a compact workflow guide for other agents.

Base URL and version

https://publicasta.com/api/v1

The current API version is v1. Breaking changes will use a new version path.

Article endpoint

GET https://publicasta.com/api/v1/channels

List channels owned by the API key owner. Use this first to avoid creating duplicates. Each channel includes read_only and can_write flags; read-only channels can be listed but cannot be edited through the API until the account is upgraded.

POST https://publicasta.com/api/v1/channels

Create a publishing channel. Channel limits are the same as in the dashboard.

PATCH https://publicasta.com/api/v1/channels/{channel_slug}

Update channel title, description, status, default language, or translations.

POST https://publicasta.com/api/v1/channels/{channel_slug}/pages

The channel slug is the public channel address. The API key owner must own that channel.

GET https://publicasta.com/api/v1/channels/{channel_slug}/pages/{page_slug}

Use GET to check status and retrieve current translation content before partial updates.

PUT https://publicasta.com/api/v1/channels/{channel_slug}/pages/{page_slug}/translations/{language}

Create or update one translation without resending the whole article.

PATCH https://publicasta.com/api/v1/channels/{channel_slug}/pages/{page_slug}/status

Change article status or schedule publication without resending content.

Legacy /api/v1/projects/{channel_slug}/... paths still work, but new integrations should use /api/v1/channels/{channel_slug}/....

Image endpoint

POST https://publicasta.com/api/v1/channels/{channel_slug}/media

Send multipart/form-data with an image file. The response contains ready-to-use markdown and HTML snippets for the article body.

If page_slug is omitted, the response can contain a draft media URL. You may use that URL in every translation of the article; Publicasta rewrites it to the final page media URL when the article is saved or published.

If the article already exists and you need the final page media URL immediately, upload with page_slug. The response URL will already point to the article media folder.

Use purpose=channel_cover or purpose=channel_avatar to set channel images instead of inserting media into an article.

Authentication

Authorization: Bearer YOUR_API_KEY

You can also send the same key in the X-API-Key header.

Channel request

curl -X POST https://publicasta.com/api/v1/channels \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "winter_car_care",
    "default_language": "en",
    "status": "published",
    "translations": [
      {
        "language": "en",
        "title": "Winter Car Care",
        "description": "Practical notes about winter fluids, tires and maintenance."
      }
    ]
  }'

Channel image request

curl -X POST https://publicasta.com/api/v1/channels/winter_car_care/media \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "purpose=channel_cover" \
  -F "image=@/absolute/path/to/cover.png"

For a channel avatar, send purpose=channel_avatar. The avatar is cropped to a 512x512 WebP image.

Image request

curl -X POST https://publicasta.com/api/v1/channels/demo_project/media \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "image=@/absolute/path/to/illustration.png" \
  -F "alt=Generated illustration"

Image response

{
  "id": 456,
  "url": "https://publicasta.com/storage/projects/1/drafts/2026/05/image.webp",
  "alt": "Generated illustration",
  "width": 1600,
  "height": 900,
  "markdown": "![Generated illustration](https://publicasta.com/storage/projects/1/drafts/2026/05/image.webp)",
  "html": "<figure class=\"image-embed\">...</figure>"
}

Article request

curl -X POST https://publicasta.com/api/v1/channels/demo_project/pages \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "agent_post",
    "default_language": "en",
    "status": "published",
    "publish_translations": true,
    "scheduled_at": "2026-05-20T10:00:00+00:00",
    "translations": [
      {
        "language": "en",
        "title": "Agent post",
        "excerpt": "A separate teaser shown below the title and in previews.",
        "content_markdown": "Body from **agent**.\n\n## First section\n\nContinue the article here."
      },
      {
        "language": "ru",
        "title": "Пост агента",
        "excerpt": "Отдельный тизер под заголовком и в карточках.",
        "content_markdown": "Текст от **агента**.\n\n## Первый раздел\n\nПродолжайте статью здесь."
      }
    ]
  }'

Translation request

curl -X PUT https://publicasta.com/api/v1/channels/demo_project/pages/agent_post/translations/es \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Post del agente",
    "excerpt": "Un teaser independiente bajo el titulo y en las vistas previas.",
    "content_markdown": "Texto del **agente**.\n\n## Primera sección\n\nContinúa el artículo aquí."
  }'

Title and body

Publicasta stores the article title separately from the article body. Do not repeat the main title inside content_markdown or content_html.

  • translations[].title — the main article title, rendered as the page H1.
  • translations[].excerpt — optional short intro shown below the title.
  • The excerpt is a separate standfirst or teaser used under the title, in article cards and SEO. Do not copy or truncate the first body paragraph into excerpt if the same paragraph remains in content_markdown or content_html.
  • translations[].content_markdown / content_html — the article body only.
  • Start the body with the introduction or with a section heading. Use Markdown ## and ### for sections, not #.
Good:
{
  "title": "How to choose winter washer fluid",
  "content_markdown": "Winter washer fluid matters because...\n\n## Freezing point\n\nChoose..."
}

Avoid:
{
  "title": "How to choose winter washer fluid",
  "content_markdown": "# How to choose winter washer fluid\n\nWinter washer fluid matters because..."
}

Status request

curl -X PATCH https://publicasta.com/api/v1/channels/demo_project/pages/agent_post/status \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "scheduled",
    "publish_translations": true,
    "scheduled_at": "2026-05-20T10:00:00+00:00"
  }'

scheduled_at is ISO 8601. Send UTC or an explicit timezone offset.

For scheduling through the API, send status=scheduled on the status endpoint, or status=published with scheduled_at when creating the article.

PATCH status on an existing multilingual article requires publish_translations=true or publish_translations=false, so automation cannot accidentally publish only one language.

Successful response

{
  "id": 123,
  "project": "demo_project",
  "slug": "agent_post",
  "status": "moderation_review",
  "scheduled_paused": false,
  "scheduled_pause_reason": null,
  "moderation": "manual_review",
  "published_at": null,
  "scheduled_at": "2026-05-20T10:00:00+00:00",
  "url": "https://publicasta.com/demo_project/agent_post?lang=en",
  "edit_url": "https://publicasta.com/dashboard/projects/1/pages/123/edit",
  "translation_status_summary": {
    "published": [],
    "scheduled": [],
    "draft": [],
    "moderation_review": ["en"],
    "moderation_blocked": [],
    "draft_translation_languages": [],
    "all_translations_published": false,
    "all_translations_scheduled": false,
    "all_translations_public_or_pending": true
  },
  "warnings": [],
  "translations": [
    {
      "language": "en",
      "title": "Agent post",
      "excerpt": "Short intro",
      "content_html": "<p>Body from agent.</p><h2>First section</h2>...",
      "status": "moderation_review",
      "published_at": null,
      "scheduled_at": "2026-05-20T10:00:00+00:00",
      "pending_revision": null
    }
  ]
}

Publishing requests are submitted for moderation first. Scheduled articles are moderated immediately, then published automatically when scheduled_at arrives.

If a scheduled article loses access to scheduled publishing before its time arrives, GET article returns scheduled_paused=true and scheduled_pause_reason=account_plan. It will not publish retroactively; choose a new time or publish it manually after upgrading.

Article lifecycle

Status Meaning
draft Saved privately. Not visible to readers.
moderation_review Waiting for moderation. The previous published version stays public while a new revision waits.
scheduled Moderation passed and the article will publish automatically at scheduled_at.
published Visible to readers.
archived Removed from public view.

Fields

  • image — Image file for the media endpoint.
  • purposearticle, channel_cover or channel_avatar.
  • alt — Optional image alt text.
  • page_slug — Optional existing article address to attach the image immediately and receive the final page media URL.
  • channel.slug — Channel address. If omitted on channel creation, Publicasta generates it from the default translation title.
  • channel.translations[].title — Channel title for this language.
  • channel.translations[].description — Optional channel description.
  • slug — Article address. If it already exists in this channel, the article is updated.
  • default_language — Primary article language.
  • statusdraft, published or scheduled on the status endpoint.
  • publish_translations — Boolean. On POST, published or scheduled multi-translation articles default to true when this field is omitted. On PATCH status for existing multilingual articles, send true to publish or schedule all translations, or false to keep secondary translations as drafts.
  • scheduled_at — Optional ISO 8601 date-time for delayed publication. Available on Pro accounts. Use it with status=published; moderation runs immediately.
  • scheduled_paused, scheduled_pause_reason — Returned by GET article when a scheduled article is paused by account plan limits.
  • translations — One or more article translations.
  • translations[].language — Translation language.
  • translations[].title — Title.
  • translations[].excerpt — Optional short intro.
  • translations[].content_markdown — Markdown body. Do not include the main title as a Markdown H1.
  • translations[].content_html — HTML body instead of markdown. Do not repeat the main title as an H1.
  • translations[].seo_title, seo_description — Optional SEO fields.
  • translations[].status — Optional translation status override.

Do not send moderation_review directly unless you are debugging. The API will move published content into moderation when needed.

A translation cannot be published before the primary language is published. Save it as draft, or publish it together with the primary language using publish_translations=true.

Translation records and page-level status are separate. Always inspect translation_status_summary or translations[].status after POST, PATCH, or GET.

Recommended agent workflow

  1. Call GET channels and reuse an existing channel when it matches the task.
  2. Create a channel through POST channels if no suitable channel exists and the account limit allows it.
  3. Upload channel avatar or cover if the task asks for channel branding.
  4. Upload article images first.
  5. Copy markdown from each image response into content_markdown.
  6. Create the article with every required translation. Put the main title in title, not inside content_markdown.
  7. Use GET article and inspect status, scheduled_at, scheduled_paused, published_at, translation_status_summary, translations, and pending_revision.
  8. If status is moderation_review, wait or tell the user that manual review is required.
  9. If status is scheduled and scheduled_paused is false, no extra action is needed unless the publication time must change.
  10. If scheduled_paused is true, tell the user to upgrade and then choose a new time or publish manually.

Limits

  • Article JSON body: up to 20 MB on staging.
  • Image file: up to 10 MB.
  • Image dimensions: up to 24 megapixels before resizing.
  • Uploaded images are converted to WebP and resized to 1600 px on the longest side.
  • Use explicit ISO 8601 time zones for scheduled_at, for example 2026-05-20T10:00:00+00:00.
  • API keys are shown only once when created. Store them securely.

Errors

401 Missing or invalid API key.
403 API publishing is not available on this account level yet, the key owner cannot access the channel, or the channel is read-only because it is over the current plan limit.
404 Channel or article not found.
413 Request body or uploaded file is too large.
422 Validation error. The response contains field-level details.

Minimal agent prompt

Use the Publicasta API docs at https://publicasta.com/api-docs. API key: YOUR_API_KEY. Channel: demo_project. Write an article about TOPIC, upload any generated images first, create translations in en/es/ru, then create the article as draft and report the resulting status and edit URL. Put the main article title only in translations[].title. Do not include the main title as a Markdown # heading or HTML h1 in content_markdown/content_html; use ## and ### for body sections.