Zernio
Zernio
Overview

Social Posting

XInstagramFacebookLinkedInTikTokYouTubePinterestRedditBlueskyThreadsGoogle Business ProfileSnapchat

Messaging

WhatsAppRCSiMessageTelegramDiscordSlack

Telephony

Phone NumbersVoice & CallsSMS

Advertising

Meta AdsGoogle AdsLinkedIn AdsTikTok AdsPinterest AdsX AdsOpenAI Ads

Blogs & Commerce

ShopifyWordPress
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources

WordPress

Connect WordPress.com or a self-hosted WordPress site, then create, schedule, update and delete its articles through the Blogs API, manage a WooCommerce store through the Commerce API and install ad platform tracking tags.


Connect a WordPress.com or self-hosted WordPress site and manage its articles with the Blogs API. A connected account uses platform: "wordpress" and represents one site with one account-scoped blog. WordPress is a blog integration: the account never appears as a target in POST /v1/posts and has no Zernio analytics or inbox.

Quick reference

PropertyValue
Platform valuewordpress
What it managesOne site's standard posts through one account-scoped blog
WordPress.com authOAuth 2.0
Self-hosted authUsername and WordPress Application Password
Tracking tagsMeta, TikTok, Google, LinkedIn, Pinterest, X and OpenAI tags as theme widgets (Tracking tags)
Social postingNo
AnalyticsNo
SchedulingYes, native (publishDate; no Zernio queue)
DraftsYes (isPublished: false)
Article bodyHTML (bodyHtml)
TagsNames; missing tags are created on the site
AuthorNumeric WordPress user ID encoded as a string
Featured imagePublic JPEG, PNG, WebP or GIF URL; up to 10 MB
SEO plugin fieldsNot supported
PaginationCursor (limit 1 to 50, default 20, plus nextCursor)

Before you start

Choose one connection path for each site:

  • WordPress.com: the site owner approves OAuth and selects a site on WordPress.com.
  • Self-hosted WordPress: the site owner supplies an HTTPS site URL, their WordPress login username and an Application Password created in WordPress admin.

The authenticated WordPress user must be able to publish posts and upload files. Zernio verifies both capabilities before it saves the connection. A role that can only write drafts is insufficient.

The account represents the selected site, not the person who authorized it. Connect another site as another account. Site and article data stays on WordPress; Zernio maps it into the common Blogs API response shape.

Connect WordPress.com

Call GET /v1/connect/wordpress with profileId and redirect_url, then send the site owner's browser to the returned authUrl:

curl "https://zernio.com/api/v1/connect/wordpress?profileId=66a1f0c2a4b9d3e8f1a2b3c4&redirect_url=https%3A%2F%2Fmyapp.com%2Fconnected" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

{
  "authUrl": "https://public-api.wordpress.com/oauth2/authorize?...",
  "state": "..."
}

Redirect the browser to authUrl. WordPress.com handles consent and site selection. Its callback connects the selected site and sends the browser to your redirect_url. The returned WordPress.com numeric site ID becomes that account's blogId; read it through List blogs instead of constructing it.

redirect_url must be a safe absolute destination. Keep the returned state opaque; Zernio validates it at the callback. Connecting the same profile to the same site again refreshes the connection in place rather than creating another account slot.

WordPress.com OAuth scopes

Zernio uses WordPress.com's default single-site authorization by omitting the scope parameter. The consent grants access to the selected site; Zernio uses that connection for articles, featured images and tags. It does not request the explicit global scope that grants access across all your sites. Granular scopes such as posts and media do not support the /wp/v2 API used by this integration. See the official WordPress.com OAuth documentation for the upstream scope model.

Connect self-hosted WordPress

In WordPress admin, the site owner opens their user profile and creates an Application Password for Zernio. Send the generated password with the login username to POST /v1/connect/wordpress/token:

curl -X POST "https://zernio.com/api/v1/connect/wordpress/token" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "66a1f0c2a4b9d3e8f1a2b3c4",
    "siteUrl": "https://example.com",
    "username": "editor@example.com",
    "applicationPassword": "xxxx xxxx xxxx xxxx xxxx xxxx"
  }'

Response (200):

