lowkey viral

API Documentation

Generate short-form 2x2 grid videos and slideshow carousels programmatically. Create content briefs, generate images with AI, and render outputs — all via API. Available on PRO and ULTIMATE plans.

Getting Started

1
Create an API key from your dashboard (requires PRO or ULTIMATE plan)
2
Use the key in the Authorization header
3
Make your first request:
curl -X GET https://lowkeyviral.com/api/v1/account \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Authentication

All API requests require a Bearer token in the Authorization header. API keys start with lkv_sk_.

Authorization: Bearer lkv_sk_...

Rate Limits

PlanLimit
PRO10 requests / minute
ULTIMATE30 requests / minute
Progress polling (all plans)60 requests / minute

When rate limited you will receive a 429 response with a Retry-After header indicating seconds to wait.

Typical Workflow

Grid Video (2x2 grid)

1
Create a briefPOST /api/v1/briefs (AI-generated) or POST /api/v1/briefs/manual (your own content).
2
Generate imagesPOST /api/v1/briefs/:id/generate with your preferred model.
3
Render the videoPOST /api/v1/briefs/:id/render to start Lambda rendering.
4
Poll for completionGET /api/v1/briefs/:id/render/:renderId/progress every 2-3 seconds until status is "done".

Tip: With POST /api/v1/briefs/manual you can combine all steps into one call. Give images a description instead of a url to have them AI-generated, and pass render: true to start rendering right away. See the render parameter for details.

Slideshow (photo carousel)

1
Create a briefPOST /api/v1/briefs with type: "slideshow" (AI-generated) or POST /api/v1/briefs/manual with type: "slideshow".
2
Generate imagesPOST /api/v1/briefs/:id/generate (auto-detects portrait 9:16).
3
Render slideshowPOST /api/v1/briefs/:id/render returns rendered slides immediately (no polling needed).

Tip: Same as grid — POST /api/v1/briefs/manual with render: true can do it all in one call. Slideshow renders are synchronous, so the response includes the finished slides array directly.

Endpoints

POST/api/v1/briefs2 credits

Generate AI content briefs from a business description.

Returns 5 briefs per request for both grid and slideshow types.

Example

curl -X POST https://lowkeyviral.com/api/v1/briefs \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A travel app for Gen-Z backpackers"}'

Response

{
  "briefs": [
    {
      "id": "clxyz...",
      "type": "grid",
      "hook": "pov: your euro trip bucket list is about to be god tier",
      "title": "find these hidden gems and more on WanderApp 🌍✈️",
      "caption_style": null,
      "images": [
        { "id": "...", "position": 0, "title": "Hallstatt", "description": "..." },
        { "id": "...", "position": 1, "title": "Kotor", "description": "..." },
        { "id": "...", "position": 2, "title": "Colmar", "description": "..." },
        { "id": "...", "position": 3, "title": "Sintra", "description": "..." }
      ]
    }
  ]
}

Slideshow Example

curl -X POST https://lowkeyviral.com/api/v1/briefs \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A skincare brand for 20-somethings", "type": "slideshow", "slide_count": 6}'
ParameterTypeRequiredDescription
promptstringyesBusiness description
typestringno"grid" (default) or "slideshow"
slide_countintegerno4-10, only for slideshow type (default: 6)
POST/api/v1/briefs/manual0+ credits

Create a manual content brief with your own images and text.

Example

curl -X POST https://lowkeyviral.com/api/v1/briefs/manual \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "hook": "these coffee shops are insane",
    "title": "Best Coffee Shops",
    "images": [
      { "url": "https://...", "title": "Cafe A", "description": "Cozy vibes" },
      { "url": "https://...", "title": "Cafe B", "description": "Great latte" },
      { "url": "https://...", "title": "Cafe C", "description": "Hidden gem" },
      { "url": "https://...", "title": "Cafe D", "description": "Rooftop" }
    ]
  }'
ParameterTypeRequiredDescription
hookstringyes (grid) / no (slideshow)Text overlay / video text. For slideshows, auto-derived from first slide caption if omitted.
titlestringnoPost caption (defaults to hook)
typestringno"grid" (default) or "slideshow"
caption_stylestringnoSlideshow only: "classic_bold", "background_bar", or "neon_glow"
imagesarrayyesGrid: exactly 4. Slideshow: 2-10.
image_modelstringnoAI model for image generation when images have descriptions but no URLs. One of: z_image_turbo, p_image, flux_2_dev.
renderbooleannoAlso render after creation. See render parameter below.
designstringnoGrid + render: true only. One of: "default", "withCaptions", "noSpaces"
soundtrackstringnoGrid + render: true only. See soundtrack list below.

The render parameter

When render: true, the endpoint triggers rendering after the brief is created (and after image generation, if any images needed to be generated). This is the same as calling POST /api/v1/briefs/:id/render yourself, just bundled into the same request.

For grid briefs: Starts an async Lambda video render. The response includes a render_id — poll GET /api/v1/briefs/:id/render/:renderId/progress every 2-3 seconds until status is "done".

