Reelspan publishes blog posts to your self-hosted WordPress site (5.6 or later) through its REST API, signed in with an application password. Videos and photos go to the site's media library and are embedded in the post.
What you can post
| Post | How it appears |
|---|---|
| Text | A post with a title and a body |
| Photos | A post with every photo embedded as an image block above the body. The first photo becomes the featured image |
| Video | A post with the video embedded as a video block above the body. photos[] can mix photos and videos too |
The title is wordpress_title, else the first line of the caption, up to 200 characters. The body is wordpress_description, else description, else the whole caption. Blank lines start new paragraphs.
The body is plain text: HTML and Markdown in it show as typed, not as formatting. If you send
wordpress_title, the caption becomes that title too, so send the body inwordpress_descriptionordescription.
The result's url is the post's link and post_id its id.
Connect your site
You need the site's address, a username and an application password. Setup takes about two minutes.
- In your WordPress admin, open Users → Profile (
/wp-admin/profile.php) and scroll to Application Passwords. They need WordPress 5.6 or later, on https. - Name it Reelspan and click Add New Application Password. Copy the password it shows once.
- In the Reelspan dashboard, open Accounts → Connect account, choose the profile and WordPress, and enter your site, username and the application password.
Your own login password is never needed. Reelspan checks the three with your site, and that the user may publish posts, before saving them, encrypted.
With the API
curl -X POST https://api.reelspan.com/v1/accounts/wordpress \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "site": "example.com", "username": "editor", "app_password": "abcd efgh ijkl mnop qrst uvwx"}'import { Reelspan } from 'reelspan';
const reelspan = new Reelspan();
await reelspan.accounts.connect('my-brand', 'wordpress', {
site: 'example.com',
username: 'editor',
app_password: process.env.WP_APP_PASSWORD,
});import os
from reelspan import Reelspan
reelspan = Reelspan()
reelspan.accounts.connect("my-brand", "wordpress", site="example.com", username="editor", app_password=os.environ["WP_APP_PASSWORD"]){ "success": true, "platform": "wordpress", "account": "example.com", "reconnected": false }| Field | Required | Also accepted (Upload-Post) |
|---|---|---|
site |
Yes. Its address, with a path if WordPress lives in one (example.com/blog) |
site_url |
username |
Yes | |
app_password |
Yes. With or without its spaces | application_password |
Connecting again replaces the WordPress account on that profile. See Connect with credentials.
Example post
A video post, saved as a draft to review in WordPress:
curl -X POST https://api.reelspan.com/v1/posts/video \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=wordpress" \
-F "title=Launch day" \
-F "wordpress_title=Our launch, in 60 seconds" \
-F "wordpress_description=Today we opened the doors.
Watch the tour above, then read on for what comes next." \
-F "wordpress_status=draft" \
-F "[email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.video({
user: 'my-brand',
platforms: ['wordpress'],
title: 'Launch day',
video: { data: await readFile('launch.mp4'), name: 'launch.mp4', type: 'video/mp4' },
extra: {
wordpress_title: 'Our launch, in 60 seconds',
wordpress_description: 'Today we opened the doors.\n\nWatch the tour above, then read on for what comes next.',
wordpress_status: 'draft',
},
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.video(
"my-brand", ["wordpress"], "launch.mp4", "Launch day",
extra={
"wordpress_title": "Our launch, in 60 seconds",
"wordpress_description": "Today we opened the doors.\n\nWatch the tour above, then read on for what comes next.",
"wordpress_status": "draft",
},
)Fields
| Field | Meaning |
|---|---|
wordpress_title |
The post's title. Falls back to the caption's first line. |
wordpress_description |
The post's body. Falls back to description. |
description |
The body, when wordpress_description isn't sent. |
title |
The caption: its first line is the title and the whole of it the body, when the fields above aren't sent. |
wordpress_status |
draft saves the post as a draft. Anything else, or nothing, publishes it. |
wordpress_excerpt |
The post's excerpt, the short summary themes show in lists and feeds. |
wordpress_slug |
The post's slug, the last part of its address (example.com/my-post). WordPress makes it unique if it is taken. |
wordpress_alt_text |
Alt text for the photos: one text for all, or one per photo. Saved on each image in the media library. Falls back to alt_text. |
alt_text |
The alt text for every network that takes it. |
In the dashboard composer, the WordPress tab has Save as a draft. A first_comment isn't posted on WordPress; the result says "first_comment": "unsupported" with a warning.
Limits and behaviour
- Files: up to 512 MB each, sent to your media library; your site's own upload limit may be lower.
- Photos: every photo in the request is uploaded and embedded, in order.
- Drafts: a draft answers with a warning, "Saved as a draft on WordPress".
- https only: Reelspan always calls your site over https, even if you enter
http://. - No redirects: Reelspan doesn't follow redirects, so enter the address the site answers on (for example with
www.if it moves you there). - Your site only: calls go only to the site you named, and never to private network addresses.
After posting
- Delete a post with Unpublish. It goes to the site's trash, where it can be restored for 30 days.
- Edit it with Edit a post:
titlechanges the title,text(ordescription) replaces the body text while keeping the images and video in it, andfieldscan changewordpress_excerptandwordpress_status(publish,draft,privateorpending).
Common errors
| Code | When | Fix |
|---|---|---|
INVALID_SITE |
Connecting: the site isn't an address | Enter it like example.com. |
INVALID_CREDENTIALS |
Connecting: the site didn't accept the username and application password | Make a new application password under Users → Profile, and check the site uses https. |
INSUFFICIENT_ROLE |
Connecting: the user can't publish posts | Use an Author, Editor or Administrator account. |
reauth_required |
The site answered 401 or 403: the application password was revoked | Make a new one and connect again. |
file_too_large |
A file is over 512 MB | Send a smaller file. |
wordpress_error |
The site refused the post or an upload. Retried automatically on 429 and 5xx | Read error for the site's reason. |
MISSING_FIELD |
Connecting without one of the three fields | Send all three. |
Errors when connecting come back as a 400 with the code in error_code. Errors when posting are in that network's result. See Errors.