{
  "account": {
    "_id": "66b2e19d8c3f5a7e9d0b1c2d",
    "platform": "wordpress",
    "username": "example.com",
    "displayName": "Example Press",
    "profileId": "66a1f0c2a4b9d3e8f1a2b3c4"
  }
}

siteUrl must use HTTPS and identify the public site root. Do not include /wp-json, a REST endpoint, a username, a password or other credentials in the URL. Zernio safely discovers the site's REST API, rejects private or local network targets, verifies the credentials and checks publish/upload capabilities before persisting the account.

An Application Password is separate from the user's interactive WordPress password. Treat it as a secret and revoke it from WordPress admin when it is no longer needed. Revoking it immediately stops API access; reconnect the account with a new Application Password to restore it.

Publish articles

WordPress uses the same article endpoints as Shopify. The differences are the single-blog model, WordPress author IDs and tag/media handling described below.

List the site blog

Always start with List blogs:

curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

A self-hosted account returns exactly one blog with id: "1":

{
  "platform": "wordpress",
  "blogs": [
    {
      "id": "1",
      "platform": "wordpress",
      "title": "Example Press",
      "handle": "example.com"
    }
  ],
  "nextCursor": null
}

The value "1" is scoped to the connected account. It does not claim that the WordPress database's internal blog ID is 1. A WordPress.com account uses its numeric WordPress.com site ID instead. Code that supports both connection types should use blogs[0].id from this response.

Fetch the same site metadata with Get a blog:

curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Create a draft

Call Create a blog article with a title. New WordPress articles default to draft, so this minimal request does not publish:

curl -X POST "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1/articles" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Autumn collection preview",
    "bodyHtml": "<p>The first pieces land next month.</p>",
    "handle": "autumn-collection-preview",
    "excerpt": "An early look at what is arriving this September.",
    "tags": ["autumn", "new arrivals"],
    "author": "42",
    "image": {
      "url": "https://cdn.example.com/autumn.jpg",
      "altText": "Wool coats on a rail"
    },
    "isPublished": false
  }'

WordPress resolves existing tags by name case-insensitively and creates a missing tag on the site. You can send up to 100 non-empty tag names. Creating a missing term depends on the connected user's WordPress permissions. author is the numeric ID of a WordPress user who can author the post, encoded as a JSON string. It is not a login, email or display name; assigning another user as author can require a higher WordPress role.

For image.url, WordPress downloads the file into that site's media library and sets the resulting attachment as the featured image. The URL must be publicly reachable and return a JPEG, PNG, WebP or GIF no larger than 10 MB. altText becomes the attachment's alternative text. Omitting image during a later PATCH preserves the existing featured image; this API has no featured-image removal sentinel.

Response (201):

{
  "platform": "wordpress",
  "article": {
    "id": "1842",
    "blogId": "1",
    "platform": "wordpress",
    "title": "Autumn collection preview",
    "bodyHtml": "<p>The first pieces land next month.</p>",
    "handle": "autumn-collection-preview",
    "tags": ["autumn", "new arrivals"],
    "author": "42",
    "excerpt": "An early look at what is arriving this September.",
    "image": {
      "url": "https://example.com/wp-content/uploads/2026/09/autumn.jpg",
      "altText": "Wool coats on a rail"
    },
    "status": "draft",
    "isPublished": false,
    "publishDate": null,
    "publishedAt": null,
    "createdAt": null,
    "updatedAt": "2026-09-16T09:30:00Z"
  }
}

bodyHtml is raw article HTML. Zernio does not provide a visual editor or transform Markdown into HTML.

Publish now

Set isPublished: true without a future publishDate:

{
  "title": "Autumn collection preview",
  "bodyHtml": "<p>The first pieces are now available.</p>",
  "isPublished": true
}

The response reports status: "publish", isPublished: true and the WordPress publication time in publishedAt.

Schedule on WordPress

Send a future ISO 8601 publishDate to schedule publication natively:

{
  "title": "Autumn collection preview",
  "bodyHtml": "<p>The first pieces land next month.</p>",
  "publishDate": "2027-01-01T12:00:00+01:00"
}

The response reports status: "future", isPublished: false and the scheduled instant in publishDate. WordPress, not Zernio's queue, publishes the article. The site must run WordPress scheduled jobs correctly; Zernio does not add a second scheduler or force publication after the requested time.

