Documentation

Learn how to generate dynamic images using our API

API Reference

Complete OpenAPI specification with all endpoints

View the auto-generated OpenAPI documentation for detailed endpoint specifications, request/response schemas, and authentication details.

Quickstart Guide

1. Clone a Starter Template

The fastest way to a working template: open Templates → New Template → Browse Starter Templates and click one.

It's cloned into your account and opens in the editor — tweak it or use it as-is.

Copy your new Template ID from the editor URL or the templates list.

Then create an API key (step 2) and render it in seconds with POST /api/generate (step 3), passing your Template ID plus any layer overrides.

Want a public, no-auth image URL instead? A cloned template is private by default, so first enable App → URL Access (allow all domains or whitelist yours), then use the public /api/render URL (step 4).

Or build a template from scratch

Navigate to Templates → New Template

Choose a preset (e.g., OG Image 1200×630px)

Add layers with semantic names: title, subtitle, logo

Save the template and note your Template ID

2. Create an API Key

Go to App → API Keys → Create New Key to generate your authentication token

3. Generate via API (Authenticated)

Use layer overrides to dynamically customize your template:

const response = await fetch('https://yourdomain.com/api/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    templateId: 'your-template-id',
    layers: {
      title: { text: 'My Blog Post Title' },
      subtitle: {
        text: 'Published on Jan 15',
        fontSize: 24,
        color: '#666666'
      },
      logo: {
        image_url: 'https://example.com/logo.png',
        width: 120,
        height: 120
      }
    },
    format: 'png',  // 'png' (default), 'jpeg', or 'webp'
    quality: 80     // 1-100 for jpeg/webp; ignored for png
  })
});

const { success, imageUrl, cached, warnings } = await response.json();
// warnings (optional) lists any image that failed to load or an
// unresolved asset reference — the render still returns 200.
// Use imageUrl in your application

The public /api/render endpoint always returns PNG; use /api/generate with format for JPEG or WebP output.

3a. Layer Override Reference

Each override targets a layer by its name and must match the shape for that layer's type. Any subset of fields works — override just fontSize without text, or just objectFit without image_url. The full typed schemas (TextLayerOverrides, ImageLayerOverrides, ShapeLayerOverrides) are in the API Reference.

Text layers   text, fontSize, fontWeight, fontStyle, fontFamily, color,
              textAlign, verticalAlign, lineHeight, letterSpacing,
              textTransform, textDecoration, backgroundColor,
              borderRadius, width, height, rotation

Image layers  image_url, objectFit, objectPosition, borderRadius,
              border, opacity, width, height, rotation

Shape layers  fill, opacity, borderWidth, borderColor, borderStyle,
              borderRadius, width, height, rotation

Strict validation: a malformed override — a bare value instead of an object ({ "title": "Hello" } instead of { "title": { "text": "Hello" } }), an unknown field, or a wrong type — is rejected with a 400 that names the offending layer and field. Text content is set with text (not content), image sources with image_url (not src).

Warnings: an override that names a layer that doesn't exist in the template, or carries fields the layer's type can't use, renders fine but is reported in the response's warnings array (or the X-Render-Warnings header on /render) as override_ignored.

3b. Use your own images (asset references)

