SimploAPI
Generate posts in your brand's voice and schedule them from your own tools.
A REST API over HTTPS with JSON bodies. Write captions and pictures that follow your brand profile, save them as posts, and schedule them to Instagram, Facebook and TikTok, from curl, a script, CI or any tool that can send an HTTP request. The base URL is https://api.getsimplo.ai/v1.
Working inside an AI assistant instead? The Simplo MCP server does the same through a chat.
Authentication
In the Simplo app, open Settings → API keys and create a key. It is shown once, so copy it then. Send it on every request:
Authorization: Bearer smp_live_…A key acts for your whole account: every project (brand) you own, and your credits. Keep it on a server or in a CI secret, never in a web page or an app. You can have up to 10 keys and revoke any of them at any time in Settings; a revoked key stops working at once. A request without a valid key answers 401 invalid_api_key.
Quickstart
From nothing to a scheduled Instagram post in five steps. The examples use jq to build JSON safely and to read the answers. Before you start, set up the brand profile in the app (Brand): generating captions or pictures for a project without one answers 400 validation_error ("Brand profile not set up"). Connect the platform you post to there too (Brand → Channels).
# Paste your key from Settings → API keys. jq is used below to build and read JSON.
export SIMPLO_API_KEY="smp_live_…"
BASE="https://api.getsimplo.ai/v1"1Find your project
Most calls name a project, one per brand. This keeps the first one; if you have several brands, look at the list and set PROJECT_ID to the one whose brand profile is set up. The accounts call tells you which platforms can receive posts.
# One project per brand. This keeps the first one's id; with several brands,
# pick the one whose brand profile is set up in the app.
PROJECT_ID=$(curl -sS "$BASE/projects" \
-H "Authorization: Bearer $SIMPLO_API_KEY" | jq -r '.[0].id')
echo "$PROJECT_ID"
# Which platforms can receive posts (connected in the Simplo app).
curl -sS "$BASE/projects/$PROJECT_ID/accounts" \
-H "Authorization: Bearer $SIMPLO_API_KEY"2Write caption ideas (costs credits)
Ideas in your brand's voice about a topic. The answer is { reply, ideas }; each idea has a hook, caption, hashtags and an imagePrompt.
jq -n --arg projectId "$PROJECT_ID" \
'{projectId: $projectId, topic: "Our new autumn menu", platforms: ["instagram"], limit: 3}' \
| curl -sS "$BASE/generate/captions" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- | tee ideas.json3Make the picture (costs credits)
The answer is { generationId, style, format, imageUrls }. The picture is also saved to the project's image history in the app.
# The first idea's imagePrompt describes its picture.
jq --arg projectId "$PROJECT_ID" \
'{projectId: $projectId, prompt: .ideas[0].imagePrompt, format: "instagram-post"}' ideas.json \
| curl -sS "$BASE/generate/image" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- | tee image.json4Save it as a dated draft
A draft with a scheduledAt is placed on that day in the app's Plan with status draft_scheduled, and never goes out by itself. The answer is the post, with its id.
# The next whole hour, in UTC, e.g. 2026-11-03T13:00:00Z.
AT=$(jq -nr 'now | floor | . - (. % 3600) + 3600 | todate')
jq -n --arg projectId "$PROJECT_ID" --arg at "$AT" \
--slurpfile ideas ideas.json --slurpfile image image.json \
'{projectId: $projectId,
caption: ($ideas[0].ideas[0] | .caption + "\n\n" + (.hashtags // [] | join(" "))),
imageUrl: $image[0].imageUrls[0],
platforms: ["instagram"],
scheduledAt: $at}' \
| curl -sS "$BASE/posts" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- | tee post.json5Schedule it
This is the call that puts it on your real account: the post's status becomes scheduled and Simplo publishes it at that hour. Run it soon after step 4: if that hour has passed by then, the answer is 400 invalid_schedule_time; pass a later scheduledAt instead. Until it goes out you can delete it (DELETE /posts/{id}) or unschedule it in the app.
# An empty body keeps the draft's time; send {"scheduledAt": "…"} to change it.
curl -sS "$BASE/posts/$(jq -r .id post.json)/schedule" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'The same in Node
Node 18 or later has fetch built in, so this needs no packages.
// quickstart.mjs — Node 18 or later, no packages.
// Run with: SIMPLO_API_KEY=smp_live_… node quickstart.mjs
const BASE = "https://api.getsimplo.ai/v1";
async function simplo(method, path, body) {
const res = await fetch(BASE + path, {
method,
headers: {
Authorization: `Bearer ${process.env.SIMPLO_API_KEY}`,
...(body !== undefined && { "Content-Type": "application/json" }),
},
body: body === undefined ? undefined : JSON.stringify(body),
});
const data = res.status === 204 ? null : await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
return data;
}
const [project] = await simplo("GET", "/projects");
const { ideas } = await simplo("POST", "/generate/captions", {
projectId: project.id,
topic: "Our new autumn menu",
platforms: ["instagram"],
limit: 3,
});
const idea = ideas[0];
const { imageUrls } = await simplo("POST", "/generate/image", {
projectId: project.id,
prompt: idea.imagePrompt,
format: "instagram-post",
});
// The next whole hour, in UTC.
const HOUR = 60 * 60 * 1000;
const scheduledAt = new Date((Math.floor(Date.now() / HOUR) + 1) * HOUR).toISOString();
const draft = await simplo("POST", "/posts", {
projectId: project.id,
caption: `${idea.caption}\n\n${(idea.hashtags ?? []).join(" ")}`,
imageUrl: imageUrls[0],
platforms: ["instagram"],
scheduledAt,
});
console.log(draft.id, draft.status); // draft_scheduled: on the calendar, not sent
const scheduled = await simplo("POST", `/posts/${draft.id}/schedule`, {});
console.log(scheduled.status, scheduled.scheduledAt); // scheduled: goes out at that hourRecipes
GitHub release → post
Every published release becomes a draft post about its notes, on the calendar at a whole hour at least an hour away (generating takes a minute, and the time must still be in the future if you schedule it). Add the key as a repository secret named SIMPLO_API_KEY and your project id as a repository variable named SIMPLO_PROJECT_ID (Settings → Secrets and variables → Actions), and change instagram to the platforms you have connected. To have the post go out on its own, uncomment the last line.
# .github/workflows/simplo.yml
# Needs a repository secret SIMPLO_API_KEY and a repository variable SIMPLO_PROJECT_ID.
name: Post releases to Simplo
on:
release:
types: [published]
jobs:
post:
runs-on: ubuntu-latest
steps:
- name: Draft a post about the release
env:
SIMPLO_API_KEY: ${{ secrets.SIMPLO_API_KEY }}
PROJECT_ID: ${{ vars.SIMPLO_PROJECT_ID }}
# Through the environment, never pasted into the script, so quotes
# and backticks in the release notes can't break it.
TOPIC: ${{ github.event.release.body || github.event.release.name || github.event.release.tag_name }}
IDEMPOTENCY_KEY: release-${{ github.event.release.id }}
run: |
set -euo pipefail
BASE=https://api.getsimplo.ai/v1
api() {
curl -sS --fail-with-body "$@" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json"
}
# 1. A caption about the release notes.
jq -n --arg projectId "$PROJECT_ID" --arg topic "$TOPIC" \
'{projectId: $projectId, topic: $topic, platforms: ["instagram"], limit: 1}' \
| api "$BASE/generate/captions" --data-binary @- > ideas.json \
|| { cat ideas.json >&2; exit 1; }
# 2. A picture for it.
jq --arg projectId "$PROJECT_ID" '{projectId: $projectId, prompt: .ideas[0].imagePrompt}' ideas.json \
| api "$BASE/generate/image" --data-binary @- > image.json \
|| { cat image.json >&2; exit 1; }
# 3. A draft on the calendar, never sent by itself. Its time is a whole hour (UTC) at
# least an hour away, so it is still in the future if you schedule it below.
AT=$(date -u -d "@$(( ($(date -u +%s) / 3600 + 2) * 3600 ))" +%Y-%m-%dT%H:%M:%SZ)
jq -n --arg projectId "$PROJECT_ID" --arg at "$AT" \
--slurpfile ideas ideas.json --slurpfile image image.json \
'{projectId: $projectId,
caption: ($ideas[0].ideas[0] | .caption + "\n\n" + (.hashtags // [] | join(" "))),
imageUrl: $image[0].imageUrls[0],
platforms: ["instagram"],
scheduledAt: $at}' \
| api "$BASE/posts" -H "Idempotency-Key: $IDEMPOTENCY_KEY" --data-binary @- > post.json \
|| { cat post.json >&2; exit 1; }
jq '{id, status, scheduledAt}' post.json
# 4. To publish it at that hour instead of leaving a draft, uncomment:
# api "$BASE/posts/$(jq -r .id post.json)/schedule" -d '{}'Idempotency-Key: release-<id> means one release makes one post. Re-running the job writes new captions and a new picture (and spends credits on them), but the post request then differs from the first one, so it is refused with 422 idempotency_key_reused instead of making a second post.
GitHub release → carousel
A carousel is written and drawn in one call and saved as a draft; it posts to Instagram only. Re-running this job in the same hour sends the same request, so the key replays the first carousel instead of paying for another. Re-running it in a later hour changes scheduledAt, so the request differs and is refused with 422 idempotency_key_reused rather than making a second carousel.
If the slides were drawn but saving the draft failed, the answer is 502 upstream_error with the slide URLs in details.slides. Those slides are paid for, so don't retry: use the URLs. A retry with the same key gets the same 502 back and is not charged again.
# .github/workflows/simplo-carousel.yml
# Needs a repository secret SIMPLO_API_KEY and a repository variable SIMPLO_PROJECT_ID.
name: Release carousel on Simplo
on:
release:
types: [published]
jobs:
carousel:
runs-on: ubuntu-latest
steps:
- name: Draft a carousel about the release
env:
SIMPLO_API_KEY: ${{ secrets.SIMPLO_API_KEY }}
PROJECT_ID: ${{ vars.SIMPLO_PROJECT_ID }}
TOPIC: ${{ github.event.release.body || github.event.release.name || github.event.release.tag_name }}
IDEMPOTENCY_KEY: release-carousel-${{ github.event.release.id }}
run: |
set -euo pipefail
BASE=https://api.getsimplo.ai/v1
api() {
curl -sS --fail-with-body "$@" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json"
}
# Writes and draws the slides and saves them as a draft. Its time is a whole hour (UTC)
# at least an hour away, so it is still in the future if you schedule it below.
AT=$(date -u -d "@$(( ($(date -u +%s) / 3600 + 2) * 3600 ))" +%Y-%m-%dT%H:%M:%SZ)
jq -n --arg projectId "$PROJECT_ID" --arg topic "$TOPIC" --arg at "$AT" \
'{projectId: $projectId, topic: $topic, slideCount: 5, scheduledAt: $at}' \
| api "$BASE/generate/carousel" -H "Idempotency-Key: $IDEMPOTENCY_KEY" --data-binary @- > carousel.json \
|| { cat carousel.json >&2; exit 1; }
jq '{postId, status, slides: [.slides[].imageUrl]}' carousel.json
# To publish it at that hour instead of leaving a draft, uncomment:
# api "$BASE/posts/$(jq -r .postId carousel.json)/schedule" -d '{}'Upload a video
Upload an MP4 or MOV (up to 100 MB) as multipart/form-data with the project in the query string, then create the post with the video the upload returned. This continues the quickstart, using its $BASE, $PROJECT_ID and $AT. A video that is already online can skip the upload: pass its link as videoUrl when you create the post.
# 1. Upload the file (MP4 or MOV, up to 100 MB). The type after ; is needed:
# curl sends an .mp4 as application/octet-stream otherwise. Use video/quicktime for a .mov.
curl -sS "$BASE/videos?projectId=$PROJECT_ID" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-F "[email protected];type=video/mp4" | tee video.json
# 2. A dated draft with the returned video. Its first frame is the cover.
jq --arg projectId "$PROJECT_ID" --arg at "$AT" \
'{projectId: $projectId, caption: "A minute with our new feature.",
video: .video, platforms: ["instagram", "facebook"], scheduledAt: $at}' video.json \
| curl -sS "$BASE/posts" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @-Times
Every scheduledAt is ISO 8601 with a UTC offset (Z or ±hh:mm); a time without one is refused. Simplo publishes once an hour, on the hour, so scheduling needs a whole hour in the future. A half-hour time zone's whole hours (India, +05:30) are fine.
A draft's date isn't checked until it is scheduled: you can place a draft on any day, and the rules apply when you call schedule.
2026-11-03T09:00:00-03:00 9 am in São Paulo (12:00 UTC): accepted
2026-11-03T12:00:00Z the same moment, written in UTC: accepted
2026-11-03T09:00:00 no offset: always 400 validation_error
2026-11-03T09:20:00-03:00 not on the hour: 400 invalid_schedule_time when scheduling (a draft accepts it)
2026-10-01T09:00:00-03:00 in the past: 400 invalid_schedule_time when scheduling (a draft accepts it)Credits
Three endpoints cost credits, and the reference marks them (the spec's x-costs-credits): POST /generate/captions (1 credit per call), POST /generate/image (per image) and POST /generate/carousel (the slide copy, plus each picture when pictures is on). Reading, creating posts, scheduling and publishing are free. The prices are in the app under Settings → Credit costs, and GET /credits returns your balance. Credits are taken before the work starts; without enough, the call is refused and nothing is charged:
HTTP/1.1 402 Payment Required
{
"error": {
"code": "insufficient_credits",
"message": "Not enough credits for this action.",
"details": { "allowed": false, "reason": "insufficient_credits", "creditsRemaining": 3, "creditsRequired": 5 }
}
}Rate limits
- 60 requests a minute per key, across all endpoints.
- 10 requests a minute per key on
/generate/*, which each run for tens of seconds. - 30 requests a minute per IP address for requests without a valid key, so guessing keys goes nowhere.
Over a limit, the answer is 429 rate_limited with a Retry-After header in seconds. Requests with a key also carry RateLimit and RateLimit-Policy headers. JSON bodies are capped at 1 MB.
Idempotency
A network error after a write leaves you not knowing whether it happened. Send an Idempotency-Key header (any string up to 255 characters) on POST /posts, POST /generate/carousel and POST /posts/{id}/publish, and retry with the same key: within 24 hours, the same key and the same request get the first answer back instead of a second post, with the header Idempotent-Replayed: true.
jq -n --arg projectId "$PROJECT_ID" --slurpfile image image.json \
'{projectId: $projectId, caption: "Fresh bread every morning.",
imageUrl: $image[0].imageUrls[0], platforms: ["instagram"]}' \
| curl -sS -i "$BASE/posts" \
-H "Authorization: Bearer $SIMPLO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: bread-2026-11-03" \
--data-binary @-
# Run it again within 24 hours: the same post comes back, not a second one,
# with this header in the answer:
# Idempotent-Replayed: true- The same key with a different body, or for a different post, answers 422
idempotency_key_reused. - While the first request is still running, a repeat answers 409
idempotency_in_progress; retry shortly. - Kept for replay: successes, and the 404, 413 and 422 answers and 400s from the request handler (such as
invalid_schedule_time), which a retry can't change. A body that fails validation is refused before the key is looked at, so it isn't kept. - Not kept, so a retry with the same key really runs again: 401, 402, 403, 409, 429 and 5xx answers,
platform_not_available(remove X in the app and retry), a publish where a platform failed (allSuccess: false), and a publish still in progress. The one 5xx that is kept is a carousel's 502 withdetails.slides, whose slides are already paid for. - Keys belong to the API key that sent them.
Publishing is safe to retry even without a key: a platform the post already reached is skipped. A post that is already live answers 200 with alreadyPublished: true; a send that is still going (a video, for instance) answers 202 with pending: true, and GET /posts/{id} shows how it ended.
Errors
Every error has the same shape, with a stable code to branch on and a message for people:
{
"error": {
"code": "validation_error",
"message": "The body is not valid.",
"details": [
{
"code": "invalid_value",
"values": ["instagram", "tiktok", "facebook"],
"path": ["platforms", 0],
"message": "Invalid option: expected one of \"instagram\"|\"tiktok\"|\"facebook\""
}
]
}
}invalid_api_key401The key is missing, mistyped or revoked. Only API keys work here, never an app sign-in token.
forbidden403The key can't do this.
not_found404No such project, post or endpoint on this account. Another account's ids answer the same way.
validation_error400The path, query or body is wrong; details lists the failing fields. Also a body that isn't JSON or is over 1 MB, and a platform that is switched off right now.
invalid_schedule_time400scheduledAt is missing, in the past, or not on a whole hour. See Times.
platform_not_available400The post includes X (added in the app), which the API doesn't publish to. Remove X in the app.
already_published409The post has gone out, so it can't be edited or rescheduled.
publishing_in_progress409The post is being sent right now. Read it again in a moment.
conflict409The request clashes with the post's current state.
idempotency_key_reused422This Idempotency-Key was already used with a different request.
idempotency_in_progress409The first request with this Idempotency-Key is still running. Retry shortly.
insufficient_credits402Not enough credits. details has creditsRemaining and creditsRequired.
subscription_inactive403The account has no active plan or trial; details.reason says why.
video_too_large413The video is over 100 MB.
rate_limited429Too many requests. Wait the number of seconds in Retry-After.
upstream_error502A social platform or an AI provider failed. Retry after a short wait, except for a carousel whose answer has details.slides: those slides were drawn and paid for, and only saving the draft failed. Don't retry it; use the slide URLs.
internal_error500Something went wrong on Simplo's side.
Platforms
The API posts to Instagram, Facebook and TikTok: instagram, facebook and tiktok in platforms. Accounts are connected in the app, and GET /projects/{projectId}/accounts shows which are ready. A platform switched off on Simplo's side for a while is refused with validation_error.
X isn't available through the API yet. A post made in the app that includes X can't be scheduled or published from here (platform_not_available). Carousels go to Instagram only; a video goes to Instagram as a Reel, to Facebook and to TikTok.
Reference
Generated from the OpenAPI 3.1 document, which you can download as openapi.json to generate a client or import into Postman. The API serves the same document at GET /v1/openapi.json.
/projectsList projects listProjects
The projects (one per brand) the key owner has. Most other endpoints need a project id from here.
200Success401invalid_api_key429rate_limited500internal_error
/projects/{projectId}/brandGet the brand profile getBrand
The project's brand profile: voice, audience, products, colors, typography.
projectId (path)requiredstringA project id from List projects.
200Success401invalid_api_key404not_found429rate_limited500internal_error
/projects/{projectId}/accountsList connected accounts listAccounts
The social accounts connected to the project and the platforms that are not. A post only goes out to a connected platform that does not need a reconnect. Accounts are connected in the Simplo app.
projectId (path)requiredstringA project id from List projects.
200Success401invalid_api_key404not_found429rate_limited500internal_error
/creditsGet the credit balance getCredits
The plan and credits. creditsRemaining is everything that can be spent: the plan's credits, used first, plus bonus credits. planCredits describes the plan's monthly allowance only.
200Success401invalid_api_key429rate_limited500internal_error
/postsList posts listPosts
The project's posts (drafts, scheduled, published, failed, missed), newest first. A draft_scheduled post is a draft placed on its day: it never sends by itself.
projectId (query)requiredstringThe project whose posts to list.
month (query)stringOnly posts of this month, as YYYY-MM.
200Success400validation_error401invalid_api_key404not_found429rate_limited500internal_error
/postsCreate a post createPost
Saves a single-image or video post as a draft (the default) or scheduled. A draft with scheduledAt is placed on that day in the plan (draft_scheduled) and never sends by itself. A scheduled post is published automatically at scheduledAt, which must be in the future and on the hour. A video post takes videoUrl (a public MP4 or MOV link, up to 100 MB) or an already uploaded video; its first frame is the cover. Not for X. Pass at most one of imageUrl, video and videoUrl.
Idempotency-Key (header)string· up to 255 charactersUp to 255 characters. Repeating a request with the same key within 24 hours returns the first answer instead of doing the work again.
projectIdrequiredstringThe project that owns the post.
captionrequiredstringThe post text.
imageUrlstring (uri)A public picture URL. Mutually exclusive with video and videoUrl.
videoobjectA video already uploaded with Upload a video. Mutually exclusive with imageUrl and videoUrl.
videoUrlstring (uri)A public MP4 or MOV link for Simplo to fetch. Mutually exclusive with imageUrl and video.
platformsrequiredarray of instagram | tiktok | facebook· at least 1Where the post goes. X is not supported.
statusdraft | scheduled· default "draft"draft saves it; scheduled publishes it at scheduledAt.
scheduledAtstring (date-time)ISO 8601 with UTC offset. Scheduling needs a future whole hour; a draft's date isn't checked until it is scheduled.
/posts/{id}Get a post getPost
One post, with its status and any publish error.
id (path)requiredstring
200Success401invalid_api_key404not_found429rate_limited500internal_error
/posts/{id}Edit a post updatePost
Changes a post's caption, picture, video or platforms; send only what changes. scheduledAt places a draft on a day without scheduling it; a scheduled post's time is changed with the schedule endpoint. Editing a scheduled post changes what goes out at its time. A post that has gone out, or is going out now, cannot be edited. Send at least one field, and at most one of imageUrl, video and videoUrl.
id (path)requiredstring
captionstringThe new post text.
imageUrlstring (uri)A public picture URL. Mutually exclusive with video and videoUrl.
videoobjectA video already uploaded with Upload a video. Mutually exclusive with imageUrl and videoUrl.
videoUrlstring (uri)A public MP4 or MOV link for Simplo to fetch. Mutually exclusive with imageUrl and video.
platformsarray of instagram | tiktok | facebook· at least 1The new list of platforms.
scheduledAtstring (date-time)ISO 8601 with UTC offset. Scheduling needs a future whole hour; a draft's date isn't checked until it is scheduled.
200Success400validation_error401invalid_api_key404not_found409already_published, publishing_in_progress413video_too_large429rate_limited500internal_error502upstream_error
/posts/{id}Delete a post deletePost
Deletes a post from Simplo; this cannot be undone. A published post stays on the social platforms: only Simplo's record and its analytics go. Deleting a scheduled post stops it from going out.
id (path)requiredstring
204No content401invalid_api_key404not_found429rate_limited500internal_error
/generate/captionscosts creditsGenerate caption ideas generateCaptions
On-brand post ideas (hook, caption, hashtags, image prompt) for a topic, saved as a research session. Costs credits. Needs a completed brand profile.
projectIdrequiredstringThe project whose brand the ideas follow.
topicrequiredstringWhat the posts are about.
platformsarray of instagram | tiktok | facebookShape the ideas for these platforms.
limitinteger· 1 to 10How many ideas, 1 to 10.
200Success400validation_error401invalid_api_key402insufficient_credits403subscription_inactive404not_found429rate_limited500internal_error502upstream_error
/generate/imagecosts creditsGenerate images generateImage
On-brand images for a post, saved to the project's image history. Costs credits (more for more images). Style "ad-layout" sets real type over a photo; other styles draw text badly. Every model tier currently runs as "standard".
projectIdrequiredstringThe project whose brand the images follow.
promptrequiredstringWhat the image shows.
formatinstagram-post | instagram-story | instagram-portrait | tiktok | x-post | facebook-post | facebook-cover· default "instagram-post"Picture sizes, not platforms: x-post is a picture shaped for X, and X itself isn't a platform the API posts to.
stylead-layout | studio | candid | cinematic | retro-film | flat-illustration | hand-drawn | render-3d | bold-type | minimal· default "studio"adBackgroundimage | brand· default "image"modelTierfast | standard | premium· default "standard"imageCountinteger· 1 to 4 · default 1How many images, 1 to 4. Each one costs credits.
includeLogoboolean· default false
200Success400validation_error401invalid_api_key402insufficient_credits403subscription_inactive404not_found429rate_limited500internal_error502upstream_error
/generate/carouselcosts creditsGenerate a carousel generateCarousel
Writes and draws an Instagram carousel about a topic and saves it as a draft post. Costs credits: the slide copy, plus each picture when pictures are on. It is never published or scheduled here. A slide in overflowSlides has more text than fits. If saving the draft fails after the slides were drawn, the answer is 502 with the slide URLs in details.slides: those slides are paid for, so use the URLs rather than retrying (a retry with the same Idempotency-Key gets the same answer).
Idempotency-Key (header)string· up to 255 charactersUp to 255 characters. Repeating a request with the same key within 24 hours returns the first answer instead of doing the work again.
projectIdrequiredstringThe project that owns the carousel.
topicrequiredstringWhat the carousel is about.
slideCountinteger· 2 to 10 · default 5How many slides, 2 to 10.
styleeditorial | clean | boldPhoto | darkpicturesboolean· default falseDraw a picture on each slide. Costs extra credits.
captionstringThe post text; written for you when left out.
scheduledAtstring (date-time)ISO 8601 with UTC offset. Scheduling needs a future whole hour; a draft's date isn't checked until it is scheduled.
/posts/{id}/scheduleSchedule a post schedulePost
Schedules a post, or moves a scheduled one to a new time. It is published to the connected accounts automatically at scheduledAt, which must be in the future and on the hour; without it the post keeps the time it has. Works on drafts, scheduled, missed and failed posts. A post that already went out cannot be rescheduled. Refused for a post that includes X.
id (path)requiredstring
scheduledAtstring (date-time)ISO 8601 with UTC offset. Scheduling needs a future whole hour; a draft's date isn't checked until it is scheduled.
/posts/{id}/publishPublish a post now publishPost
Publishes the post to its platforms immediately, on the real accounts; this cannot be undone. Safe to retry: a platform already published is skipped. The answer lists a result per platform and allSuccess. A send that is still in progress (a video, or a post going through a posting partner) answers 202 with pending: true; read the post for the result. A post that is already live answers 200 with alreadyPublished: true. Refused for a post that includes X.
id (path)requiredstringIdempotency-Key (header)string· up to 255 charactersUp to 255 characters. Repeating a request with the same key within 24 hours returns the first answer instead of doing the work again.
200Success202Accepted. The send is still in progress (pending: true); read the post for the result400validation_error, platform_not_available401invalid_api_key403subscription_inactive404not_found409publishing_in_progress, idempotency_in_progress422idempotency_key_reused429rate_limited500internal_error502upstream_error
/videosUpload or import a video uploadVideo
Hosts a video for a video post. Send an MP4 or MOV (up to 100 MB) as multipart/form-data in the file field, with projectId in the query string, or send JSON with a public url for Simplo to fetch, with projectId in the body or the query. The upload is streamed, never held in memory. Pass the returned video to Create a post as video.
projectId (query)stringThe project that owns the video. Required for an upload.
projectIdstringRequired here or in the query string.
urlrequiredstring (uri)A public MP4 or MOV link for Simplo to fetch.
filerequiredstring (binary)MP4 or MOV, up to 100 MB
201Created400validation_error401invalid_api_key403subscription_inactive404not_found413video_too_large429rate_limited500internal_error502upstream_error
/openapi.jsonno key neededGet the OpenAPI document getOpenApi
This API described as an OpenAPI 3.1 document. No API key needed.
200Success500internal_error