The API reference moved here from eksis.io/developers.

Quick start

From a new key to a scheduled post in five requests.

Each step shows the request in curl and in JavaScript (fetch, Node 18 or newer). Every endpoint page has more languages. Keep the key in an environment variable instead of pasting it into commands:

export EKSIS_API_KEY="eksis_sk_..."

Check the key

Ask the API which workspace the key reaches.

curl https://api.eksis.io/v1/me \
  -H "Authorization: Bearer $EKSIS_API_KEY"

The answer names the workspace, its time zone, its plan, and the role of the key. A 402 means the workspace is on Free, where the key only works with the MCP server. Details: Describe the key and its workspace.

Pick a channel

List the channels connected to the workspace.

curl https://api.eksis.io/v1/channels \
  -H "Authorization: Bearer $EKSIS_API_KEY"

Each channel has an id, a platform, and a status. Pick one whose status is active: a post scheduled to any other status waits until the channel is reconnected in the app. This guide calls its id CHANNEL_ID.

What a platform accepts (content types, caption length, media rules) is listed by Platform capabilities. Read it before composing for a platform you have not used yet.

Bring in an image

When the file already has a public address, import it:

curl -X POST https://api.eksis.io/v1/media/imports \
  -H "Authorization: Bearer $EKSIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/photo.jpg"}'

eksis downloads the file into the media library and answers 201 with the finished media. Its data.id is MEDIA_ID below. A file on your own disk goes through Start an upload and Finish an upload instead.

Schedule the post

Create the post with mode set to schedule.

curl -X POST https://api.eksis.io/v1/posts \
  -H "Authorization: Bearer $EKSIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "caption": "Your caption",
    "mediaIds": ["MEDIA_ID"],
    "targets": [{ "channelId": "CHANNEL_ID" }],
    "mode": "schedule",
    "scheduledAt": "2026-11-02T09:00:00Z"
  }'
  • targets holds one entry per channel. Each entry can override caption and mediaIds for that channel alone.
  • contentType is optional. Without it, eksis picks the type that fits the media, such as a feed post for one image on Instagram. Set it to choose another type the platform publishes, such as reels or story.
  • Platform options (a YouTube title, a TikTok audience, a Pinterest board) go in targets[].settings. Each platform specification lists the fields its network accepts.
  • scheduledAt is an absolute instant, so always send an offset or Z. To schedule in the workspace's local time, convert with the time zone from step 1.
  • mode also takes draft, queue (the next free slot in the channel queue), and now.

A 201 answers with the post id (POST_ID), its status, and warnings: things eksis accepted but you may want to change, such as a caption that will be cut short. A post that breaks a platform rule is refused with 422, and the failing checks are listed in error.details.validations. To run the same checks without saving anything, send the body to Validate a post first. Every field is described in Create a post.

Older field names

Requests written before October 2026 used baseCaption, baseMediaIds, and targets[].socialAccountId. They still work, but they are deprecated: use caption, mediaIds, and targets[].channelId in new code.

Check how it went

Read the post back to see how each target went.

curl https://api.eksis.io/v1/posts/POST_ID \
  -H "Authorization: Bearer $EKSIS_API_KEY"

Every target carries its own status, a permalink once it is published, and an error with code and message when publishing failed. Publishing happens in the background, so read the post again after the scheduled time instead of assuming it went out.

To hear about it without polling, add a webhook endpoint for post.target.published and post.target.failed.

Next

On this page