For slideshow briefs: Renders slides synchronously with text overlays. The response includes a slides array with the finished URLs. No polling needed.

Credit cost: +1 render credit on top of whatever else the call costs (image generation, etc.). Image generation credits are only charged for images that need generation (description present, url missing).

render is independent of image generation. You can pass your own image URLs and still use render: true — it will skip image generation and go straight to rendering. Or you can omit render and just have images generated without rendering.

Response

{
  "id": "clxyz...",
  "hook": "these coffee shops are insane",
  "title": "Best Coffee Shops",
  "images": [
    { "id": "...", "position": 0, "title": "Cafe A", "description": "Cozy vibes", "url": "https://...", "rendered_url": null }
  ]
}

When render: true for a grid, the response includes a render_id for polling:

{
  "id": "clxyz...",
  "hook": "...",
  "title": "...",
  "images": [...],
  "render_id": "abc123"
}

When render: true for a slideshow, the response includes a slides array immediately:

{
  "id": "clxyz...",
  "hook": "...",
  "title": "...",
  "images": [...],
  "slides": [
    { "index": 0, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-0.jpg" },
    { "index": 1, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-1.jpg" }
  ]
}
GET/api/v1/briefs0 credits

List all your content briefs.

Query Parameters

ParameterTypeDescription
typestringFilter by type: "grid" or "slideshow". Omit for all.
limitintegerMax results (default 20, max 100)
cursorstringPagination cursor

Invalid type or limit values return 422 validation_error.

Example

curl https://lowkeyviral.com/api/v1/briefs \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Response

{
  "data": [
    {
      "id": "...",
      "hook": "...",
      "title": "...",
      "is_generated": true,
      "video_url": null,
      "images": [...]
    }
  ],
  "has_more": false,
  "next_cursor": null
}
GET/api/v1/briefs/:id0 credits

Get a single content brief by ID.

Example

curl https://lowkeyviral.com/api/v1/briefs/BRIEF_ID \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Response

{
  "id": "clxyz...",
  "type": "slideshow",
  "hook": "...",
  "title": "...",
  "is_generated": true,
  "video_url": null,
  "caption_style": "classic_bold",
  "created_at": "2026-02-12T00:00:00Z",
  "images": [
    { "id": "...", "position": 0, "title": "...", "description": "...", "url": "https://...", "rendered_url": "https://generated.lowkeyviral.com/slideshows/.../slide-0.jpg" }
  ]
}

For slideshow briefs, rendered_url on each image contains the rendered slide with text overlay applied. This field is null until the slideshow is rendered.

DELETE/api/v1/briefs/:id0 credits

Delete a content brief and its associated images.

Example

curl -X DELETE https://lowkeyviral.com/api/v1/briefs/BRIEF_ID \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Response

{ "success": true }
POST/api/v1/briefs/:id/generate4-8+ credits

Generate images for a brief. Pass render: true to also start rendering once images are ready (same behavior as the render parameter on /briefs/manual).

Credits depend on model: z_image_turbo = 4, p_image = 8, flux_2_dev = 8. Add +1 credit if render is true.

For slideshow briefs, images are generated in portrait (9:16) orientation automatically. Credit cost scales with slide count: z_image_turbo = 1 credit/image, p_image = 2 credits/image, flux_2_dev = 2 credits/image.

ParameterTypeRequiredDescription
image_modelstringnoOne of: z_image_turbo, p_image, flux_2_dev. Defaults to your preferred model.
renderbooleannoAlso render after generation. Grid returns render_id; slideshow returns slides.
designstringnoGrid + render: true only. "default", "withCaptions", "noSpaces"
soundtrackstringnoGrid + render: true only. See soundtrack list below

Example

curl -X POST https://lowkeyviral.com/api/v1/briefs/BRIEF_ID/generate \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "image_model": "z_image_turbo",
    "render": true,
    "design": "default",
    "soundtrack": "City Sunshine"
  }'

Response

{
  "id": "clxyz...",
  "hook": "...",
  "title": "...",
  "is_generated": true,
  "video_url": null,
  "created_at": "...",
  "images": [...],
  "render_id": "abc123"
}

When render: true for a slideshow, the response includes rendered slides immediately:

{
  "id": "clxyz...",
  "hook": "...",
  "title": "...",
  "is_generated": true,
  "images": [...],
  "slides": [
    { "index": 0, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-0.jpg" },
    { "index": 1, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-1.jpg" }
  ]
}
POST/api/v1/briefs/:id/render1 credit

Start rendering. For grid briefs, returns a renderId for polling. For slideshow briefs, returns rendered slides immediately.

Grid Example

curl -X POST https://lowkeyviral.com/api/v1/briefs/BRIEF_ID/render \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"design": "default", "soundtrack": "City Sunshine"}'

Grid Response

{ "render_id": "abc123" }

Slideshow Example

curl -X POST https://lowkeyviral.com/api/v1/briefs/BRIEF_ID/render \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"caption_style": "classic_bold"}'

Slideshow Response

{
  "slides": [
    { "index": 0, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-0.jpg" },
    { "index": 1, "url": "https://generated.lowkeyviral.com/slideshows/briefId/slide-1.jpg" }
  ]
}
ParameterTypeApplies toDescription
designstringGrid only"default", "withCaptions", "noSpaces"
soundtrackstringGrid onlySee soundtrack list below
caption_stylestringSlideshow only"classic_bold", "background_bar", "neon_glow"
GET/api/v1/briefs/:id/render/:renderId/progress0 credits

Poll render progress. Call every 2-3 seconds.

Note: This endpoint is for grid briefs only. Slideshow renders are synchronous and return immediately from the render endpoint. Calling this on a slideshow brief returns 422.

Type values: "progress", "done", "error". Poll every 2-3 seconds.

Example

curl https://lowkeyviral.com/api/v1/briefs/BRIEF_ID/render/RENDER_ID/progress \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Responses

In progress:

{
  "type": "progress",
  "progress": 0.45,
  "started_at": "2026-02-12T00:00:00.000Z",
  "elapsed_seconds": 32,
  "stalled": false
}

stalled is true when progress has not changed for an extended period, typically during Lambda cold starts. The server will automatically return type: "error" if the render times out.

Completed:

{
  "type": "done",
  "url": "https://s3.us-east-1.amazonaws.com/.../out.mp4",
  "size": 1234567
}

Error:

{
  "type": "error",
  "message": "Render timed out. The Lambda function did not complete in time."
}
POST/api/v1/uploads0 credits

Get a presigned URL to upload a custom image.

PUT your image file to the upload_url with the matching Content-Type header. Max 10 MB.

Supported content_type values: image/jpeg, image/png, image/webp.

Example

curl -X POST https://lowkeyviral.com/api/v1/uploads \
  -H "Authorization: Bearer lkv_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"content_type": "image/jpeg"}'

Response

{
  "upload_url": "https://...",
  "file_url": "https://generated.lowkeyviral.com/...",
  "content_type": "image/jpeg",
  "max_size": 10485760
}
GET/api/v1/account0 credits

Get your account info including credits and plan type.

Example

curl https://lowkeyviral.com/api/v1/account \
  -H "Authorization: Bearer lkv_sk_your_key_here"

Response

{
  "credits": 42,
  "plan_type": "PRO",
  "next_reset_date": "2026-03-01T00:00:00Z"
}

Brief Fields

FieldDescription
typeBrief type: "grid" or "slideshow"
hookShort text rendered in the video (grid) or derived from first slide caption (slideshow). Max 80 chars.
titlePost caption for socials (not shown in video/slides)
caption_styleSlideshow only: text overlay style ("classic_bold", "background_bar", "neon_glow")
images[].titlePer-image caption label
images[].descriptionImage generation prompt (not shown in output)
images[].rendered_urlSlideshow only: rendered slide URL with text overlay applied (null until rendered)

Valid Option Values

Designs

default, withCaptions, noSpaces

Image Models

ModelCreditsNotes
z_image_turbo1 credit/imageFastest, good quality
p_image2 credits/imageHigh quality
flux_2_dev2 credits/imageHigh quality, detailed

Total image-generation cost = per-image cost × number of images/slides.

Caption Styles (Slideshow)

StyleDescription
classic_boldWhite text with black outline stroke
background_barWhite text on semi-transparent dark background
neon_glowBright green (#00ff88) text with glow effect

Soundtracks

Advertime, And Just Like That, Blippy Trance, Brewing Potions, City Sunshine, Funshine, Happy Whistling Ukulele, I Guess What I'm Trying to Say, La Citadelle, Lukewarm Banjo, Magical Transition, Martini Sunset, Meditating Beat, Night in Venice, River Meditation, Soundtrack From the Starcourt Mall, Strength of the Titans, Study and Relax, Sun Up Gunned Down, The Celebrated Minuet

Credit Costs

OperationEndpointGridSlideshow
Generate AI briefsPOST /api/v1/briefs2 (5 briefs)2 (5 briefs)
Create manual briefPOST /api/v1/briefs/manual00
Generate images (z_image_turbo)POST /api/v1/briefs/:id/generate4 (4 x 1)1 per image
Generate images (p_image)POST /api/v1/briefs/:id/generate8 (4 x 2)2 per image
Generate images (flux_2_dev)POST /api/v1/briefs/:id/generate8 (4 x 2)2 per image
RenderPOST /api/v1/briefs/:id/render11
All other endpointsGET / DELETE00

Error Codes

All errors return a consistent format:

{
  "error": {
    "code": "error_code",
    "message": "Human-readable description"
  }
}
HTTP StatusCodeDescription
401unauthorizedInvalid or missing API key
403forbiddenAPI keys require a PRO or ULTIMATE plan
402insufficient_creditsNot enough credits for this operation
422validation_errorInvalid request body or parameters
404not_foundResource not found
429rate_limitedToo many requests
500internal_errorUnexpected server error

Need help? Contact support or check our FAQ.