Your own tools can do what you do on the website: turn links into branded posts with your templates, check on them, download the results and run your automations.

The API comes with Starter, Pro, Team S, Team M, Team L, Enterprise (not Free). Every call costs the same credits as doing it on the website. To use Socialix from Claude or ChatGPT without code, see Claude and ChatGPT (every plan).

Getting started

1. Make a key. Account, then API, then New key. Copy it right away: we only show it once. Keys start with sx_live_. Keep a key secret like a password.

2. Check that it works.

curl https://socialix.ai/api/v1/account/plan \
  -H "Authorization: Bearer sx_live_YOUR_KEY"

3. Find your template.

curl https://socialix.ai/api/v1/templates/ \
  -H "Authorization: Bearer sx_live_YOUR_KEY"
# [{"id": 812, "name": "History covers", "template_type": "post_rebrand", ...}]

4. Make a post from a link. Send an Idempotency-Key. If your connection drops and you send the same request again with the same key, you get the first answer back instead of a second post and a second charge.

curl -X POST https://socialix.ai/api/v1/jobs/ \
  -H "Authorization: Bearer sx_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: history-001" \
  -d '{"url": "https://www.instagram.com/p/DAbc123/", "template_id": 812}'
# 201 {"id": 90412, "status": "queued", ...}

5. Get the result. Ask every few seconds, or add a webhook and we tell you.

curl https://socialix.ai/api/v1/jobs/90412 \
  -H "Authorization: Bearer sx_live_YOUR_KEY"
# {"status": "done",
#  "result_url": "https://socialix.ai/api/v1/files/s/...",
#  "result_slide_urls": null,
#  "result_ig_caption": "..."}

result_url opens the file without a key for about 60 minutes, so you can hand it straight to a scheduler. If a post fails, status is failed, error_code says why, and the credits come back.

Keys

Send the key on every call: Authorization: Bearer sx_live_YOUR_KEY. A key acts as the person who made it and only ever reaches that account's own templates, posts and files. It can never reach billing, sign-in, your team settings, or other keys. Keys made before 21 October 2026 start with sk_live_ and keep working.

When you make a key you can limit what it may do:

PermissionWhat it allows
account:readSee plan, credits and performance
automations:readSee automations and their runs
automations:writeCreate, edit, pause, delete and run automations
jobs:readSee posts, their results and your library
jobs:writeMake, cancel and retry posts
templates:readSee templates and folders
templates:writeCreate, copy, edit and delete templates

Revoke a key on the same page and it stops working at once. On a team, every member makes their own keys, posts are paid from the team's shared credits, and the team owner can see and revoke every member's keys. If your plan changes to one without the API, your keys answer 403 until it comes back; nothing is deleted.

Plans, limits and credits

PlanCalls a minute, per keyCalls a minute, all keysNew posts a minutePosts waiting at onceKeysWebhooks
Starter120240302531
Pro3006001205053
Team S6001,20012010055
Team M6001,20012015055
Team L6001,20012025055
Enterprise1,2002,400600By agreement2010

Over a limit you get 429 with a Retry-After header. Request bodies can be up to 512 KB; send pictures and videos through /uploads/.

Credits per post, the same as on the website:

Post Rebrand (cover or slideshow)10
Tweet Rebrand10
Tweet Card5
Simple Overlay5
Snapchat5
Canvas5 (+ 1 per extra source)
Copy my page's look150
Find sources150 (given back if nothing is found)
Performance "Refresh now"5
Clip versions10 (per clip)
Download or crop1 (Free plan only, free on paid plans)

A failed or cancelled post gives its credits back. See pricing for the monthly credits of each plan.

Making posts

Many links, one template. Up to 50 links into a Post Rebrand template in one call, then follow the batch:

curl -X POST https://socialix.ai/api/v1/jobs/batch -H "Authorization: Bearer sx_live_YOUR_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: batch-17" \
  -d '{"template_id": 812, "items": [{"source_post_url": "https://www.instagram.com/p/A/"},
                                     {"source_post_url": "https://www.instagram.com/p/B/"}]}'
