import { NextResponse } from "next/server"; import { COMPOSITION_FAMILIES, LAYOUT_TEMPLATE_LABELS, LAYOUT_TEMPLATES, } from "@/lib/layout"; import { API_DOCS_URL } from "@/lib/plans"; export async function GET() { return NextResponse.json({ name: "Songs2VID API", version: "1.0", authentication: "Authorization: Bearer ", requirements: ["YouTube account connected"], rateLimit: "100,000 requests per minute per account", billing: false, notes: "OSS self-hosted: full entitlements, no Stripe/credits/paywall. In-repo docs: docs/api/", webhooks: "Optional webhookUrl on job create — HTTPS POST JSON on item/job terminal states for n8n", guidance: { recommended: "For most jobs (especially 5+ audio files): POST /api/v1/upload per file, then POST /api/v1/render (or /api/v1/jobs) with paths + optional webhookUrl", batch: "POST /api/v1/jobs/batch is for small packs only. Large multipart bodies may fail with 'failed to parse body as FormData'", polling: "GET /api/v1/jobs/:id until status is COMPLETED, FAILED, or PARTIAL", }, layoutTemplates: LAYOUT_TEMPLATES.map((id) => ({ id, label: LAYOUT_TEMPLATE_LABELS[id], })), compositionFamilies: COMPOSITION_FAMILIES.map((family) => ({ id: family.id, label: family.label, defaultTemplate: family.defaultTemplate, variants: family.variants.map((id) => ({ id, label: LAYOUT_TEMPLATE_LABELS[id], })), })), endpoints: [ { method: "POST", path: "/api/v1/upload", description: "Upload image, audio, PNG logo, or .ttf/.otf font (font ≤10MB)", body: "multipart/form-data: file, type (image|audio|logo|font)", }, { method: "POST", path: "/api/v1/render", description: "Alias of /api/v1/jobs — create a render job (n8n-friendly). Optional webhookUrl for callbacks.", body: "application/json: { imagePath, webhookUrl?, items[{ audioPath, audioFilename, metadata }] }", }, { method: "POST", path: "/api/v1/jobs", description: "Create a video job from uploaded file paths with layouts, watermark, and per-item covers", body: "application/json: { imagePath, webhookUrl?, items[{ audioPath, audioFilename, metadata }] }", }, { method: "POST", path: "/api/v1/jobs/batch", description: "One-shot batch for small packs only; large uploads may fail FormData parsing; prefer upload + jobs", body: "multipart/form-data: image, audio[] (repeatable), metadata? (JSON string)", }, { method: "GET", path: "/api/v1/playlists", description: "List YouTube playlists for the authenticated account", }, { method: "POST", path: "/api/v1/playlists", description: "Create a YouTube playlist", body: "application/json: { title, description?, privacy? (public|unlisted|private) }", }, { method: "GET", path: "/api/v1/jobs", description: "List recent jobs (also available as GET /api/v1/render)", query: "limit (default 20, max 100)", }, { method: "GET", path: "/api/v1/jobs/:id", description: "Get job status and item details (poll for n8n)", }, ], docs: API_DOCS_URL, }); }