isPublished: false explicitly requests a draft and wins when it is sent alongside a future publishDate. Omit isPublished when scheduling. You cannot write WordPress's raw status field through this API.

List and get articles

List blog articles includes every publish, future, draft, pending and private article visible to the connected user. It is cursor-paginated: pass limit from 1 to 50 and then reuse the opaque nextCursor exactly as returned.

curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1/articles?limit=20" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"
{
  "platform": "wordpress",
  "articles": [
    {
      "id": "1842",
      "blogId": "1",
      "platform": "wordpress",
      "title": "Autumn collection preview",
      "status": "draft",
      "isPublished": false,
      "publishDate": null
    }
  ],
  "nextCursor": "wp:2"
}

Get one article with Get a blog article:

curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1/articles/1842" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Article IDs are WordPress post IDs represented as strings. Read them from list/create responses rather than constructing them.

Update an article

Update a blog article is a partial update. Omitted fields keep their current value:

curl -X PATCH "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1/articles/1842" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Autumn collection is here",
    "tags": ["autumn", "available now"],
    "isPublished": true
  }'

tags replaces the full tag list; an empty array clears it. Empty bodyHtml and excerpt strings clear those fields. Sending isPublished: false moves a published or scheduled article back to draft. Omitting both isPublished and publishDate preserves its current WordPress status and publication date.

Delete an article

Delete a blog article permanently deletes the article on WordPress:

curl -X DELETE "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/blogs/1/articles/1842" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

A successful delete returns 204 with no response body. Zernio stores no copy to restore. WordPress retains the article's media attachments and tags so other content can keep using them.

Supported operations

OperationEndpoint
List blogsGET /v1/accounts/{accountId}/blogs
Get a blogGET /v1/accounts/{accountId}/blogs/{blogId}
List articlesGET /v1/accounts/{accountId}/blogs/{blogId}/articles
Create an articlePOST /v1/accounts/{accountId}/blogs/{blogId}/articles
Get an articleGET /v1/accounts/{accountId}/blogs/{blogId}/articles/{articleId}
Update an articlePATCH /v1/accounts/{accountId}/blogs/{blogId}/articles/{articleId}
Delete an articleDELETE /v1/accounts/{accountId}/blogs/{blogId}/articles/{articleId}

Commerce

A self-hosted site running WooCommerce is also a Commerce store: the Commerce API at /v1/commerce manages its products, variants, images, stock, categories (as collections), coupons (as discounts), product custom fields and pages, and can sync the store into a Meta catalog for catalog ads. Pass this account's id as accountId; objects report platform: "woocommerce".

The connected user must be allowed to manage WooCommerce. WordPress.com sites cannot serve WooCommerce through Zernio, though their pages remain available through the Commerce pages endpoints. GET /v1/commerce/store returns the capabilities the site serves. Sales channels, menus, redirects, metaobjects, markets and marketing activities are Shopify only; see WooCommerce differences.

curl "https://zernio.com/api/v1/commerce/products?accountId=66c0a1b2c3d4e5f6a7b8c9d0&status=active" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Tracking tags

Install an ad platform's pixel or site tag on the site with POST /v1/accounts/{accountId}/tracking-tags/{tagId}/install, where accountId is your connected ads account (Meta, TikTok, Google, LinkedIn, Pinterest, X or OpenAI), tagId the tracking tag and the body names this site's storeAccountId. Zernio adds a Custom HTML widget with the platform's base code to a widget area of the active theme (a footer area when there is one, else the first active area; pass sidebarId to choose), then reads the widget back to confirm WordPress kept the <script> tag.

const { data } = await zernio.trackingtags.installTrackingTagOnStore({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d', tagId: '18ce54d4x5t' },
  body: { storeAccountId: '66b2e19d8c3f5a7e9d0b1c4f', sidebarId: 'sidebar-1' }
});

Response (200), an X Pixel:

{
  "platform": "xads",
  "install": {
    "storeAccountId": "66b2e19d8c3f5a7e9d0b1c4f",
    "platform": "wordpress",
    "siteUrl": "https://example.com",
    "tagPlatform": "xads",
    "siteTagId": "o8z1q",
    "installed": true,
    "method": "wordpress_widget",
    "widgetId": "custom_html-3",
    "sidebarId": "sidebar-1",
    "sidebarName": "Footer",
    "created": true,
    "homepageCheck": "found"
  }
}
  • One widget per tag. Each widget carries a Zernio marker naming its platform and on-site id, so the install is idempotent per tag: calling it again updates (or moves) the same widget and returns created: false. Tags of several platforms, or several tags of one platform, run side by side, and tag code the site owner pasted by hand is never touched.
  • Homepage check. With verifyHomepage (default true) Zernio fetches the homepage afterwards: homepageCheck is found, not_found, unreachable or skipped. not_found can be a page cache that has not refreshed; the widget read-back is the authoritative check.
  • Status. GET with ?storeAccountId= returns whether this tag's widget is live (in an active widget area, script intact), a read-only preflight (ready, reason and the theme's widget areas in sidebars) to check a site before installing, and tags, every Zernio widget on the site with its platform, siteTagId, widgetId, sidebarId and whether it is active. The preflight reads capabilities only, so ready: true is not a guarantee: a stripped script is detected by the install itself.
  • Uninstall. DELETE with ?storeAccountId= removes every widget Zernio created for the tag and reports the count in removed (0 when nothing was installed).

What the widget contains

A widget holds the platform's base code, so on WordPress each tag records page views; storefront events such as add to cart or purchase are a Shopify feature.

PlatformWidget codeOfficial fallback
Metafbevents.js, fbq('init') with the pixel id, PageViewMeta's Meta pixel for WordPress plugin (official-facebook-pixel)
TikTokTikTok's base code, ttq.load with the pixel code, ttq.page()TikTok's TikTok plugin (tiktok-for-business, WooCommerce stores)
GoogleThe gtag.js Google tag (gtag('config', 'AW-...')), plus the PAGE_VIEW conversion snippet when the account has oneGoogle's Site Kit by Google plugin (google-site-kit)
LinkedInLinkedIn's Insight Tag base code (_linkedin_partner_id, insight.min.js)Paste the tag's code into the theme header
PinterestPinterest's base code, pintrk('load') with the tag id, pintrk('page') and a pagevisit eventThe Pinterest for WooCommerce plugin (WooCommerce stores only)
XX's uwt.js base code, whose twq('config') records the page viewPaste the tag's code into the theme header
OpenAIOpenAI's oaiq base code with a page_viewed eventPaste the tag's code into the theme header

When WordPress cannot run the tag

WordPress keeps a <script> tag only for users with the unfiltered_html capability. When the site cannot run the tag, Zernio removes anything it wrote and answers 422 tracking_tag_install_blocked with the cause in details.reason:

details.reasonCause
insufficient_permissionsThe connected user is not an Administrator (lacks edit_theme_options).
wordpress_com_planWordPress.com strips scripts on plans without plugin support.
scripts_strippedThe site removed the script: the user lacks unfiltered_html (a multisite admin who is not a Super Admin), or DISALLOW_UNFILTERED_HTML is set.
no_widget_areasThe theme has no widget areas (block themes such as Twenty Twenty-Five use the Site Editor).
widgets_api_unavailableThe site has no widgets REST API (WordPress older than 5.8, or disabled by a security plugin).
{
  "error": "The active theme has no widget areas (block themes use the Site Editor instead). Add the tag's code (the `code` field on GET .../tracking-tags/{tagId}) to the footer template part with a Custom HTML block, or paste the tag's code (the `code` field on GET .../tracking-tags/{tagId}) into the theme's header instead.",
  "type": "invalid_request_error",
  "code": "tracking_tag_install_blocked",
  "details": { "reason": "no_widget_areas" }
}

The message always names the manual alternative for the tag's platform: the official plugin in the table above where one exists, otherwise pasting the tag's code (from GET /v1/accounts/{accountId}/tracking-tags/{tagId}) into the theme.

Article fields

There is no platformSpecificData for WordPress because a WordPress site is not a POST /v1/posts target.

FieldTypeBehavior
titlestringRequired on create.
bodyHtmlstringRaw article HTML.
handlestringWordPress post slug. Generated from the title when omitted.
excerptstringShort summary stored in the WordPress excerpt field.
tagsstring[]Tag names. The complete list replaces existing tags; missing names are created.
authorstringNumeric WordPress user ID encoded as a string.
image{url, altText?}Public image downloaded into the site's media library and set as the featured image.
isPublishedbooleanfalse creates or restores a draft; true publishes now unless a future date schedules it.
publishDatedatetimeISO 8601 with offset or Z; a future value schedules publication on WordPress.