Upload an image, then reference it in any image_url override (or a template layer's src) with its asset:<id> reference. The renderer resolves it from your account server-side, so you never need a public URL. You can also pass a base64 data:image/* URI directly. Prefer a UI? Manage your uploads and copy references under App → Assets.

# 1. Upload a file (multipart). 'name' is optional.
curl -X POST https://yourdomain.com/api/uploads \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -F '[email protected]' \
  -F 'name=hero shot'
# → 201 { "id": "...", "name": "hero shot", "reference": "asset:...", ... }

# 2. List your uploads to find their ids / references later
curl https://yourdomain.com/api/uploads \
  -H 'Authorization: Bearer YOUR_API_KEY'
# → { "uploads": [{ "id": "...", "name": "hero shot", "reference": "asset:..." }], "total": 1 }

# 3. Reference it when generating (works in image_url overrides and layer src)
{
  "templateId": "your-template-id",
  "layers": {
    "photo": { "image_url": "asset:PASTE_UPLOAD_ID" }
  }
}

3c. TypeScript SDK (@renderfast/client)

Prefer a typed client over raw fetch? The official SDK wraps every endpoint and returns a { data, error } result — no manual URL building or response parsing.

npm install @renderfast/client
import { createClient, postApiGenerate } from '@renderfast/client';

const client = createClient({
  baseUrl: 'https://yourdomain.com',
  headers: {
    Authorization: 'Bearer ' + process.env.RENDERFAST_API_KEY
  }
});

const { data, error } = await postApiGenerate({
  client,
  body: {
    templateId: 'your-template-id',
    layers: {
      title: { text: 'My Blog Post Title' },
      subtitle: { text: 'Published on Jan 15', fontSize: 24, color: '#666666' }
    }
  }
});

if (error) throw error;
console.log(data.imageUrl); // { success, imageUrl, cached, generationTimeMs }

The same generated functions cover the rest of the API — getApiTemplates, postApiTemplatesByIdClone, getApiUploads, and more. Each takes { client, body?, path?, query? } and returns { data, error }.

4. Generate via URL (Public, No Auth)

For public templates, generate images directly via URL with JSON-encoded layer data:

# Simple text override
/api/render?templateId=uuid&layers={"title":{"text":"Hello World"}}

# Multiple layer overrides
/api/render?templateId=uuid&layers={"title":{"text":"Blog Title"},"subtitle":{"text":"By John Doe"},"logo":{"image_url":"https://example.com/avatar.jpg"}}

# Use in HTML
<meta property="og:image" content="https://yourdomain.com/api/render?templateId=..." />

Note: The public endpoint doesn't require authentication and doesn't count toward rate limits. Perfect for social media OG images!

5. Edit Templates Programmatically (Optional)

Update existing templates via API for programmatic template management, bulk updates, or CI/CD integration:

const response = await fetch('https://yourdomain.com/api/templates/your-template-id', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Updated Template Name',
    description: 'Updated description',
    jsonData: {
      canvas: { width: 1200, height: 630, background: '#ffffff' },
      layers: [
        // Your updated layer definitions
      ],
      variables: []
    }
  })
});

const updatedTemplate = await response.json();

Updatable fields: name, description, jsonData, previewUrl

Template Creation Guide

Layer Naming (Critical Concept)

  • Each layer needs a unique name (e.g., "title", "avatar", "date")
  • Layer names are used as keys in the API
  • Choose semantic names that describe the content
  • Use lowercase with underscores (e.g., "post_title", "author_avatar")

Layer Types & Overrides

Text Layers

Override text content and styling:

{
  "title": {
    "text": "New content",
    "fontSize": 48,
    "fontWeight": "bold",
    "color": "#000000",
    "textAlign": "center",
    "lineHeight": 1.2,
    "letterSpacing": -1,
    "textTransform": "uppercase"
  }
}

Image Layers

Override image source and display properties:

{
  "avatar": {
    "image_url": "https://example.com/avatar.jpg",
    "width": 120,
    "height": 120,
    "objectFit": "cover",
    "borderRadius": 60,
    "opacity": 1
  }
}

Canvas Setup

Common Presets
  • OG Image: 1200×630px
  • Twitter Card: 1200×600px
  • Instagram Post: 1080×1080px
  • Instagram Story: 1080×1920px
Best Practices
  • Keep important content 50px from edges
  • Use solid backgrounds for better readability
  • Limit title text to 60 characters max
  • Test with realistic content

Typography Guidelines

Recommended Font Sizes

  • Main title: 64-96px
  • Subtitle: 32-48px
  • Body text: 24-32px
  • Small text: 18-24px

Font Weights

  • Titles: Bold (700+)
  • Body: Regular/Medium (400-500)
  • Contrast: Ensure WCAG AA minimum

Testing Your Template

  • Use the preview panel in the editor with sample data
  • Test with realistic content (long titles, short titles, edge cases)
  • Try different layer override combinations
  • Check rendering at actual size (not zoomed)

Rate Limits & Usage

Rate limits are based on your subscription plan and reset monthly:

  • Free Plan: 100 generations/month
  • Starter Plan: 1,000 generations/month
  • Pro Plan: 5,000 generations/month
  • Business Plan: Unlimited generations

Note: Cached responses don't count toward your limit. The public /api/render endpoint also doesn't count toward rate limits.

Need Help?

Questions about the API or template creation? Contact our support team