Files
Atakan Doğan Özban 848607f9e0 Add lower-corner layouts, custom blur backgrounds, and classic blur fill.
Ship composition families, optional background images for lower-corner templates, and an optional blurred cover fill for classic letterbox.
2026-08-07 00:51:37 +02:00

10 KiB
Raw Permalink Blame History

Endpoints

Set these for the examples below:

export BASE_URL="http://localhost:3000"          # local / self-hosted app
export API_KEY="s2yt_live_your_key_here"

Live HTML docs: docs.songs2vid.com/docs/api/endpoints.

Discovery

curl "$BASE_URL/api/v1"

Returns the endpoint list and requirements (no auth). No billing routes are listed or implemented.

Upload a file (two-step)

curl -X POST "$BASE_URL/api/v1/upload" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@cover.jpg" \
  -F "type=image"
curl -X POST "$BASE_URL/api/v1/upload" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@track1.mp3" \
  -F "type=audio"
# Optional: PNG watermark logo
curl -X POST "$BASE_URL/api/v1/upload" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@logo.png" \
  -F "type=logo"
# Optional: custom font (.ttf / .otf, max 10 MB)
curl -X POST "$BASE_URL/api/v1/upload" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@Brand.ttf" \
  -F "type=font"

Request fields

Field Required Notes
file Yes Multipart file
type Yes image | audio | logo | font

Allowed files

type Formats Max size
image JPEG, PNG, WebP, GIF 500 MB
audio MP3, WAV, FLAC 500 MB
logo PNG only 500 MB
font .ttf / .otf 10 MB

Response

{
  "path": "/uploads/.../track.mp3",
  "filename": "track.mp3",
  "size": 4123456,
  "audioTags": {
    "title": "Song Title",
    "artist": "Artist Name",
    "album": "Album",
    "genre": "Electronic",
    "year": "2024"
  }
}

audioTags is present for MP3 when tags are readable; otherwise null.

Self-hosted unlocks per-track covers, custom watermarks/fonts, and art-track layouts. Max batch size: 100. Watermarks are optional — nothing forces the default Songs2VID badge.

curl -X POST "$BASE_URL/api/v1/jobs" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "imagePath": "/uploads/.../cover.jpg",
    "items": [{
      "audioPath": "/uploads/.../track.mp3",
      "audioFilename": "track.mp3",
      "metadata": {
        "title": "My Artist - My Track (Official Audio)",
        "songTitle": "My Track",
        "artist": "My Artist",
        "description": "",
        "tags": "electronic",
        "privacy": "PUBLIC",
        "categoryId": "10",
        "resolution": "1920x1080",
        "notifySubscribers": true,
        "madeForKids": false,
        "embeddable": true,
        "creativeCommons": false,
        "includeWatermark": true,
        "layout": {
          "template": "LOWER_LEFT_COVER_TEXT",
          "blurAmount": 60,
          "blurOpacity": 85,
          "textPadding": 48,
          "titleArtistGap": 12,
          "titleBold": true,
          "textOffsetX": 0,
          "textOffsetY": 0
        },
        "watermark": {
          "mode": "default",
          "fontKey": "montserrat",
          "position": "bottom-right",
          "offsetX": 24,
          "offsetY": 24
        },
        "playlistId": null
      }
    }]
  }'

Success response

{
  "jobId": "clxxxxxxxx",
  "itemCount": 1,
  "status": "PENDING",
  "playlist": null
}

Metadata fields

Field Type Notes
title string YouTube video title
songTitle string | null On-video song title for art-track (max 120)
artist string | null On-video artist line (max 80)
description string YouTube description
tags string Comma-separated
privacy string PUBLIC | PRIVATE | UNLISTED
categoryId string YouTube category ID
resolution string See resolutions below
notifySubscribers boolean YouTube notify flag
madeForKids boolean Made for kids
embeddable boolean Allow embedding
creativeCommons boolean CC vs standard YouTube license
includeWatermark boolean Apply watermark settings
imagePath string | null Per-track cover
backgroundImagePath string | null Lower-corner templates only: separate blur-fill image (else cover is blurred)
playlistId string | null Existing playlist ID
layout object Art-track layout
watermark object Watermark settings

Snake_case aliases are accepted for layout/watermark fields.

Resolutions

Value Aspect
1920x1080 16:9
1280x720 16:9
854x480 16:9
720x720 1:1
640x360 16:9
426x240 16:9

YouTube categories

ID Name
1 Film & Animation
2 Autos & Vehicles
10 Music
15 Pets & Animals
17 Sports
19 Travel & Events
20 Gaming
22 People & Blogs
23 Comedy
24 Entertainment
25 News & Politics
26 Howto & Style
27 Education
28 Science & Technology
29 Nonprofits & Activism

Watermark fields

