API

API

One REST API for every channel eksis publishes to. Authenticate with a key, send JSON, and let eksis carry the platform differences.

Base URL

OpenAPI spec
https://api.eksis.io/v1

Schedule and publish social posts, read your connected channels, upload media, and answer comments — from your own code.

Authenticating

Every request carries an API key in the Authorization header:

Authorization: Bearer eksis_sk_...

Create a key in Settings → API inside the workspace it should reach. A key belongs to one workspace and cannot be pointed at another, so the workspace is never part of a request.

Keys are shown once, at creation. eksis stores only a hash, so a key that is lost is replaced, not recovered. Treat one like a password: server-side only, never in a browser, an app bundle, or a repository.

Roles

A key carries a role — viewer, contributor, editor, or admin — and can never be given more access than the person who created it has. Pick the smallest one that does the job: a key that only reads analytics has no business being able to publish.

Rate limits

Quotas are counted per workspace per day, shared by every key it has.

PlanKeysRequests / day
Freeno API access
Starter31,000
Premium1010,000
Agency3050,000

Every response carries x-ratelimit-limit and x-ratelimit-remaining. Once the quota is gone the API answers 429 with a retry-after header in seconds.

Errors

Failures are always JSON, always under an error key, and always carry a stable code. Branch on code, never on message — messages are written for people and get reworded.

Pagination

Collections return data and nextCursor. Pass nextCursor back as cursor to get the next page; null means you have reached the end. Cursors are timestamps of the last row, so a page never skips or repeats a row when new ones arrive mid-walk.

Versioning

The version is in the path. Breaking changes arrive as /v2; v1 keeps working. New optional fields can appear in a response at any time, so parse tolerantly.

Your first call

This proves the key works and shows which workspace it reaches.

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

Endpoints

Account

What this key can reach.

get /v1/me

Describe the key and its workspace

The cheapest call that proves a key is alive and shows what it points at.

Responses

200The workspace, the key, and its quota.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.

Channels

The social accounts connected to the workspace.

get /v1/channels

List connected channels

Every connected social account, with the health of its connection. A channel whose status is not active will hold anything scheduled to it until it is reconnected in the app.

Parameters

includeDisconnected query string true · false Include channels that were disconnected. Off by default.

Responses

200The channels of this workspace.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.

Posts

Draft, schedule, publish, and inspect posts.

get /v1/posts

List posts

Newest first, by creation time.

Parameters

status query string all · draft · pending_approval · scheduled · publishing · published · failed · partial Keep only posts in this state.
channels query string Comma-separated channel ids. Keeps posts aimed at any of them.
limit query integer Rows per page. Values above 100 are clamped to 100.
cursor query string The nextCursor from the previous page, unchanged.

Responses

200One page of posts.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
post /v1/posts

Create a post

One endpoint covers drafts, schedules, the queue, and publishing now — mode is what differs. Anything but draft is refused while a target still has a blocking validation error, and the offending checks come back in error.details.validations.

Request body

title string | null Internal label, never published.
baseCaption string Used by every target that has no caption of its own.
baseMediaIds string[] Media ids from POST /v1/media/uploads. Used by targets with an empty mediaIds.
targets requiredobject[] One entry per destination channel. A post always has at least one.
socialAccountId requiredstring Channel id from GET /v1/channels.
contentType requiredstring feed · photo · post · text · carousel · reels · video · short · story
caption string | null Overrides baseCaption for this channel only.
mediaIds string[]
firstComment string | null
settings object Platform-specific settings, e.g. YouTube privacy or TikTok disclosure.
scheduledAt string | null · date-time Required when mode is schedule. Interpreted as an absolute instant, so send an offset.
mode string draft · schedule · now · queue draft saves without publishing. schedule needs scheduledAt. queue takes the next free slot from the channel queue. now publishes immediately.

Responses

201The post was created.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
get /v1/posts/{postId}

Read one post

