Skip to content

API docs

Partner API reference

Generate AI cartoons programmatically. Also available as a machine-readable OpenAPI 3.1 spec.

Samples:

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 Requests with a Retry-After header (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

GET /ping.php

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();
POST /cartoons.php

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
subjectstringYesThe subject(s)' appearance.
problemstringYesThe problem / pet-peeve / point.
locationstringYesThe room / location.
holidayenumNobirthday, christmas, halloween, new_year, valentines, thanksgiving, st_patricks, fourth_of_july
style_presetenumNonew_yorker, anime, pixar_3d, newspaper_comic, sticker
toneenumNoplayful, medium, savage
aspect_ratioenumNo1:1, 9:16, 16:9
formatenumNoOutput layout (default single): single, gag, reaction, comic, sticker_sheet. comic/sticker_sheet are multi-panel; gag/reaction add captions.
panel_countenumNoPanels for multi-panel formats: 3, 4, 6, 8. Ignored otherwise.
title_bannerstringNoOptional top banner / caption rendered verbatim (text formats; max 80 chars).
punchline_bannerstringNoOptional bottom banner / caption rendered verbatim (text formats; max 80 chars).
variantsintegerNoHow many previews to generate (capped by your plan's max variants).
metadataobjectNoOpaque passthrough echoed back on reads & in the webhook.
Request
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"}
  }'
Request
<?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);
Request
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();
Example response (202)
{
  "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" }
    }
  }
}
GET /cartoons.php?id={id}

Fetch a single cartoon you own, with each render's status and (once ready) its watermarked, signed, short-TTL preview URL.

Request
curl "https://cartoonicate.com/api/v1/partner/cartoons.php?id=4821" \
  -H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
  "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 }
    }
  }
}
GET /cartoons.php

List your cartoons, newest first. Query params: limit (1–100, default 25), offset (default 0).

Request
curl "https://cartoonicate.com/api/v1/partner/cartoons.php?limit=25&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
  "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 }
  }
}
GET /account.php

Your account, plan, and current quota usage. Takes no parameters.

Request
curl https://cartoonicate.com/api/v1/partner/account.php \
  -H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
  "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"
    }
  }
}
GET /usage.php

Recent API calls plus a month-to-date summary. Query params: limit (1–100, default 50), offset (default 0).

Request
curl "https://cartoonicate.com/api/v1/partner/usage.php?limit=50&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
  "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.

POST /animations.php

Body: render_id (required) — a ready render from one of your cartoons.

Request
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 }'
Request
<?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);
Request
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();
Example response (202)
{
  "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."
  }
}
GET /animations.php?id={id}

Fetch one animation you own (or omit id to list them). Once ready, the watermarked preview URL is signed + short-TTL.

Request
curl "https://cartoonicate.com/api/v1/partner/animations.php?id=55" \
  -H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
  "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.

Example error
{
  "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 payload
{
  "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.

Verify (PHP)
<?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.