watermark.mode: none | default | text | logo

  • none — no overlay
  • default — built-in Songs2VID badge PNG (assets/watermark.png)
  • logo — requires prior type=logo upload; set logoPath
  • text — custom string (max 80); set text

watermark.position: top-left | top-right | bottom-left | bottom-right | center

watermark.offsetX / offsetY: 0200 (default 20)

watermark.fontKey: system | inter | montserrat | roboto | oswald | playfair | custom (styles art-track text and text watermarks)

Art-track layouts

metadata.layout.template (or flat layout_template / layoutTemplate). Valid enums are also listed on GET /api/v1 as layoutTemplates. Mirrored pairs used by the Layout Studio composition grid are listed under compositionFamilies (side: cover beside text; lower: lower corner).

Enum Description
COVER_LEFT_TEXT_RIGHT Cover left, title & artist right
COVER_TOP_TEXT_BOTTOM Cover top, title & artist below
COVER_RIGHT_TEXT_LEFT Cover right, title & artist left
CENTERED_COMPACT Centered cover + text stack
LOWER_LEFT_COVER_TEXT Lower-left cover; textPadding is equal left + bottom inset (diagonal from frame corner) with title/artist to the right
LOWER_RIGHT_COVER_TEXT Lower-right cover; textPadding is equal right + bottom inset (diagonal from frame corner) with title/artist to the left

For lower-corner templates only, optional metadata.backgroundImagePath (or background_image_path) sets a separate full-frame blur fill. Upload with type=image first, then pass the returned path. The cover (imagePath / per-item metadata.imagePath) stays the sharp corner square. Omit the field to blur the cover itself (default). blurAmount / blurOpacity still apply to whichever image is used as the fill.

Optional fine-tuning (clamped; camelCase or snake_case):

Field Range Default Purpose
blurAmount / blur_amount 0100 55 Background boxblur intensity
blurOpacity / blur_opacity 0100 100 Blurred fill vs black
blurFill / blur_fill boolean false Classic letterbox only: fill bars with blurred cover (ignored for art-track templates)
textPadding / text_padding 16120 48 Edge inset for cover/text. On lower-corner templates this value is applied equally on both axes (left=bottom or right=bottom) so the cover corner sits on a true diagonal from the frame corner
titleArtistGap / title_artist_gap 064 10 Space between title and artist
titleBold / title_bold boolean true Bold song title (preview + FFmpeg)
textOffsetX / text_offset_x 120120 0 Shift text block horizontally
textOffsetY / text_offset_y 120120 0 Shift text block vertically

Also set metadata.songTitle (max 120) and metadata.artist (max 80) for the on-video text lines. metadata.title remains the YouTube title.

Omit layout.template for classic letterbox (black-padded cover by default). Set layout.blurFill / blur_fill to true to fill letterbox bars with a blurred cover; then blurAmount / blurOpacity apply. Free-form cover coordinates (x, y, coverX, …) and layout-level offsetX/offsetY are rejected.

Invalid template strings return 400:

{ "error": "Invalid layout template. Refer to API documentation for valid enum values." }

YouTube playlists

curl "$BASE_URL/api/v1/playlists" \
  -H "Authorization: Bearer $API_KEY"
curl -X POST "$BASE_URL/api/v1/playlists" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"My Album","description":"From Songs2VID","privacy":"unlisted"}'

Or pass createPlaylist on a job / batch body to create a playlist and attach all videos.

One-shot batch (small packs only)

curl -X POST "$BASE_URL/api/v1/jobs/batch" \
  -H "Authorization: Bearer $API_KEY" \
  -F "image=@cover.jpg" \
  -F "audio=@track1.mp3" \
  -F "audio=@track2.mp3" \
  -F 'metadata={"defaults":{"privacy":"PUBLIC"},"items":[{"title":"Track One"},{"title":"Track Two"}]}'

Prefer two-step upload + jobs for larger packs.

Poll job status

curl "$BASE_URL/api/v1/jobs/JOB_ID" \
  -H "Authorization: Bearer $API_KEY"
curl "$BASE_URL/api/v1/jobs?limit=10" \
  -H "Authorization: Bearer $API_KEY"

GET /api/v1/jobs accepts limit (default 20, max 100).

Job statuses

Status Meaning
PENDING Queued
PROCESSING Encoding or uploading
COMPLETED All items succeeded
FAILED All items failed
PARTIAL Mix of completed and failed

Item statuses

Status Meaning
PENDING Waiting
ENCODING FFmpeg building video
UPLOADING Uploading to YouTube
COMPLETED Live (youtubeVideoId set)
FAILED Failed (error message)

YouTube channel daily upload caps are enforced by Google, not Songs2VID.

HTTP errors

Status When
400 Validation error
401 Missing or invalid API key
403 YouTube not connected, or request not allowed
404 Job not found
429 API rate limit exceeded

There is no 402 payment / credits status in OSS.