curl https://socialix.ai/api/v1/jobs/batch/BATCH_ID -H "Authorization: Bearer sx_live_YOUR_KEY"

One link, several templates (one post per page you run): POST /jobs/fanout with url and template_ids.

Your own pictures or videos. Upload first, then pass the address you get back in picture_urls or video_urls:

curl -X POST https://socialix.ai/api/v1/uploads/ -H "Authorization: Bearer sx_live_YOUR_KEY" -F "file=@photo.jpg"

Plain download or crop of a source link: POST /jobs/download and POST /jobs/crop with url.

Getting results

GET /jobs/{id} answers one post. To pick up everything that finished for some templates, poll like this and move your cursor to the finished_at of the last post you handled:

curl "https://socialix.ai/api/v1/jobs/?template_ids=812,813&finished_since=2026-10-21T08:00:00Z&order=oldest&status=done&limit=50" \
  -H "Authorization: Bearer sx_live_YOUR_KEY"

Use order=oldest with a cursor, or a busy minute can skip posts. Unknown query parameters are ignored, not refused, so check the names.

Your library, every finished post newest first, each with a download_url: GET /workspace/outputs?page=1&page_size=60. With the key you can also fetch the bytes directly: GET /files/{result_file_id}.

Webhooks

Add an https address under Account, then API, and we POST to it when a post finishes:

{"event": "job.finished",
 "job": {"id": 90412, "public_id": "JOB-AB12", "status": "done", "template_id": 812,
         "error_code": null, "finished_at": "2026-10-21T08:00:00Z",
         "result_url": "https://socialix.ai/api/v1/files/s/...", "slide_urls": null}}

Check that it came from us. The signature is an HMAC-SHA256 of the timestamp, a dot and the raw body, with the secret shown next to the address:

import hmac, hashlib, time

def is_from_socialix(secret, headers, raw_body):
    ts = headers["X-Socialix-Timestamp"]
    if abs(time.time() - int(ts)) > 300:
        return False
    expected = hmac.new(secret.encode(), ts.encode() + b"." + raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, headers["X-Socialix-Signature"])

Answer with any 2xx quickly. Anything else is tried again 5 times in all (after 30 s, 120 s, 480 s, 1920 s), and after 20 failures in a row the address is switched off until you switch it back on.

Automations and stats

List them with GET /automations, run one now with POST /automations/{id}/run-now, pause or resume with PATCH /automations/{id} and {"enabled": false} or true. Automation posts cost credits like any post. Stats of the pages you track: GET /performance/overview and GET /performance/highlights. Credits left: GET /account/plan.

Errors

401The key is wrong or revoked.
402Not enough credits. The answer says how many are needed and how many you have.
403The plan has no API (plan_required), the key lacks that permission, or no key may call that address.
404Not found, or not yours. Both answer the same.
409A request with the same Idempotency-Key is still running, or the post is not in a state for that action.
413The request body is too large.
422Something in the request does not make sense; the answer says what.
429Too many calls, or too many posts waiting. Wait for Retry-After seconds.

A failed post is not a failed request: the request answers 201, and the post later ends with status: failed and an error_code.

Working with AI

Building with Claude, ChatGPT or Cursor? Copy this prompt into the chat first. It lists every endpoint (and says the list is complete, so the AI does not invent addresses), the limits and the credit prices. It never contains a key.

Show the prompt
You are helping me write code against the Socialix API.

## What Socialix does
It turns a link (usually an Instagram post or a video) plus one of my
templates into a finished social post: a rendered video or image, with a
caption. Each of those runs is a JOB.

## Talking to it
Base URL: https://socialix.ai/api
Auth: every request carries `Authorization: Bearer sx_live_...`
Bodies are JSON. Put your real key in an environment variable, never in
code you paste anywhere, including back to me.

## Rules you must follow

1. THE ENDPOINT LIST BELOW IS COMPLETE. If something you want is not on
   it, it does not exist. Do not guess a plausible-looking path, and do
   not assume a REST convention fills a gap. Say the API cannot do it.