Includes every target with its own status, permalink, and failure — this is how you learn whether publishing worked.

Parameters

postId path requiredstring

Responses

200The post and its targets.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
patch /v1/posts/{postId}

Replace a post

The body is the whole post, not a partial patch: targets you leave out are removed.

Parameters

postId path requiredstring

Request body

title string | null Internal label, never published.
baseCaption string Used by every target that has no caption of its own.
baseMediaIds string[] Media ids from POST /v1/media/uploads. Used by targets with an empty mediaIds.
targets requiredobject[] One entry per destination channel. A post always has at least one.
socialAccountId requiredstring Channel id from GET /v1/channels.
contentType requiredstring feed · photo · post · text · carousel · reels · video · short · story
caption string | null Overrides baseCaption for this channel only.
mediaIds string[]
firstComment string | null
settings object Platform-specific settings, e.g. YouTube privacy or TikTok disclosure.
scheduledAt string | null · date-time Required when mode is schedule. Interpreted as an absolute instant, so send an offset.
mode string draft · schedule · now · queue draft saves without publishing. schedule needs scheduledAt. queue takes the next free slot from the channel queue. now publishes immediately.

Responses

200The post was replaced.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
delete /v1/posts/{postId}

Delete a post

Only before it goes out. A published post lives on the platform, and eksis will not pretend otherwise.

Parameters

postId path requiredstring

Responses

200The post was deleted.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
409The post is already published.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
post /v1/posts/{postId}/publish

Publish now

Queues every target that has not gone out yet and returns immediately — it does not wait for the platforms. Poll GET /v1/posts/{postId} to see how each target ended up.

Parameters

postId path requiredstring

Responses

200Publishing was queued.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
409The post is already published.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.

Media

Upload images and video for posts to use.

get /v1/media

List media

Parameters

type query string image · video
limit query integer Rows per page. Values above 100 are clamped to 100.
cursor query string The nextCursor from the previous page, unchanged.

Responses

200One page of media.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
post /v1/media/uploads

Start an upload

Uploading takes two steps. This one reserves the media id and hands back a pre-signed URL; you then PUT the bytes straight to storage and call complete. The file never passes through the API, so a large video does not sit in an API instance’s memory.

Accepted types: JPEG, PNG, WebP, HEIC, MP4, QuickTime, WebM.

Request body

filename requiredstring
mime requiredstring
size requiredinteger Bytes. Checked against the plan’s storage quota.
folderId string | null

Responses

201Upload where uploadUrl says, with the headers given, then call complete.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
post /v1/media/{mediaId}/complete

Finish an upload

Marks the media ready so a post may use it. Send the dimensions if you know them — several platforms reject media whose aspect ratio they cannot check ahead of time.

Parameters

mediaId path requiredstring

Request body

width integer
height integer
durationMs integer Video only.

Responses

200The media is ready.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.

Comments

Read and answer comments from the inbox.

get /v1/comments

List comments

Comments left by other people on your posts, newest first. Your own comments are not included.

Parameters

status query string all · open · assigned · done
channels query string Comma-separated channel ids.
q query string Case-insensitive substring of the comment text.
limit query integer Rows per page. Values above 100 are clamped to 100.
cursor query string The nextCursor from the previous page, unchanged.

Responses

200One page of comments.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
post /v1/comments/{commentId}/reply

Reply to a comment

Sends the reply to the platform right away and marks the comment done. Unlike publishing, this one does wait: a failure here comes back as a platform error rather than as a status to poll for.

Parameters

commentId path requiredstring

Request body

text requiredstring

Responses

200The reply was sent.
401The API key is missing, revoked, expired, or unknown.
402The workspace moved to a plan that does not include the API.
403The key’s role does not allow this.
404No such row in this workspace.
422The body did not validate.
429The workspace used up its daily quota. See retry-after.
502The platform rejected the reply.

Start on the free plan

Connect two accounts, schedule your first week, and see whether it fits. No card, no trial countdown.

Get started