All endpoints require authentication via API key, except /health.
Authentication
Include your API key in every request using the X-API-Key header:
curl https://studio99.app/api/v1/fonts \
-H "X-API-Key: your_api_key"Get your API key from your Dashboard. Keep it secret — don't expose it in client-side code.
Text & Unicode
The API works best when you send exact Unicode (e.g. शुभ विवाह) — you get precise, predictable output. Romanized input (e.g. shubh vivah) also works: the API auto-detects and transliterates it, but you give up control over spelling choices.
If your users type in English letters, convert to Unicode in your app first, then send the Unicode to /generate. Google Input Tools does this for free (no key) — drop this helper into your product:
JavaScript
// Romanized -> Indic Unicode via Google Input Tools (free, no key).
// lang: 'hi' (Hindi) | 'mr' (Marathi) | 'gu' (Gujarati)
async function toUnicode(text, lang = 'hi') {
const url = `https://inputtools.google.com/request?text=${encodeURIComponent(text)}`
+ `&ime=transliteration_en_${lang}&num=1&ie=utf-8&oe=utf-8&app=jsapi`;
const res = await fetch(url);
const data = await res.json();
if (data[0] !== 'SUCCESS') return text; // fall back to input
return data[1].map((tok) => tok[1]?.[0] ?? '').join(''); // best of each token
}
// In your app: user types "shubh vivah" -> convert -> call Studio99.
const text = await toUnicode('shubh vivah', 'hi'); // "शुभ विवाह"
await fetch('https://studio99.app/api/v1/generate', {
method: 'POST',
headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ text, language: 'hindi', count: 4 }),
});Python
import requests
# lang: 'hi' (Hindi) | 'mr' (Marathi) | 'gu' (Gujarati)
def to_unicode(text, lang='hi'):
r = requests.get('https://inputtools.google.com/request', params={
'text': text, 'ime': f'transliteration_en_{lang}',
'num': 1, 'ie': 'utf-8', 'oe': 'utf-8', 'app': 'jsapi',
})
data = r.json()
if data[0] != 'SUCCESS':
return text
return ''.join((tok[1][0] if tok[1] else '') for tok in data[1])
text = to_unicode('shubh vivah', 'hi') # 'शुभ विवाह'
requests.post('https://studio99.app/api/v1/generate',
headers={'X-API-Key': 'YOUR_API_KEY'},
json={'text': text, 'language': 'hindi', 'count': 4})cURL (inspect the raw response)
curl "https://inputtools.google.com/request?text=shubh%20vivah&ime=transliteration_en_hi&num=5&ie=utf-8&oe=utf-8&app=jsapi"
# -> ["SUCCESS",[["shubh vivah",["शुभ विवाह","शुभ विवा", ...]]]]
# Pick a suggestion, then send it as "text" to /api/v1/generate.Tip: show your users the suggestions and let them pick, then send the chosen Unicode. Commas and line breaks are treated as separators. You can also try this live (with your key) in the Playground on your dashboard.
/api/v1/generateGenerate calligraphy text. Searches the library first, then generates new results.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The text to generate calligraphy for. Unicode text in the target language is preferred (Devanagari for Hindi/Marathi, Gujarati script, or Latin for English); romanized Latin is auto-transliterated as a fallback. |
language | string | No | "hindi", "marathi", "gujarati", "english" (or hi/mr/gu/en). Auto-detected if omitted. |
style | string | No | "calligraphy", "decorative", "publication" |
weight | string | No | Bias font selection toward a weight class: "light", "regular", "bold" or "extra_bold" (case-insensitive). Omit to let the engine choose. |
fontId | string | No | Specific font ID. Auto-selects if omitted. |
count | number | No | Number of results to return, 1–6 (default: 4). 6 is the max on every plan; higher values are clamped to 6. Each returned result costs 1 credit. |
format | string | No | "svg" (default) or "png". PNG is returned per result as base64, alongside the SVG. |
pngWidth | number | No | Target PNG width in px (default 1200, capped by your plan) |
use_case | string | No | Semantic font selection: "wedding", "invitations", "logos", "names", "posters", "greetings", "quotes", "certificates", "birthday", "religious", "festive", "formal", "casual" |
mood | string | No | Semantic font selection: "elegant", "festive", "playful", "romantic", "serious", "spiritual" |
recipe | string | array | No | Which typographic treatment(s) to return. Omit for the full curated slate. "plain" = clean text as-is (most legible); "flagship" = full calligraphy engine; "duo" = two-font light/bold (multiline). Pick ONE recipe + count to get that many variations of it. |
lines | string | number | No | Line breaking. "auto" (default) respects your \n line breaks, else auto-splits a phrase into 2–4 balanced lines. 1 = force a single line. 2–6 = force exactly that many lines. |
align | string | No | Alignment of stacked lines: "center" (default) — smart ink-nested centering; "left" / "right" — edge-aligned, still vertically nested. Ignored for single-line results. |
lineGap | number | No | Extra vertical spacing between stacked lines (multiline only). Leave unset for the calibrated default. |
seed | number | No | Reproducible output — the same seed with the same inputs returns the same result. Omit for fresh randomized variations each call. |
curl -X POST https://studio99.app/api/v1/generate \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"text": "शुभ विवाह",
"language": "hindi",
"count": 4,
"format": "svg"
}'Multi-line & recipes
Send a phrase and it auto-splits into optically-stacked lines, or use\nfor exact breaks. Pick a single recipe with acountto get that many variations of one treatment.
// Multi-line greeting, optically stacked
{ "text": "रक्षाबंधन की\nहार्दिक शुभकामनाएं", "language": "hindi" }
// 4 plain variations (different fonts), one per result
{ "text": "नमस्ते", "language": "hindi", "recipe": "plain", "count": 4 }
// Force 3 left-aligned lines
{ "text": "जय श्री राम", "language": "hindi", "lines": 3, "align": "left" }Good to know
Output format & speed. svg is the fastest to deliver — it's returned directly. png is rasterized on our servers, so it adds a little time. On the free tier, output is a watermarked preview image; paid plans return clean, full-resolution SVG (and PNG) — so a paid plan is both higher quality and typically faster than a watermarked preview. The first request after a period of inactivity may be slower (a cold start), then subsequent requests are quick.
Advanced options degrade gracefully. recipe, style, weight, use_case and mood are treated as preferences. If a combination would return too few results, the API automatically broadens the pool so you always get a full response rather than an empty or short one. For the most predictable output, send fewer constraints (or just text + language).
Response
{
"success": true,
"data": {
"libraryResults": [
{
"id": "art_abc123",
"displayName": "शुभ विवाह",
"thumbnailUrl": "https://...",
"source": "library",
"category": { "name": "Wedding", "slug": "wedding" }
}
],
"generatedResults": [
{
"id": "gen_xyz789",
"fontId": "font-uuid",
"fontFamily": "Calligraphy Pro",
"resultText": "...",
"source": "generated",
"svg": {
"path": "M10 20 C30 40...",
"width": 800,
"height": 200,
"svgString": "<svg>...</svg>"
},
"png": { "base64": "iVBORw0KG...", "width": 1200, "height": 300 }
}
],
"metadata": {
"fontSelection": { "wasAutoSelected": true, "detectedLanguage": "hindi" },
"processingTimeMs": 245
}
},
"usage": { "monthlyUsed": 42, "monthlyLimit": 5000, "remaining": 4958 }
}/api/v1/renderRe-render an exact text string in a given font — no transliteration or styling intelligence. Use generate to discover styled results, then render the chosen result at any size or format (e.g. a high-resolution download).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | Exact text to render — typically a resultText returned by generate |
fontId | string | Yes | Font ID (from generate results or the fonts endpoint) |
fontSize | number | No | SVG coordinate scale, 8–300 (default: 72) |
format | string | No | "svg" (default) or "png" |
pngWidth | number | No | Target PNG width in px (default 1200, capped by your plan) |
curl -X POST https://studio99.app/api/v1/render \
-H "X-API-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{
"text": "<resultText from generate>",
"fontId": "font-uuid",
"format": "png",
"pngWidth": 2048
}'Response
// format: "svg" (default)
{
"success": true,
"data": { "svgString": "<svg>...</svg>", "width": 800, "height": 200, "format": "svg" }
}
// format: "png"
{
"success": true,
"data": {
"png": { "base64": "iVBORw0KG...", "width": 2048, "height": 512 },
"width": 800,
"height": 200,
"format": "png"
}
}/api/v1/library/searchSearch the Inkora calligraphy art library.
Query Parameters
| Param | Type | Description |
|---|---|---|
q | string | Search query (text or name) |
category | string | Category slug: "wedding", "festival", "religious" |
language | string | Language code: "hi", "mr", "gu", "en" |
page | number | Page number (default: 1) |
limit | number | Results per page (default: 20, max varies by plan) |
curl "https://studio99.app/api/v1/library/search?q=diwali&language=hi&limit=10" \
-H "X-API-Key: your_api_key"/api/v1/library/{id}Get full details of a single artwork by ID, shortId, or slug.
curl "https://studio99.app/api/v1/library/art_abc123" \
-H "X-API-Key: your_api_key"/api/v1/library/{id}/downloadGet a short-lived signed download URL for an artwork file (PNG, JPG, or SVG).
curl "https://studio99.app/api/v1/library/art_abc123/download?format=PNG" \
-H "X-API-Key: your_api_key"
// Response
{
"success": true,
"data": {
"downloadUrl": "https://...", // valid for 5 minutes
"availableFormats": ["PNG", "JPG", "SVG"],
"canRenderSvg": true
}
}For artworks where canRenderSvg is true, GET /api/v1/library/{id}/render-svg returns a freshly rendered SVG of the artwork's text:
curl "https://studio99.app/api/v1/library/art_abc123/render-svg" \
-H "X-API-Key: your_api_key"
// Response
{
"success": true,
"data": { "svgString": "<svg>...</svg>", "width": 800, "height": 200, "fontFamily": "..." }
}/api/v1/fontsList all available fonts with metadata. Font files are never exposed.
curl "https://studio99.app/api/v1/fonts" \
-H "X-API-Key: your_api_key"Response
{
"success": true,
"data": {
"fonts": [
{
"id": "font-uuid",
"name": "Calligraphy Pro",
"slug": "calligraphy-pro",
"family": "CalligraphyPro",
"languages": ["Hindi", "Marathi"],
"style": "CALLIGRAPHY",
"weight": "REGULAR",
"categories": ["wedding", "festival"]
}
]
}
}/api/v1/capabilitiesCapability discovery for AI agents and developers — languages, formats, semantic vocabularies (moods, use cases), and endpoint map. No authentication required.
curl "https://studio99.app/api/v1/capabilities"
// Response (excerpt)
{
"success": true,
"data": {
"category": "Indic Typography API",
"languages": ["hindi", "marathi", "gujarati", "english"],
"formats": ["svg", "png"],
"supportsExactText": true,
"semantics": {
"moods": ["elegant", "festive", "playful", "romantic", "serious", "spiritual"],
"useCases": ["certificates", "greetings", "invitations", "logos", "names", ...]
},
"mcp": "https://mcp.studio99.app/api/mcp"
}
}The fonts endpoint accepts the same semantic vocabulary as filters: ?language=hindi&mood=elegant&use_case=wedding&limit=8
/api/v1/healthService health check. The only endpoint that requires no authentication.
curl "https://studio99.app/api/v1/health"
// Response
{ "success": true, "data": { "status": "ok", "version": "1.0" } }Error Codes
All errors return a standard format:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Monthly API call limit of 100 exceeded."
}
}| Code | HTTP | Description |
|---|---|---|
AUTHENTICATION_REQUIRED | 401 | Missing or invalid API key |
RATE_LIMIT_EXCEEDED | 429 | Monthly quota or burst limit exceeded |
INSUFFICIENT_CREDITS | 429 | Not enough credits for this request — lower count, top up, or upgrade |
INVALID_INPUT | 400 | Bad request body or parameters |
TEXT_TOO_LONG | 400 | Exceeds tier's max text length |
FONT_NOT_FOUND | 404 | Invalid fontId or artwork not found |
GENERATION_FAILED | 500 | Internal generation error |
Credits & Billing
The API bills in credits. Your plan includes a monthly credit allotment; you spend credits only on successful calls.
| Operation | Credit cost |
|---|---|
generate | 1 credit per variant returned |
render (SVG or PNG) | 1 credit per output |
library download | 1 credit (coming soon) |
search · fonts · health · capabilities | Free |
- One format per call. Omit
formatfor SVG, or sendformat=png. Both formats = two calls. - Free tier is preview-only. Output is a watermarked JPG (600×400, no commercial license). Upgrade for clean full-resolution SVG/PNG with a commercial license.
- Wallet top-ups. Paid plans can buy extra credits at ₹1/credit; purchased credits are spent after your monthly allotment and last 12 months.
- Inkora library. Coming soon for API plans.
Every response reports your live balance:
"usage": { "unit": "credits", "monthlyUsed": 42, "monthlyLimit": 5000, "remaining": 4958 }Rate Limits
Rate limits are applied per API key at two levels:
- Burst limit: Requests per minute (varies by plan: 5-120 req/min)
- Monthly limit: Credits per billing month (varies by plan: 100 to custom)
Rate limit info is included in response headers:
X-RateLimit-Limit: 20 # Max requests per minute
X-RateLimit-Remaining: 18 # Remaining in current window
X-RateLimit-Reset: 1704067200 # Window reset time (Unix)When rate-limited, the API returns HTTP 429 with a RATE_LIMIT_EXCEEDED error. Implement exponential backoff in your client.
Licensing & Usage
Artwork you generate on a paid plan is licensed to you for commercial use. In short: use what you generate freely in your own products — just don't resell the raw output as a competing library or service.
You can
- Use generated artwork in your apps, designs, and deliverables to your end-users
- Use it commercially, in perpetuity — including work created while your plan was active
- Store and integrate the output within your product
You can't
- Resell or redistribute the raw generated assets as standalone products
- Build a competing calligraphy/text-art generation service or asset library from our output
- Sublicense the output as-is to third parties
Free tier output is a watermarked preview for evaluation only — no commercial use. Full terms are in our Terms of Service.
Ready to build?
Get your free API key and start generating exact Indic typography in minutes.
Need help? Contact us or check the pricing page.