API and development
Process images with the SocialCutter API from Python
SocialCutter API client in Python with requests: health, platforms, processing by URL and file, batches, history, wallet and retries with backoff.
- Python
- requests
- API
- SocialCutter
- process images
- multipart
- API key
Requirements
Install requests and keep the credentials in environment variables:
pip install requests
export SOCIALCUTTER_API_URL="https://api.socialcutter.theboomer.dev"
export SOCIALCUTTER_API_KEY="sc_your_key"
Create the key at https://dash.socialcutter.theboomer.dev under Profile → API keys. It starts with sc_ and is shown only once. The full API reference is at https://docs.socialcutter.theboomer.dev.
Minimal client
A reusable session avoids repeating the header and credentials on every call:
import os
import requests
API_URL = os.environ.get("SOCIALCUTTER_API_URL", "https://api.socialcutter.theboomer.dev")
API_KEY = os.environ["SOCIALCUTTER_API_KEY"] # never hardcode it
session = requests.Session()
session.headers.update({"X-API-Key": API_KEY})
def get(path, **params):
r = session.get(f"{API_URL}{path}", params=params, timeout=30)
r.raise_for_status()
return r.json()
def post_json(path, payload):
r = session.post(f"{API_URL}{path}", json=payload, timeout=60)
r.raise_for_status()
return r.json()
raise_for_status() raises on any non-2xx response, so error bodies are never processed as if they were valid.
Health and credentials
# Public: no key required
print(get("/api/v1/health")) # status, version, uptime, database
# Identity of the authenticated account
print(get("/api/v1/auth/me"))
# Available uses
print(get("/api/v1/credits"))
/api/v1/health returns the service state and database connection. If /api/v1/auth/me returns 401, the key is missing, malformed or revoked.
List platforms and formats
data = get("/api/v1/platforms")
for platform, formats in data["platforms"].items():
for f in formats:
print(platform, f["format"], f"{f['width']}x{f['height']}", f["aspect_ratio"])
/platforms, /formats and /fit-modes are public. Use them to build the destination list without hardcoding dimensions.
Process an image by URL
resp = post_json("/api/v1/images/process", {
"source": {"type": "url", "value": "https://example.com/photo.jpg"},
"destinations": [
{"platform": "instagram", "format": "post"},
{"platform": "tiktok", "format": "cover"},
],
})
print(resp["id"], resp["status"])
Process a local file (multipart)
with open("photo.jpg", "rb") as fh:
r = session.post(
f"{API_URL}/api/v1/images/process/upload",
files={"file": ("photo.jpg", fh, "image/jpeg")},
data={"destinations": '[{"platform":"linkedin","format":"post"}]'},
timeout=60,
)
r.raise_for_status()
resp = r.json()
In multipart the file goes in the file field and destinations is a JSON string in a form field. The upload limit is 5 MB; above that the API returns 413.
Process a batch
batch = post_json("/api/v1/images/batch", {
"images": [
{"source": {"type": "url", "value": "https://example.com/a.jpg"},
"destinations": [{"platform": "instagram", "format": "post"}]},
{"source": {"type": "url", "value": "https://example.com/b.jpg"},
"destinations": [{"platform": "twitter", "format": "post"}]},
]
})
Read the response and download
The response carries the job id in id, a status and an outputs list, one entry per destination with platform, format, url, width, height and size_bytes. Timings live in metadata.
resp = post_json("/api/v1/images/process", {
"source": {"type": "url", "value": "https://example.com/photo.jpg"},
"destinations": [{"platform": "instagram", "format": "post"}],
})
for out in resp["outputs"]:
print(out["platform"], out["format"], f"{out['width']}x{out['height']}")
img = session.get(out["url"], stream=True, timeout=60)
img.raise_for_status()
with open(f"{out['platform']}-{out['format']}.webp", "wb") as fh:
for chunk in img.iter_content(8192):
fh.write(chunk)
History and wallet
# Last 10 images
print(get("/api/v1/history", limit=10))
# Only those created from the API
print(get("/api/v1/history", origin="api", limit=10))
# Daily quota, extra pool and purchased balance
print(get("/api/v1/wallet"))
limit accepts 1 to 100 and skip pages through results. The origin filter separates browser (dashboard) from api.
Errors and retries with backoff
Capture the status code and decide whether a retry is worth it. Client errors (4xx, except 429) are not retried: repeating the same request will not fix them.
import time
def with_retries(fn, attempts=4, base=0.5):
for i in range(attempts):
try:
return fn()
except requests.HTTPError as e:
code = e.response.status_code
if code == 429 or code >= 500:
if i == attempts - 1:
raise
time.sleep(base * (2 ** i)) # 0.5, 1, 2, 4 s
continue
raise
with_retries(lambda: post_json("/api/v1/images/process", payload))
For automatic retries across the whole session, requests delegates to urllib3.Retry, which applies exponential wait and honors the Retry-After header:
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=4,
backoff_factor=0.5,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset(["GET", "POST"]),
respect_retry_after_header=True,
)
session.mount("https://", HTTPAdapter(max_retries=retry))
Documented pattern at https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Retry. Names and options can change between library versions; confirm them in that documentation.
Cost
- 1 use per destination (platform and format) per request.
- Repeated destinations in the same request are not charged twice.
- Failed processings are refunded.
Typical errors
| Code | Meaning |
|---|---|
| 400 | Invalid payload: unknown platform, format or mode, malformed JSON, or a key already active |
| 401 | Missing, malformed, expired or revoked credentials |
| 404 | Resource not found (image or file id) |
| 413 | The file exceeds 5 MB |
| 422 | Request validation error |
| 429 | Wallet quota exhausted |
| 500 | Processing failure; uses from that request are refunded |
Next steps
- Terminal guide: Process images with the API from the terminal (curl)
- Node guide: Process images with the SocialCutter API from Node.js
- PHP guide: Process images with the SocialCutter API from PHP
- API documentation: https://docs.socialcutter.theboomer.dev
- Dashboard: https://dash.socialcutter.theboomer.dev
Frequently asked questions
Which library do I need in Python?
requests, installed with pip install requests. For multipart you need nothing else: requests builds the form when you pass files and data.
Where do I put the API key?
In the SOCIALCUTTER_API_KEY environment variable, never in code. It travels on every request in the X-API-Key header.
How do I upload an image from disk?
With POST /api/v1/images/process/upload using files={'file': ...} and destinations as a JSON form field. The limit is 5 MB.
How is a batch charged?
1 use per destination (platform and format) per image. A batch of 3 images with 2 destinations each is 6 uses.
Why do I get 429?
Because the wallet quota is exhausted. Check GET /api/v1/credits and GET /api/v1/wallet before large batches.