Code samples
Copy-paste examples in curl, TypeScript, and Python for every live endpoint.
Every example uses the placeholder cam_live_xxxxxxxxxxxxxxxxxxxx — replace with your real key from the dashboard.
Setup
# Get a key
open https://dashboard.createa.meme
# Set it once in your shell
export CAM_API_KEY="cam_live_xxxxxxxxxxxxxxxxxxxx"// TypeScript
const CAM_API_KEY = process.env.CAM_API_KEY!
const BASE = 'https://api.createa.meme'
async function camFetch(path: string, init?: RequestInit) {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: {
Authorization: `Bearer ${CAM_API_KEY}`,
'Content-Type': 'application/json',
...(init?.headers ?? {}),
},
})
if (!res.ok) {
const body = await res.text()
throw new Error(`Createa API ${res.status}: ${body}`)
}
return res.json()
}# Python (requires `pip install httpx`)
import os, httpx
CAM_API_KEY = os.environ["CAM_API_KEY"]
BASE = "https://api.createa.meme"
def cam(path: str, **kwargs):
headers = {"Authorization": f"Bearer {CAM_API_KEY}"}
headers.update(kwargs.pop("headers", {}))
res = httpx.request(headers=headers, **kwargs, url=f"{BASE}{path}")
res.raise_for_status()
return res.json()GET /v1/templates — list templates
curl -s "https://api.createa.meme/v1/templates?limit=10&category=reactions" \
-H "Authorization: Bearer $CAM_API_KEY"const { data } = await camFetch('/v1/templates?limit=10&category=reactions')
console.log(data.templates) // [{ id, name, slug, image_url, ... }]data = cam("/v1/templates", method="GET", params={"limit": 10, "category": "reactions"})["data"]
print(data["templates"][0]["name"])GET /v1/templates/{id} — single template detail
curl -s "https://api.createa.meme/v1/templates/tpl_drake" \
-H "Authorization: Bearer $CAM_API_KEY"const { data } = await camFetch('/v1/templates/tpl_drake')
// data.box_positions describes each region's role + max_charsdata = cam("/v1/templates/tpl_drake", method="GET")["data"]
for box in data["box_positions"]:
print(box["name"], box["role"], box["max_chars"])GET /v1/templates/{id}/image — blank template image (302 redirect)
curl -sL -o template.png "https://api.createa.meme/v1/templates/tpl_drake/image" \
-H "Authorization: Bearer $CAM_API_KEY"// Follow the 302 to the CDN URL
const res = await fetch(`${BASE}/v1/templates/tpl_drake/image`, {
headers: { Authorization: `Bearer ${CAM_API_KEY}` },
redirect: 'follow',
})
const buffer = Buffer.from(await res.arrayBuffer())GET /v1/trending — trending templates + topics
curl -s "https://api.createa.meme/v1/trending" \
-H "Authorization: Bearer $CAM_API_KEY"const { data } = await camFetch('/v1/trending')
console.log(data.templates.slice(0, 5)) // top 5 trendingGET /v1/models — available AI models
curl -s "https://api.createa.meme/v1/models" \
-H "Authorization: Bearer $CAM_API_KEY"const { data } = await camFetch('/v1/models')
// data.image_models = [{ id: 'gpt-image', cost_credits: 3, ... }, ...]
// data.caption_models = [{ id: 'gpt-5.5' }, { id: 'claude-sonnet-4-6' }, ...]POST /v1/meme/caption — caption a known template (1 credit)
curl -s -X POST "https://api.createa.meme/v1/meme/caption" \
-H "Authorization: Bearer $CAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template_id": "tpl_drake",
"captions": [
{ "text": "writing tests", "position": "top" },
{ "text": "writing the test that proves the bug exists", "position": "bottom" }
]
}'const { data } = await camFetch('/v1/meme/caption', {
method: 'POST',
body: JSON.stringify({
template_id: 'tpl_drake',
captions: [
{ text: 'writing tests', position: 'top' },
{ text: 'writing the test that proves the bug exists', position: 'bottom' },
],
}),
})
console.log(data.url) // CDN URLdata = cam("/v1/meme/caption", method="POST", json={
"template_id": "tpl_drake",
"captions": [
{"text": "writing tests", "position": "top"},
{"text": "writing the test that proves the bug exists", "position": "bottom"},
],
})["data"]
print(data["url"])POST /v1/meme/generate — text-to-meme, AI picks template + captions (2 credits)
curl -s -X POST "https://api.createa.meme/v1/meme/generate" \
-H "Authorization: Bearer $CAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "the perfect monday morning: no meetings, hot coffee, boss is OOO",
"count": 1,
"tone": "dry"
}'const { data } = await camFetch('/v1/meme/generate', {
method: 'POST',
body: JSON.stringify({
text: 'the perfect monday morning: no meetings, hot coffee, boss is OOO',
count: 1,
tone: 'dry',
}),
})
const meme = data.memes[0]
console.log(meme.url, meme.template.name, meme.caption)data = cam("/v1/meme/generate", method="POST", json={
"text": "the perfect monday morning: no meetings, hot coffee, boss is OOO",
"count": 1,
"tone": "dry",
})["data"]
print(data["memes"][0]["url"])POST /v1/meme/ai-image — original AI imagery (3 credits)
curl -s -X POST "https://api.createa.meme/v1/meme/ai-image" \
-H "Authorization: Bearer $CAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "a confused cat looking at deployment errors",
"caption": { "top": "WORKS ON MY MACHINE", "bottom": "MY MACHINE WAS LYING" },
"model": "gpt-image",
"aspect_ratio": "1:1",
"output_format": "png"
}'const { data } = await camFetch('/v1/meme/ai-image', {
method: 'POST',
body: JSON.stringify({
prompt: 'a confused cat looking at deployment errors',
caption: { top: 'WORKS ON MY MACHINE', bottom: 'MY MACHINE WAS LYING' },
model: 'gpt-image',
aspect_ratio: '1:1',
output_format: 'png',
}),
})
console.log(data.url)data = cam("/v1/meme/ai-image", method="POST", json={
"prompt": "a confused cat looking at deployment errors",
"caption": {"top": "WORKS ON MY MACHINE", "bottom": "MY MACHINE WAS LYING"},
"model": "gpt-image",
"aspect_ratio": "1:1",
"output_format": "png",
})["data"]
print(data["url"])POST /v1/meme/remix — edit or remix an existing image (5 credits)
curl -s -X POST "https://api.createa.meme/v1/meme/remix" \
-H "Authorization: Bearer $CAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/photo.jpg",
"prompt": "turn this person into a firefighter holding a hose, photorealistic",
"aspect_ratio": "1:1"
}'const { data } = await camFetch('/v1/meme/remix', {
method: 'POST',
body: JSON.stringify({
image_url: 'https://example.com/photo.jpg',
prompt: 'turn this person into a firefighter holding a hose, photorealistic',
aspect_ratio: '1:1',
}),
})
console.log(data.url) // CDN URLdata = cam("/v1/meme/remix", method="POST", json={
"image_url": "https://example.com/photo.jpg",
"prompt": "turn this person into a firefighter holding a hose, photorealistic",
"aspect_ratio": "1:1",
})["data"]
print(data["url"])POST /v1/animate — animate a template into a 5s clip (beta, 10-16 credits)
Asynchronous: submit returns a job_id; poll until completed. Invite-only
beta — email us for access.
curl -s -X POST "https://api.createa.meme/v1/animate" \
-H "Authorization: Bearer $CAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template_id": "tpl_moodeng3",
"motion": "the hippo blinks slowly and wiggles its ears",
"resolution": "480P"
}'
# -> { "data": { "job_id": "vid_...", "status": "queued", "poll_url": "..." } }
curl -s "https://api.createa.meme/v1/animate/vid_YOUR_JOB_ID" \
-H "Authorization: Bearer $CAM_API_KEY"
# poll every 2-3s -> { "data": { "status": "completed", "video_url": "https://..." } }const { data: job } = await camFetch('/v1/animate', {
method: 'POST',
body: JSON.stringify({
template_id: 'tpl_moodeng3',
motion: 'the hippo blinks slowly and wiggles its ears',
}),
})
let clip = job
while (clip.status === 'queued' || clip.status === 'processing') {
await new Promise((r) => setTimeout(r, 3000))
clip = (await camFetch(`/v1/animate/${job.job_id}`)).data
}
console.log(clip.status === 'completed' ? clip.video_url : clip.error)import time
job = cam("/v1/animate", method="POST", json={
"template_id": "tpl_moodeng3",
"motion": "the hippo blinks slowly and wiggles its ears",
})["data"]
while job["status"] in ("queued", "processing"):
time.sleep(3)
job = cam(f"/v1/animate/{job['job_id']}")["data"]
print(job["video_url"] if job["status"] == "completed" else job["error"])Error handling
All errors return a consistent JSON shape:
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry in 12s.",
"doc_url": "https://docs.createa.meme/errors/rate-limited"
}
}async function camFetch(path: string, init?: RequestInit) {
const res = await fetch(`https://api.createa.meme${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.CAM_API_KEY}`,
'Content-Type': 'application/json',
...(init?.headers ?? {}),
},
})
const body = await res.json()
if (!body.success) {
const err = body.error
if (err.code === 'RATE_LIMITED') {
const retry = Number(res.headers.get('retry-after') ?? 1)
await new Promise((r) => setTimeout(r, retry * 1000))
return camFetch(path, init) // simple retry
}
throw new Error(`${err.code}: ${err.message}`)
}
return body
}Coming soon: official SDK
We're shipping @createa/meme-api on npm — typed TypeScript client auto-generated from our OpenAPI spec. Watch the status page for release.