import Link from "next/link"; import { redirect } from "next/navigation"; import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; import { hasProFeatures } from "@/lib/edition"; import { prisma } from "@/lib/db"; import { DashboardShell } from "@/components/DashboardShell"; import { UpgradeProLink } from "@/components/UpgradeProLink"; function CodeBlock({ children }: { children: string }) { return (
      {children}
    
); } export default async function ApiDocsPage() { const session = await getServerSession(authOptions); if (!session?.user?.email) redirect("/"); const user = await prisma.user.findUnique({ where: { email: session.user.email }, include: { youtubeConnection: true }, }); if (!user) redirect("/"); const isPro = hasProFeatures(user.plan); return (
← Back to settings

REST API

Programmatic uploads and batch jobs for Pro subscribers. Generate your API key in{" "} Settings .

{!isPro && (

API access requires Pro.

)}

Authentication

Send your API key on every request. Keys start with s2yt_live_.

{`Authorization: Bearer s2yt_live_your_key_here`}

Rate limits

Default is 60 requests per minute per account. Approved rate-limit extensions increase that ceiling. Check live usage and request an extension in{" "} Settings → API access . Video quota limits from your Pro plan still apply to job creation.

Choosing a flow

Recommended for most jobs (especially 5+ audio files):{" "} two-step: upload each file with POST /api/v1/upload, then create the job with POST /api/v1/jobs (JSON).

One-shot batch{" "} (POST /api/v1/jobs/batch) is for small packs only, typically 1 cover + up to a few audio files. Large multipart bodies often fail with{" "} failed to parse body as FormData. Prefer two-step for albums or long tracklists.

  • Do not set Content-Type manually for multipart; the client must include the boundary.
  • For Postman: Body → form-data, each audio row key must be exactly audio (type File).
  • If a file field shows a warning triangle, re-select the file from disk.

Discovery

{`GET /api/v1`}

Returns endpoint list and requirements (no auth).

1. 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"`}

Response includes path,{" "} filename, and{" "} size. Upload the image once, then each audio file. Keep the{" "} path values for the next step.

2. Create job from paths (recommended)

Use the exact path strings returned by upload. Add one{" "} items[] entry per track.

{`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 Track", "description": "", "tags": "electronic", "privacy": "PUBLIC", "categoryId": "10", "resolution": "1920x1080", "notifySubscribers": true, "madeForKids": false, "embeddable": true, "creativeCommons": false, "includeWatermark": false, "playlistId": null } }] }'`}

YouTube playlists (Pro)

List existing playlists, create a new one, or create one inline when starting a job. Pass playlistId in item metadata / batch{" "} defaults, or use{" "} createPlaylist to make a playlist and attach all videos to it. Privacy may be public,{" "} unlisted, or{" "} private. If playlist permission was just added, sign out and sign in again for youtube.force-ssl.

{`# List playlists curl "$BASE_URL/api/v1/playlists" \\ -H "Authorization: Bearer $API_KEY"`} {`# Create a playlist curl -X POST "$BASE_URL/api/v1/playlists" \\ -H "Authorization: Bearer $API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"title":"My Album","description":"From Songs2YT","privacy":"unlisted"}'`} {`# Use an existing playlist ID in metadata / defaults: { "playlistId": "PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } # Or create one inline with a job / batch request: { "createPlaylist": { "title": "My Album", "description": "Uploaded via Songs2YT", "privacy": "private" }, "defaults": { "privacy": "PUBLIC" }, "items": [{ "title": "Track One" }] }`}

One-shot batch (small packs only)

Upload one cover image and a few audio files in a single multipart request. Not recommended for large batches: use two-step instead if you see FormData parse errors.

{`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={"createPlaylist":{"title":"My Album","privacy":"unlisted"},"defaults":{"privacy":"PUBLIC"},"items":[{"title":"Track One"},{"title":"Track Two"}]}'`}

Optional metadata JSON supports{" "} defaults applied to every item and per-item overrides in{" "} items. Item order should match the order of{" "} audio files.

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"`}
); }