pethalvoid · remotion

api-renderer

Backend-only image/video render API for n8n. Auth with process.env.API_KEY via the x-api-key header.

Auth

Every /render/* request must include your server API_KEY. Keys are hashed and stored in SQLite (data/renderer.db).

x-api-key: <process.env.API_KEY>

# or
Authorization: Bearer <process.env.API_KEY>

Endpoints

GET /health

Public health check. No auth.

POST /render/carousel

Renders each slide to PNG 1080×1080. Returns public URLs (auto-deleted after 1h).

{
  "slides": [ /* hook | point | data | cta */ ],
  "theme": "dark",
  "handle": "@yafizhambb"
}

→ { "urls": ["https://…/output/{jobId}/slide-1.png"], "jobId": "…" }
POST /render/video

Renders all slides into one MP4. Optional durationPerSlide (frames, default 90).

{
  "slides": [ … ],
  "theme": "dark",
  "handle": "@yafizhambb",
  "durationPerSlide": 90
}

→ { "url": "https://…/output/{jobId}/video.mp4", "jobId": "…" }

curl

export API_KEY="your-key-from-server-env"
export BASE="https://api-renderer.pethalvoid.com"

curl -s "$BASE/render/carousel" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $API_KEY" \
  -d '{
    "handle": "@yafizhambb",
    "theme": "dark",
    "slides": [
      { "type": "hook", "slideNumber": 1, "heading": "Stop guessing what works" },
      { "type": "point", "slideNumber": 2, "heading": "Focus on communities", "body": "Most leads come from forums." },
      { "type": "data", "slideNumber": 3, "heading": "Where leads come from",
        "chartData": [
          { "label": "Communities & Forums", "value": 48 },
          { "label": "Cold DM LinkedIn/X", "value": 17 }
        ]
      },
      { "type": "cta", "slideNumber": 4, "heading": "Follow for more", "body": "Weekly breakdowns." }
    ]
  }'

n8n

  1. HTTP Request node → Method POST
  2. URL https://api-renderer.pethalvoid.com/render/carousel (or /render/video)
  3. Header x-api-key = {{$env.API_KEY}} (or your n8n credential)
  4. Body → JSON with slides, handle, theme

Slide shape

{
  "type": "hook" | "point" | "data" | "cta",
  "slideNumber": 1,
  "heading": "...",
  "body": "...",            // point, cta
  "chartData": [            // data only
    { "label": "Communities & Forums", "value": 48 }
  ]
}