Publishing.
One call pushes a finished article — content, slug, meta tags, featured image — into your CMS. Connect WordPress, Sanity, or Contentful once in the dashboard; publish forever via the API.
Integrations#
CMS credentials are configured at Dashboard → Integrations, where they are verified against the live CMS and stored encrypted (AES-256-GCM). There is deliberately no public API for creating integrations — credentials never need to transit your application code. Each integration gets an ID you reference when publishing.
Publish an article#
/v1/articles/{id}/publish| Field | Type | Description | |
|---|---|---|---|
| integration_id | string | required | The connected CMS to publish to. Must belong to your org, else 404. |
| as_draft | boolean | default: false | true creates the post in the CMS unpublished (WordPress draft status, Sanity without publishedAt, Contentful entry left unpublished). |
curl -X POST https://scribe.whizztech.ai/v1/articles/9e72c4b0-51af-4c3d-8e6a-2d94b7f01c55/publish \
-H "Authorization: Bearer $SCRIBE_KEY" \
-H "Content-Type: application/json" \
-d '{
"integration_id": "e8d3b6a1-42f7-49c0-95ab-7c614f20d9e8",
"as_draft": false
}'{
"object": "publish",
"status": "published",
"external_id": "1284",
"external_url": "https://www.acme-analytics.com/blog/saas-churn-product-analytics"
}| Field | Type | Description |
|---|---|---|
| object | "publish" | Resource type. |
| status | "published" | The publish attempt succeeded. |
| external_id | string | Post/document/entry ID inside the CMS. |
| external_url | string | undefined | Public URL when the CMS returns one (WordPress does; Sanity and Contentful IDs resolve inside your own frontend). |
A CMS-side failure returns 502 with code publish_failed and the upstream reason:
{
"error": {
"code": "publish_failed",
"message": "WordPress publish failed (401): rest_cannot_create"
}
}Publishing marks the article published and records the attempt. Publishing the same article again creates a new post in the CMS — deduplicate on your side if you retry.
WordPress setup#
Uses the core REST API with Application Passwords — no plugin required. Requirements: WordPress ≥ 5.6, HTTPS, and a user with the Author role or higher (the connector verifies publish_posts capability at connect time).
- Log in to wp-admin as the publishing user and open Users → Profile → Application Passwords.
- Name it
whizz-scribeand click Add New Application Password. Copy the generated password (spaces are fine — they're part of it). - In Dashboard → Integrations, choose WordPress and enter the site URL (e.g.
https://www.example.com), the username, and the application password. Verification calls/wp-json/wp/v2/users/me.
What a publish sends:
- Title, slug, and the article HTML with the H1 stripped (WordPress renders the title).
meta_descriptionas the excerpt.- The hero image (when present) uploaded to the media library, alt-texted, and set as the featured image.
- Yoast and RankMath meta fields for SEO title/description — harmless when neither plugin is installed; if the meta write is rejected the connector automatically retries the post without it.
Sanity setup#
Writes documents through the Content Lake mutations API with a robot token. Body markdown is converted to Portable Text blocks: H2–H4 headings, bullet lists, and paragraphs (the H1 is dropped — the title lives on the document; links are flattened to plain text).
- In sanity.io/manage, open your project → API → Tokens and add a token with Editor permissions.
- In Dashboard → Integrations, enter the project ID, dataset (e.g.
production), and the token. Optional: a document type — defaults topost.
Field mapping on the created document:
| Field | Type | Description |
|---|---|---|
| title | string | Article title. |
| slug | slug | { _type: "slug", current: … }. |
| excerpt | string | The meta description. |
| body | block[] | Portable Text content. |
| publishedAt | datetime | Set to now on publish; omitted when as_draft is true. |
Contentful setup#
Uses the Content Management API: the entry is created, then published in a second version-locked call. With as_draft: true the entry stays in draft.
- In Contentful, open Settings → API keys → Content management tokens and generate a personal access token (CMA token).
- In Dashboard → Integrations, enter the space ID, environment (defaults to
master), and the token. Optional: a content type ID — defaults toblogPost. - Make sure the target content model has fields for title, slug, body, and description. The defaults map to field IDs
title,slug,body,description; a customfield_mapon the integration overrides any of them.
The body is written as Markdown into a Long Text field (Contentful renders markdown natively for long text), with the H1 stripped. Locale is en-US for English articles, the raw language code otherwise — make sure that locale exists in your space.
A/B titles#
Every article ships with title_variants — three alternates with different psychological hooks (data-led, how-to, contrarian). The publish call always uses the primary title; the variants are there for your own experimentation layer, ad headlines, or social captions. Rotate them client-side and keep the slug stable.