2. ALWAYS send an `Idempotency-Key` header on POSTs that make something.
   Making a post costs credits. If the connection drops you cannot know
   whether it worked, and a plain retry charges twice. Send a unique
   string per intended action; retrying with the SAME one returns the
   original result instead of doing it again. Reusing one with different
   content is a 422, not a replay.

3. DO NOT POLL FOR COMPLETION IN A LOOP. A job is asynchronous: the POST
   returns immediately with a job id, and the work happens after. Prefer
   the webhook (below). If you must watch a single job you just made,
   GET /v1/jobs/{job_id}/stream is a live stream, still not a poll loop.

4. A FAILED JOB IS NOT A FAILED REQUEST. The POST succeeds; the job later
   reaches status `failed` with an `error_code` saying why. Handle those
   separately from HTTP errors.

## What the key may do
- account:read: See plan, credits and performance
- automations:read: See automations and their runs
- automations:write: Create, edit, pause, delete and run automations
- jobs:read: See posts, their results and your library
- jobs:write: Make, cancel and retry posts
- templates:read: See templates and folders
- templates:write: Create, copy, edit and delete templates

A key is refused (403) for anything outside that list: billing, sign-in,
the team, moderation, admin, and managing keys or webhooks themselves.

## HTTP responses
- 200/201 fine. 401 the key is wrong or cancelled. 403 the key lacks that
  permission, nothing may reach that path with a key at all, or the plan
  has no API (error plan_required).
- 409 an earlier request with the same Idempotency-Key is still running.
- 422 the request did not make sense (the body says which part).
- 429 too many requests; the plan sets the rate. Back off and retry.

## Being told when a job finishes
Socialix POSTs to an address I register in the console. Body:
  {"event":"job.finished","job":{"id":1,"public_id":"JOB-AB","status":"done",
   "template_id":7,"error_code":null,"finished_at":"2026-01-01T00:00:00Z",
   "result_url":"https://.../files/s/...","slide_urls":null}}
result_url is a signed link that works without a key for about an hour.
Verify it before trusting it:
  timestamp = the X-Socialix-Timestamp header
  expected  = HMAC_SHA256(secret, timestamp + "." + raw_request_body)
  compare expected with the X-Socialix-Signature header,
  in constant time, against the RAW body, not a re-serialised copy of it,
  which will differ by whitespace and never match.
Reject a timestamp far from now: that is what stops a captured message
being replayed. Reply 2xx quickly; anything else is retried
5 times (30s, 120s, 480s, 1920s), and after 20 failures in a row the
address is switched off.

## Plans, limits and credits (from the live configuration)
API keys: Starter, Pro, Team S, Team M, Team L, Enterprise. Not on: Free.
- Starter: 120 calls/min per key, 240 per account, 30 new jobs/min, 25 jobs waiting at once, 3 keys, 1 webhooks
- Pro: 300 calls/min per key, 600 per account, 120 new jobs/min, 50 jobs waiting at once, 5 keys, 3 webhooks
- Team S: 600 calls/min per key, 1200 per account, 120 new jobs/min, 100 jobs waiting at once, 5 keys, 5 webhooks
- Team M: 600 calls/min per key, 1200 per account, 120 new jobs/min, 150 jobs waiting at once, 5 keys, 5 webhooks
- Team L: 600 calls/min per key, 1200 per account, 120 new jobs/min, 250 jobs waiting at once, 5 keys, 5 webhooks
- Enterprise: 1200 calls/min per key, 2400 per account, 600 new jobs/min, no fixed cap jobs waiting at once, 20 keys, 10 webhooks
Credits per job (the same as on the website):
- Post Rebrand (cover or slideshow): 10
- Tweet Rebrand: 10
- Tweet Card: 5
- Simple Overlay: 5
- Snapchat: 5
- Canvas: 5 (+ 1 per extra source)
- Copy my page's look: 150
- Find sources: 150 (given back if nothing is found)
- Performance "Refresh now": 5
- Clip versions: 10 (per clip)
- Download or crop: 1 (Free plan only, free on paid plans)
Request bodies: at most 512 KB of JSON; send media through /v1/uploads/.

