DocsQuickstart

Quickstart

Generate your first personalized video in 5 minutes. This guide walks through creating a render, polling for completion, and downloading the video.

Prerequisites

  • • A Significant Figures account (Studio tier or above for API access)
  • • An API key — create one in your dashboard
  • • curl, Python 3, or Node.js installed

1Get Your API Key

Create an API key in your dashboard settings. Choose the render-batch preset for full render access.

Example API key
sf_live_a1b2c3d4e5f6789...

# Copy and save this — it won't be shown again!

Security: Never commit API keys to version control. Use environment variables or secret managers.

2Make Your First Render Request

Let's create a video using the Emeritus template (academic research portrait). This template auto-fetches data from OpenAlex — you just need an author ID.

Using curl

Terminal
curl -X POST https://app.sigfigsstudio.com/api/render \
  -H "Content-Type: application/json" \
  -H "X-API-Key: sf_live_YOUR_KEY_HERE" \
  -d '{
    "templateId": "emeritus",
    "data": {
      "authorId": "A5001825849"
    },
    "brand": {
      "accentColor": "#14b8a6"
    },
    "audio": {
      "includeVoiceover": true,
      "voiceId": "en-GB-RyanNeural"
    }
  }'

Using Python

render.py
import requests
import os

API_KEY = os.environ["SIGFIGS_API_KEY"]
BASE_URL = "https://app.sigfigsstudio.com/api"

# Create render job
response = requests.post(
    f"{BASE_URL}/render",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": API_KEY,
    },
    json={
        "templateId": "emeritus",
        "data": {
            "authorId": "A5001825849"
        },
        "brand": {
            "accentColor": "#14b8a6"
        },
        "audio": {
            "includeVoiceover": True,
            "voiceId": "en-GB-RyanNeural"
        }
    }
)

result = response.json()
print(f"Job created: {result['jobId']}")
print(f"Credits remaining: {result['creditsRemaining']}")

Using Node.js

render.js
const API_KEY = process.env.SIGFIGS_API_KEY;
const BASE_URL = "https://app.sigfigsstudio.com/api";

const response = await fetch(`${BASE_URL}/render`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": API_KEY,
  },
  body: JSON.stringify({
    templateId: "emeritus",
    data: {
      authorId: "A5001825849"
    },
    brand: {
      accentColor: "#14b8a6"
    },
    audio: {
      includeVoiceover: true,
      voiceId: "en-GB-RyanNeural"
    }
  }),
});

const result = await response.json();
console.log(`Job created: ${result.jobId}`);
console.log(`Credits remaining: ${result.creditsRemaining}`);

Response

201 Created
{
  "success": true,
  "jobId": "78008b5b-4207-4b2e-a1c5-9b923f519d4c",
  "status": "pending",
  "templateId": "emeritus",
  "displayName": "Dr. Jane Smith",
  "creditsRemaining": 97,
  "message": "Render job created. Poll GET /api/render/[jobId] for status."
}

Save the jobId — you'll use it to check render status.

3Poll for Completion

Videos typically take 30-120 seconds to render. Poll GET /api/render/:id until status is "complete".

Using curl

Terminal
curl -H "X-API-Key: sf_live_YOUR_KEY_HERE" \
  https://app.sigfigsstudio.com/api/render/78008b5b-4207-4b2e-a1c5-9b923f519d4c

Using Python (with polling loop)

poll.py
import requests
import time
import os

API_KEY = os.environ["SIGFIGS_API_KEY"]
BASE_URL = "https://app.sigfigsstudio.com/api"
JOB_ID = "78008b5b-4207-4b2e-a1c5-9b923f519d4c"

while True:
    response = requests.get(
        f"{BASE_URL}/render/{JOB_ID}",
        headers={"X-API-Key": API_KEY}
    )
    
    data = response.json()
    status = data["job"]["status"]
    
    print(f"Status: {status}")
    
    if status == "complete":
        print(f"✓ Video ready: {data['job']['outputUrl']}")
        break
    elif status == "failed":
        print(f"✗ Render failed: {data['job'].get('error')}")
        break
    
    time.sleep(5)  # Poll every 5 seconds

Using Node.js (with polling loop)

poll.js
const API_KEY = process.env.SIGFIGS_API_KEY;
const BASE_URL = "https://app.sigfigsstudio.com/api";
const JOB_ID = "78008b5b-4207-4b2e-a1c5-9b923f519d4c";

const poll = setInterval(async () => {
  const response = await fetch(`${BASE_URL}/render/${JOB_ID}`, {
    headers: { "X-API-Key": API_KEY }
  });
  
  const data = await response.json();
  const status = data.job.status;
  
  console.log(`Status: ${status}`);
  
  if (status === "complete") {
    clearInterval(poll);
    console.log(`✓ Video ready: ${data.job.outputUrl}`);
  } else if (status === "failed") {
    clearInterval(poll);
    console.log(`✗ Render failed: ${data.job.error}`);
  }
}, 5000); // Poll every 5 seconds

Response (complete)

200 OK
{
  "success": true,
  "job": {
    "id": "78008b5b-4207-4b2e-a1c5-9b923f519d4c",
    "status": "complete",
    "outputUrl": "https://skkroo2x4wm2v7c8.public.blob.vercel-storage.com/emeritus/78008b5b.mp4",
    "authorName": "Dr. Jane Smith",
    "createdAt": "2026-03-19T19:18:53.849Z",
    "completedAt": "2026-03-19T19:19:20.614Z"
  }
}

4Download Your Video

The outputUrl is publicly accessible. Download it with curl, wget, or any HTTP client.

Terminal
curl -O https://skkroo2x4wm2v7c8.public.blob.vercel-storage.com/emeritus/78008b5b.mp4

# Or using wget
wget https://skkroo2x4wm2v7c8.public.blob.vercel-storage.com/emeritus/78008b5b.mp4
Python
import requests

video_url = "https://skkroo2x4wm2v7c8.public.blob.vercel-storage.com/emeritus/78008b5b.mp4"
response = requests.get(video_url)

with open("output.mp4", "wb") as f:
    f.write(response.content)
    
print("✓ Video downloaded: output.mp4")

Video URLs are permanent — they don't expire. You can embed them directly or download and re-host.

Next Steps

Tips & Best Practices

Use Environment Variables for API Keys

Never hardcode keys in your source code. Use process.env or os.environ.

Poll Responsibly

Poll every 5-10 seconds, not every second. Rate limit is 120 req/min for GET /render/:id.

Handle Errors Gracefully

Check for status === "failed" in polling loops. The error field contains details.

Monitor Credit Usage

The render response includes creditsRemaining. Track this to avoid running out mid-campaign.

Questions?

Check the full API reference or reach out to support.