Developer docs

Calligraphy Generator API documentation

Use API keys to generate transparent PNG calligraphy images for Arabic names, cursive names, tattoo previews, wedding stationery, and product personalization.

Authentication

Send your API key in either header. Dashboard endpoints use your Supabase access token; public render endpoints use `cg_live_...` API keys.

Authorization: Bearer cg_live_your_key
# or
x-api-key: cg_live_your_key

POST /api/v1/generate

Required: `text` (120 characters max), `style`. Optional: `resolution`, `transparent_background`, `text_color`, `background_color` (6-digit hex), `response_format` (`data_url` or `base64`).

snake_case names are canonical; camelCase aliases (`textColor`, `backgroundColor`, `transparentBackground`, `responseFormat`, and `fontStyle` for `style`) are also accepted. If both forms are sent, the snake_case value wins.

curl https://www.calligraphy-generator.com/api/v1/generate \
  -H "Authorization: Bearer cg_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Layla",
    "style": "Diwani",
    "resolution": "SQUARE_HD",
    "transparent_background": true,
    "text_color": "#111827",
    "response_format": "data_url"
  }'
const response = await fetch('https://www.calligraphy-generator.com/api/v1/generate', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer cg_live_your_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    text: 'Layla',
    style: 'Diwani',
    resolution: 'SQUARE_HD',
    transparent_background: true,
    response_format: 'data_url',
  }),
});

const generation = await response.json();
console.log(generation.image.data_url);
import requests

response = requests.post(
    'https://www.calligraphy-generator.com/api/v1/generate',
    headers={'Authorization': 'Bearer cg_live_your_key'},
    json={
        'text': 'Layla',
        'style': 'Diwani',
        'resolution': 'SQUARE_HD',
        'transparent_background': True,
        'response_format': 'data_url',
    },
)
response.raise_for_status()
print(response.json()['image']['data_url'])

Response headers

Every successful generate response includes usage and rate-limit headers; 429 responses add `Retry-After`.

HeaderDescription
X-Request-IdUnique request ID — include it in support requests.
X-Usage-LimitMonthly render quota for your plan.
X-Usage-RemainingRenders remaining in the current billing period.
X-RateLimit-LimitRequests allowed per minute.
X-RateLimit-RemainingRequests remaining in the current one-minute window.
Retry-AfterOn 429 responses only: seconds to wait before retrying.

GET /api/v1/styles

Returns supported styles grouped by script (Arabic, English, Chinese) with `id`, `name`, `script`, `description`, and `preview_text`, plus output resolutions. Current styles: Diwani, Thuluth, Handwritten, Koufi, signature, calligraphy, bubble, Hanyi, Gen, Yrdzst. Resolutions: HD, SQUARE_HD, SQUARE_4K.

curl https://www.calligraphy-generator.com/api/v1/styles

Try every style live in the API playground.

Webhooks

Pro and Business plans can register up to 3 HTTPS endpoints (from the developer dashboard) to get quota alerts. Events: `quota.threshold_80` fires when usage crosses 80% of the monthly quota; `quota.exhausted` fires when the quota is fully used. Deliveries are one attempt per event with a 5-second timeout — no retries.

POST <your endpoint>
X-Webhook-Event: quota.threshold_80
X-Webhook-Signature: 8f3b2c... (hex SHA-256 HMAC of the raw body)

{
  "event": "quota.threshold_80",
  "data": { "used": 4000, "quota": 5000 },
  "created_at": "2026-06-10T12:00:00.000Z"
}
const crypto = require('crypto');
const expected = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET).update(rawBody).digest('hex');
if (expected !== req.headers['x-webhook-signature']) throw new Error('Invalid webhook signature');

Plans and limits

Free Test Mode

$0 · 100 renders/month · 20/minute

Starter

$19/mo · 1,000 renders/month · 60/minute

Pro

$49/mo · 5,000 renders/month · 180/minute

Business

$149/mo · 25,000 renders/month · 600/minute

Errors

Errors include a stable code and request ID. Keep the request ID for support. Only successful renders count toward your quota.

{
  "error": {
    "type": "quota_error",
    "code": "quota_exceeded",
    "message": "Monthly quota exceeded."
  },
  "request_id": "req_..."
}
StatusCodeDescription
400invalid_jsonBody is not valid JSON.
400invalid_requestA parameter failed validation (missing text, unknown style, bad hex color, ...).
401missing_api_keyNo API key was sent.
401invalid_api_keyThe key is unknown or revoked.
413request_too_largeBody exceeds 16 KB.
429quota_exceededMonthly quota used up. Retry-After indicates when the period resets.
429rate_limit_exceededPer-minute rate limit hit. Retry after Retry-After seconds.
500generation_failedRendering failed. Failed requests are not billed.
503metering_unavailableUsage metering is temporarily unavailable; the request was not billed. Retry shortly.