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"])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.