API docs
Partner API reference
Generate AI cartoons programmatically. Also available as a machine-readable OpenAPI 3.1 spec.
Overview
The API is REST over HTTPS. Requests and responses are JSON. Every response is an envelope:
successful calls return {"success": true, "data": {…}};
failures return {"success": false, "message": "…", "data": null}.
Cartoon creation is asynchronous — you receive render ids immediately and either poll or receive a webhook.
Preview images are always watermarked.
Every response carries an X-Trace-Id header — include it when contacting support.
Authentication
Send your secret API key on every request, either as a bearer token or a custom header. Keys are server-to-server only — never expose them in a browser, mobile app, or public repo. Create and revoke keys on the API keys page.
Authorization: Bearer ck_live_xxxxxxxxxxxxxxxx # — or — X-API-Key: ck_live_xxxxxxxxxxxxxxxx
Base URL
https://cartoonicate.com/api/v1/partner
Rate limits & quota
- Rate limit: a per-minute request cap set by your plan. Exceeding it returns
429 Too Many Requestswith aRetry-Afterheader (seconds). Honor it and back off. - Monthly quota: a monthly cap on previews generated. When exhausted, cartoon creation returns
402 Payment Required. The quota is checked before any generation, so a 402 means nothing was spent. - See your live numbers on the Plan and Usage pages.
Endpoints
Health / key check. Confirms your key works and shows which account + plan it maps to. Takes no parameters.
curl https://cartoonicate.com/api/v1/partner/ping.php \ -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init('https://cartoonicate.com/api/v1/partner/ping.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY'],
]);
$res = json_decode(curl_exec($ch), true);const res = await fetch('https://cartoonicate.com/api/v1/partner/ping.php', {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
});
const data = await res.json();Create a cartoon (asynchronous). Returns 202 with render ids; poll the GET endpoint or wait for the cartoon.completed webhook.
Body fields
| Field | Type | Required | Notes |
|---|---|---|---|
| subject | string | Yes | The subject(s)' appearance. |
| problem | string | Yes | The problem / pet-peeve / point. |
| location | string | Yes | The room / location. |
| holiday | enum | No | birthday, christmas, halloween, new_year, valentines, thanksgiving, st_patricks, fourth_of_july |
| style_preset | enum | No | new_yorker, anime, pixar_3d, newspaper_comic, sticker |
| tone | enum | No | playful, medium, savage |
| aspect_ratio | enum | No | 1:1, 9:16, 16:9 |
| format | enum | No | Output layout (default single): single, gag, reaction, comic, sticker_sheet. comic/sticker_sheet are multi-panel; gag/reaction add captions. |
| panel_count | enum | No | Panels for multi-panel formats: 3, 4, 6, 8. Ignored otherwise. |
| title_banner | string | No | Optional top banner / caption rendered verbatim (text formats; max 80 chars). |
| punchline_banner | string | No | Optional bottom banner / caption rendered verbatim (text formats; max 80 chars). |
| variants | integer | No | How many previews to generate (capped by your plan's max variants). |
| metadata | object | No | Opaque passthrough echoed back on reads & in the webhook. |
curl -X POST https://cartoonicate.com/api/v1/partner/cartoons.php \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": "a tired-looking developer with glasses",
"problem": "keeps pushing to main on a Friday",
"location": "a messy home office",
"tone": "medium",
"style_preset": "new_yorker",
"aspect_ratio": "1:1",
"variants": 2,
"metadata": {"order_id": "abc-123"}
}'<?php
$payload = json_encode([
'subject' => 'a tired-looking developer with glasses',
'problem' => 'keeps pushing to main on a Friday',
'location' => 'a messy home office',
'tone' => 'medium',
'style_preset' => 'new_yorker',
'variants' => 2,
'metadata' => ['order_id' => 'abc-123'],
]);
$ch = curl_init('https://cartoonicate.com/api/v1/partner/cartoons.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json',
],
]);
$res = json_decode(curl_exec($ch), true);const res = await fetch('https://cartoonicate.com/api/v1/partner/cartoons.php', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
subject: 'a tired-looking developer with glasses',
problem: 'keeps pushing to main on a Friday',
location: 'a messy home office',
tone: 'medium',
style_preset: 'new_yorker',
variants: 2,
metadata: { order_id: 'abc-123' },
}),
});
const data = await res.json();{
"success": true,
"message": "Cartoon queued. Poll the GET endpoint or wait for the webhook.",
"data": {
"cartoon": {
"id": 4821,
"status": "processing",
"variants": 2,
"render_ids": [9001, 9002],
"metadata": { "order_id": "abc-123" }
}
}
}Fetch a single cartoon you own, with each render's status and (once ready) its watermarked, signed, short-TTL preview URL.
curl "https://cartoonicate.com/api/v1/partner/cartoons.php?id=4821" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"cartoon": {
"id": 4821,
"source": "api",
"status": "complete",
"created_at": "2026-05-31 12:00:00",
"inputs": {
"subject": "a tired-looking developer with glasses",
"problem": "keeps pushing to main on a Friday",
"location": "a messy home office",
"holiday": null,
"style_preset": "new_yorker",
"tone": "medium",
"aspect_ratio": "1:1"
},
"metadata": { "order_id": "abc-123" },
"renders": [
{ "id": 9001, "status": "ready", "preview_url": "https://.../preview.png", "error": null },
{ "id": 9002, "status": "ready", "preview_url": "https://.../preview.png", "error": null }
],
"summary": { "total": 2, "ready": 2, "pending": 0, "complete": true }
}
}
}List your cartoons, newest first. Query params: limit (1–100, default 25), offset (default 0).
curl "https://cartoonicate.com/api/v1/partner/cartoons.php?limit=25&offset=0" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"cartoons": [
{ "id": 4821, "source": "api", "created_at": "2026-05-31 12:00:00", "inputs": { "...": "..." }, "metadata": null }
],
"pagination": { "limit": 25, "offset": 0, "total": 1 }
}
}Your account, plan, and current quota usage. Takes no parameters.
curl https://cartoonicate.com/api/v1/partner/account.php \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"account": {
"id": 12,
"company_name": "Acme Inc.",
"status": "active",
"webhook": { "configured": true, "url": "https://example.com/hooks" }
},
"plan": {
"code": "growth",
"name": "Growth",
"allow_webhooks": true,
"allow_final": false,
"max_variants": 4
},
"quota": {
"previews_per_month": 1000,
"previews_used": 137,
"previews_remaining": 863,
"rate_limit_per_min": 120,
"resets": "2026-06-01T00:00:00Z"
}
}
}Recent API calls plus a month-to-date summary. Query params: limit (1–100, default 50), offset (default 0).
curl "https://cartoonicate.com/api/v1/partner/usage.php?limit=50&offset=0" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"summary": { "calls_month": 412, "previews_month": 137, "errors_month": 3 },
"calls": [
{
"endpoint": "cartoons.php", "method": "POST", "status": 202,
"billable": "preview", "count": 2, "latency_ms": 91,
"trace_id": "a1b2c3d4", "created_at": "2026-05-31 12:00:00"
}
],
"pagination": { "limit": 50, "offset": 0, "total": 412 }
}
}Animations Premium
Animate one of your ready renders into a short clip. Animations are
premium (your plan must have allow_video enabled — otherwise you get
402) and asynchronous: creating one returns
202 with an animation id; poll the GET endpoint for the
watermarked preview. Calls meter against your monthly quota as video.
The un-watermarked final clip is never served over the API.
Body: render_id (required) — a ready render from one of your cartoons.
curl -X POST https://cartoonicate.com/api/v1/partner/animations.php \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "render_id": 9001 }'<?php
$payload = json_encode(['render_id' => 9001]);
$ch = curl_init('https://cartoonicate.com/api/v1/partner/animations.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json',
],
]);
$res = json_decode(curl_exec($ch), true);const res = await fetch('https://cartoonicate.com/api/v1/partner/animations.php', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ render_id: 9001 }),
});
const data = await res.json();{
"success": true,
"data": {
"animation": {
"id": 55,
"render_id": 9001,
"cartoon_id": 4821,
"status": "processing"
},
"message": "Animation queued. Poll GET /api/v1/partner/animations.php?id=55."
}
}Fetch one animation you own (or omit id to list them). Once ready, the watermarked preview URL is signed + short-TTL.
curl "https://cartoonicate.com/api/v1/partner/animations.php?id=55" \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"animation": {
"id": 55,
"render_id": 9001,
"cartoon_id": 4821,
"status": "complete",
"preview_url": "https://.../video_preview.png",
"duration_s": 4,
"created_at": "2026-05-31 12:05:00",
"error": null
}
}
}
An animation.completed webhook is forthcoming; for now, poll the GET endpoint.
Errors
All errors use the standard envelope with an HTTP status code and a human-readable message.
{
"success": false,
"message": "subject, problem, and location are all required.",
"data": null
}| Status | Meaning | When it happens |
|---|---|---|
| 401 | Unauthorized | Missing or invalid API key. Send a valid key via Authorization: Bearer or X-API-Key. |
| 402 | Quota exceeded | Your monthly preview quota is exhausted. Upgrade your plan or wait for the next cycle. |
| 404 | Not found | The requested cartoon does not exist or is not owned by your account. |
| 422 | Validation error | A required field is missing or a value is invalid. |
| 429 | Rate limited | Too many requests this minute. Honor the Retry-After response header and back off. |
| 500 | Server error | Something went wrong on our side. Retry with backoff; the trace id helps us investigate. |
Webhooks
If your plan supports webhooks and you've configured a URL on the
Webhooks page, we POST a
cartoon.completed event when a cartoon finishes rendering — so you don't have to poll.
{
"event": "cartoon.completed",
"created": "2026-05-31T12:01:30+00:00",
"data": {
"cartoon_id": 4821,
"renders": [
{ "id": 9001, "status": "ready", "preview_url": "https://.../preview.png" }
],
"metadata": { "order_id": "abc-123" }
}
}
Each delivery includes X-Cartoonicate-Signature: t=<ts>,v1=<hex>.
Verify it by recomputing hash_hmac('sha256', t . '.' . body, secret) and comparing in constant time.
<?php
$secret = getenv('CARTOONICATE_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_CARTOONICATE_SIGNATURE'] ?? ''; // "t=<ts>,v1=<hex>"
$parts = [];
foreach (explode(',', $header) as $kv) {
[$k, $v] = array_pad(explode('=', $kv, 2), 2, '');
$parts[$k] = $v;
}
$expected = hash_hmac('sha256', ($parts['t'] ?? '') . '.' . $body, $secret);
if (!hash_equals($expected, $parts['v1'] ?? '')) {
http_response_code(400);
exit('invalid signature');
}
// reject if abs(time() - (int)($parts['t'] ?? 0)) > 300 // replay guard
http_response_code(200);Prefer machine-readable? Load the OpenAPI 3.1 spec into Postman, Swagger UI, or your codegen of choice.