## Every endpoint (complete)

### account:read
GET /v1/account/plan: Your plan and credits
GET /v1/account/usage: Your usage
GET /v1/performance/highlights: Page highlights
GET /v1/performance/overview: Page stats overview
GET /v1/performance/pages/{profile_id}: One page's stats
GET /v1/performance/profiles: Tracked pages
GET /v1/performance/profiles/{profile_id}: A tracked page
GET /v1/performance/profiles/{profile_id}/follower-history: Follower history
GET /v1/performance/profiles/{profile_id}/reels: A page's posts
GET /v1/performance/profiles/{profile_id}/refresh-status: Refresh state
GET /v1/performance/watching/feed: Watched pages feed

### automations:read
GET /v1/automations: List automations
GET /v1/automations/limits: Automation limits
GET /v1/automations/{automation_id}: Get an automation
GET /v1/automations/{automation_id}/outputs: Posts from an automation
GET /v1/automations/{automation_id}/runs: Automation runs

### automations:write
POST /v1/automations: Create an automation
    body required: name, run_hour, run_minute, sources
    body optional: always_crop, enabled, folder_id, max_posts_per_day, route_overrides, template_id, workspace_topic_opt_in, workspace_topic_scope
DELETE /v1/automations/{automation_id}: Delete an automation
PATCH /v1/automations/{automation_id}: Change an automation
    body optional: always_crop, destination_id, enabled, folder_id, max_posts_per_day, name, route_overrides, run_hour, run_minute, sources, template_id, workspace_topic_opt_in, workspace_topic_scope
POST /v1/automations/{automation_id}/run-now: Run an automation now
POST /v1/automations/{automation_id}/runs/{run_id}/retry-failed: Retry a run's failed posts

### jobs:read
GET /v1/files/kind/{file_id}: Is a file a video or a picture
GET /v1/files/s/{token}: Download through a signed link
GET /v1/files/{file_id}: Download a file
GET /v1/jobs/: List posts
GET /v1/jobs/batch/{batch_id}: Progress of a batch
GET /v1/jobs/source-probe: What a link holds
    query required: url
GET /v1/jobs/thumbnail: Preview picture of a link
    query required: url
GET /v1/jobs/typical-duration: Typical time per kind of job
GET /v1/jobs/{job_id}: Get a post
GET /v1/jobs/{job_id}/stream: Live progress of a post
GET /v1/uploads/{filename}: Get an upload
GET /v1/workspace/outputs: Your library

### jobs:write
POST /v1/jobs/: Make a post
    body required: template_id
    body optional: lane (interactive | bulk or empty), apply_crop, element_overrides, image_source_mode, manual_tweet_text, picture_urls, url, video_urls
POST /v1/jobs/batch: Make many posts
    body required: template_id, items
    body optional: image_source_mode
POST /v1/jobs/crop: Crop a video
    body required: url
    body optional: apply_crop
POST /v1/jobs/download: Download a source
    body required: url
POST /v1/jobs/fanout: One link, several templates
    body required: template_ids
    body optional: apply_crop, element_overrides, image_source_mode, manual_tweet_text, picture_urls, url, video_urls
POST /v1/jobs/{job_id}/cancel: Cancel a post
POST /v1/jobs/{job_id}/get-anyway: Get a refused cover anyway
POST /v1/jobs/{job_id}/retry: Retry a failed post
POST /v1/uploads/: Upload a picture or video

### templates:read
GET /v1/templates/: List templates
GET /v1/templates/folders: Template folders
GET /v1/templates/post-rebrand/settings: Post Rebrand settings
GET /v1/templates/{template_id}: Get a template
GET /v1/templates/{template_id}/thumbnail: Template preview picture