Responses also include WordPress's normalized status: publish, future, draft, pending or private. This field is read-only. isPublished is true only for publish; publishDate reports a scheduled future time when applicable.

The shared Blogs API also exposes seo for Shopify. WordPress rejects seo explicitly because core WordPress has no portable SEO-write contract and plugin fields differ. Zernio does not silently discard it. Use a plugin's own API outside Zernio if you need Yoast, Rank Math or another plugin's metadata.

What you cannot do

The WordPress connection does not expose:

  • Social posts through POST /v1/posts
  • Analytics, comments, DMs or the Inbox API
  • Ads or social account insights (ad platform tracking tags can be installed on the site)
  • Creating a site or another blog
  • Renaming or deleting the connected site/blog through the Blogs API
  • SEO plugin fields
  • Custom post types, pages, categories or taxonomies other than article tags through the Blogs API (pages, and WooCommerce product categories, are served by the Commerce API)
  • A visual editor or Markdown conversion
  • Removing an existing featured image through a PATCH sentinel

POST /v1/accounts/{accountId}/blogs, PATCH /v1/accounts/{accountId}/blogs/{blogId} and DELETE /v1/accounts/{accountId}/blogs/{blogId} return 405 for WordPress. Those operations remain available to platforms that support blog management.

Common errors

ErrorCauseFix
400 on self-hosted connectsiteUrl is not HTTPS, includes credentials, resolves to a private/local address or does not expose a usable WordPress REST APIPass the public HTTPS site root without credentials or /wp-json.
400 on an article requestA field is invalid, author is not a numeric user ID, or seo was sentCorrect the named field. Remove seo; SEO plugin writes are unsupported.
401 or 403 on self-hosted connectThe username/Application Password is invalid, revoked or lacks publish/upload capabilitiesCreate a new Application Password for a user that can publish posts and upload files.
403 on an article requestThe connected WordPress user cannot perform that action, such as assigning another author or creating a tagRestore the user's WordPress role/capabilities or reconnect with another user.
404 blog_not_foundblogId does not identify this account's single site blogCall List blogs and use its only returned ID. Self-hosted sites use 1.
404 blog_article_not_foundThe post was deleted or belongs to another connected siteList articles on this account and blog to find a current ID.
405 on a blog mutationWordPress site/blog creation, rename and deletion are unsupportedManage the site itself in WordPress; use article CRUD through Zernio.
422 tracking_tag_install_blockedA tracking tag install cannot run on this site; details.reason says whySee the reasons and the platform's official fallback.
429Zernio or WordPress rate limited the requestRetry later. See rate limits.
502 or 503WordPress failed or was unavailableCheck the site and retry only after the earlier request's result is known; a timed-out mutation may have reached WordPress.

When a WordPress.com grant or self-hosted Application Password stops working, reconnect the same site on the same profile. The existing account is refreshed in place when the site identity matches.

Related

  • Connecting accounts: both authentication paths.
  • Blogs API: the generated reference for every blog and article endpoint.
  • Get WordPress.com authorization URL: OAuth query and response fields.
  • Connect self-hosted WordPress: Application Password request and response fields.
  • Error handling: canonical error envelopes and retry guidance.
  • Commerce API: WooCommerce products, stock, coupons, pages and Meta catalog sync.
  • Pixels and tracking tags: the tags you can install, per ad platform.
  • Platforms overview: social-posting platforms and connect-only integrations.
  • WordPress REST API authentication: upstream authentication and Application Password behavior.
  • WordPress posts, media and tags: upstream resources behind the article mapping.
Was this page helpful?

Shopify

Connect a Shopify store to manage its blog articles through the Blogs API, manage its catalog, stock and discounts through the Commerce API and install ad platform pixels; a store publishes no social posts.

On this page

Quick referenceBefore you startConnect WordPress.comWordPress.com OAuth scopesConnect self-hosted WordPressPublish articlesList the site blogCreate a draftPublish nowSchedule on WordPressList and get articlesUpdate an articleDelete an articleSupported operationsCommerceTracking tagsWhat the widget containsWhen WordPress cannot run the tagArticle fieldsWhat you cannot doCommon errorsRelated