Upload API
SellersREST endpoints for sellers to create listings and upload ZIPs programmatically. Anyone can read this page; calling the API requires a logged-in seller or admin.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/templates | List mine |
| POST | /api/v1/templates | Create draft |
| POST | /api/v1/templates/:id/package | One-shot ZIP upload |
| POST | /api/v1/templates/:id/upload-url | Presigned PUT |
| POST | /api/v1/templates/:id/versions | Register after PUT |
| POST | /api/v1/templates/:id/submit | Submit for review |
Auth
Use the same Clerk session cookie as the website (browser credentials: "include"). Unauthenticated → 401. Not a seller → 403.
Create a seller profile once at /seller.
One-shot upload (recommended)
# 1) Create draft
curl -X POST "$BASE/api/v1/templates" \
-H "Content-Type: application/json" \
-H "Cookie: ..." \
-d '{
"title": "My Kit",
"slug": "my-kit",
"description": "…",
"priceCents": 2900
}'
# 2) Upload package
curl -X POST "$BASE/api/v1/templates/TEMPLATE_ID/package" \
-H "Cookie: ..." \
-F "file=@./template.zip;type=application/zip" \
-F "version=1.0.0" \
-F "changelog=Initial"Invalid Remotion packages return 422 PACKAGE_REJECTED with a readable error list. A failed upload does not replace a good version.
Presigned flow
POST …/upload-urlwith{ "version": "1.0.0" }PUTthe ZIP touploadUrlPOST …/versionswithstorageKey,checksumSha256,sizeBytes
Browser snippet
async function uploadPackage(templateId, file, version = "1.0.0") {
const body = new FormData();
body.append("file", file);
body.append("version", version);
const res = await fetch(`/api/v1/templates/${templateId}/package`, {
method: "POST",
body,
credentials: "include",
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || res.statusText);
return data;
}Limits
- Max ZIP: ~200MB (configurable server-side)
- Production requires object storage (R2/S3)
- Same packaging rules as the dashboard