### templates:write
POST /v1/templates/: Create a template
    body required: name, template_type (twitter | snapchat | simple_overlay | canvas | tweet_rebrand | post_rebrand)
    body optional: ai_emoji_level (none | some | lots or empty), ai_language (en | de | es | pt | fr | it | nl | tr | ar | ja | ko | hi | id | pl | ru | match or empty), bg_color (black | white), content_style (meme | hype | deadpan | wholesome | dramatic | informative), end_slide_style (dark | block | blur | profile | save | split | bigfollow | next or empty), end_slide_when (always | replace | never or empty), other_slides (restyle | as_they_came | leave_out or empty), post_look (classic | bold | story | panel | mag | html or empty), slide_frame_bg (black | blur or empty), slide_num_style (plain | big or empty), slide_pic_style (keep | blur | frame | strip or empty), slide_text_style (native | box | bar or empty), tweet_text_mode (ai | fixed | manual | none), ai_banned_words (+47 more)
POST /v1/templates/bulk: Move or delete templates
    body required: template_ids, action (move | delete)
    body optional: folder_id
POST /v1/templates/folders: Create a folder
    body required: name
DELETE /v1/templates/folders/{folder_id}: Delete a folder
PATCH /v1/templates/folders/{folder_id}: Rename a folder
    body required: name
DELETE /v1/templates/{template_id}: Delete a template
PATCH /v1/templates/{template_id}: Change a template
    body optional: ai_emoji_level (none | some | lots or empty), ai_language (en | de | es | pt | fr | it | nl | tr | ar | ja | ko | hi | id | pl | ru | match or empty), bg_color (black | white or empty), content_style (meme | hype | deadpan | wholesome | dramatic | informative or empty), end_slide_style (dark | block | blur | profile | save | split | bigfollow | next or empty), end_slide_when (always | replace | never or empty), other_slides (restyle | as_they_came | leave_out or empty), post_look (classic | bold | story | panel | mag | html or empty), slide_frame_bg (black | blur or empty), slide_num_style (plain | big or empty), slide_pic_style (keep | blur | frame | strip or empty), slide_text_style (native | box | bar or empty), template_type (twitter | snapchat | simple_overlay | canvas | tweet_rebrand | post_rebrand or empty), tweet_text_mode (ai | fixed | manual | none or empty) (+52 more)
POST /v1/templates/{template_id}/duplicate: Copy a template
POST /v1/templates/{template_id}/pin: Pin a template

## Watching for finished work
If you cannot receive a webhook (no public address), poll like this.
this is the ONLY correct shape, and it replaces the retired
/integrations/jobs/recent endpoint:

  GET /v1/jobs/?template_ids=762,761&finished_since=<ISO>&order=oldest
      &status=done&limit=50

- order=oldest is REQUIRED when walking a cursor. Newest-first with a
  limit silently drops the older end of a busy window, and your cursor
  then steps past jobs you never saw.
- finished_since filters on when a job FINISHED, not when it was made.
  A job created before your cursor can finish after it.
- Advance your cursor to the finished_at of the last item you handled,
  not to 'now': anything that finished while you were working would be
  skipped.
- Unknown query parameters are IGNORED, not rejected. A typo returns 200
  with the wrong rows rather than an error, so check the names above.

## What was retired
/integrations/jobs/recent, /integrations/templates and
/integrations/files/{id} were removed on 2026-09-15. If you find code
calling them, it is old: rewrite it against the endpoints above. They
used one shared password; a key replaces it.

## A worked example
```bash
curl -X POST https://socialix.ai/api/v1/jobs/ \
  -H "Authorization: Bearer $SOCIALIX_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"template_id": 762, "url": "https://www.instagram.com/p/ABC123/"}'
```
The response carries the job id. Wait for the webhook (or poll as above),
then read GET /v1/jobs/{id}. `result_url` is a signed link to the file
that works without the key for about an hour (hand it to a scheduler).
Or fetch GET /v1/files/{result_file_id} with the key: that returns the
BYTES, with a real Content-Type (image/jpeg, video/mp4). GET /v1/files/kind/{id} answers
image | video | unknown if you need to know before downloading;
"unknown" is a real answer, not an error, because most ids carry no
file extension.

Ask me for the template id you should use. Do not invent one.

Every endpoint with its fields · openapi.json · Support