{"openapi":"3.1.0","info":{"title":"3dassets.dev API","version":"1.1.0","description":"Free, open, web-optimised CC0 GLB assets for three.js, Blender, Godot, Unity and any glTF-capable tool. New submissions use CC0 1.0 Universal automatically, with explicit contributor acceptance required. Reads are public; writes use `Authorization: Bearer <api-key>`."},"servers":[{"url":"https://3dassets.dev/api/v1"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Asset":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","enum":["processing","pending","published","rejected","failed","unpublished"]},"url":{"type":"string","format":"uri"},"cdnUrl":{"type":"string","format":"uri","description":"Direct GLB. CORS *, immutable."},"downloadUrl":{"type":"string","format":"uri","description":"Counted 302 to cdnUrl."},"thumbnailUrl":{"type":"string","format":"uri"},"posterUrl":{"type":"string","format":"uri"},"blurhash":{"type":"string"},"category":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}}},"tags":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"}}}},"license":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"attributionRequired":{"type":"boolean"},"attributionText":{"type":"string"}}},"contributor":{"type":"object","properties":{"username":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"}}},"stats":{"type":"object","properties":{"fileSize":{"type":"integer"},"triangles":{"type":"integer"},"vertices":{"type":"integer"},"meshes":{"type":"integer"},"materials":{"type":"integer"},"textures":{"type":"integer"},"animations":{"type":"array","items":{"type":"string"}},"sizeMeters":{"type":"array","items":{"type":"number"},"minItems":3,"maxItems":3},"extensionsUsed":{"type":"array","items":{"type":"string"}}}},"usage":{"type":"object","description":"Ready-to-paste loader code or import steps per tool","properties":{"threejs":{"type":"string"},"r3f":{"type":"string"},"modelViewer":{"type":"string"},"blender":{"type":"string"},"godot":{"type":"string"},"unity":{"type":"string"}}},"aiGenerated":{"type":"boolean","description":"AI helped create the model, code or textures; contributor-reported"},"aiModel":{"type":"string","maxLength":160,"description":"Optional model ID or custom model/tool name, only meaningful when aiGenerated is true; omit if unknown"},"downloads":{"type":"integer"},"publishedAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}},"Submit":{"type":"object","required":["title","summary","category","attestation"],"properties":{"title":{"type":"string","minLength":2,"maxLength":120},"summary":{"type":"string","minLength":10,"maxLength":280},"description":{"type":"string","maxLength":5000,"description":"Markdown"},"category":{"type":"string","description":"slug from /categories"},"license":{"type":"string","const":"cc0-1.0","default":"cc0-1.0","description":"Fixed CC0 1.0 Universal; may be omitted"},"tags":{"type":"array","items":{"type":"string"},"maxItems":12},"sourceUrl":{"type":"string","format":"uri"},"aiGenerated":{"type":"boolean","description":"AI helped create the model, code or textures; contributor-reported"},"aiModel":{"type":"string","maxLength":160,"description":"Optional model ID or custom model/tool name, only meaningful when aiGenerated is true; omit if unknown"},"attestation":{"type":"boolean","const":true,"description":"I confirm that I created this asset or hold the rights to publish it under CC0 1.0 Universal, and agree to dedicate it to the public domain under CC0 so anyone can use, modify and redistribute it for personal or commercial purposes without attribution. I understand this dedication is irrevocable and the asset will be reviewed before publishing."}}},"PackSubmission":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","enum":["submitted","approved","rejected"]},"submittedAt":{"type":"string","format":"date-time"},"packUrl":{"type":"string","format":"uri","description":"Set once approved."},"review":{"type":"object","properties":{"reason":{"type":"string"}}},"assets":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"thumbnailUrl":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"}}}}}},"SubmitPack":{"type":"object","required":["title","summary","assets"],"properties":{"title":{"type":"string","minLength":2,"maxLength":120},"summary":{"type":"string","minLength":10,"maxLength":280},"description":{"type":"string","maxLength":5000,"description":"Markdown"},"assets":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":50,"description":"Slugs of your own assets (processing, pending or published), in display order"}}}},"responses":{"RateLimited":{"description":"Rate limited. Counted per API key, or per IP address when none is sent. Reads 120/min · 3,000/hour, downloads 60/min · 600/hour · 3,000/day, submissions 20/min · 150/hour · 400/day with a key (roughly half without). Honour Retry-After.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"RateLimit-Limit":{"schema":{"type":"integer"}},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window rolls over."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/assets":{"get":{"summary":"Search published assets","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"theme","in":"query","schema":{"type":"string"}},{"name":"style","in":"query","schema":{"type":"string"}},{"name":"contributor","in":"query","schema":{"type":"string"}},{"name":"featured","in":"query","schema":{"type":"string"}},{"name":"sort","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Asset"}},"page":{"type":"integer"},"totalPages":{"type":"integer"},"total":{"type":"integer"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Create an asset from an uploaded quarantine key","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Submit"},{"type":"object","required":["quarantineKey"],"properties":{"quarantineKey":{"type":"string"},"previewKey":{"type":"string"}}}]}}}},"responses":{"202":{"description":"Accepted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/assets/from-url":{"post":{"summary":"Create an asset by fetching a public https URL","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Submit"},{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}}]}}}},"responses":{"202":{"description":"Accepted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/assets/{slug}":{"get":{"summary":"Get one asset (owner/staff may read unpublished)","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"}}}}}},"404":{"description":"Not found"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"summary":"Edit your own asset’s metadata (the uploaded GLB is immutable)","description":"Applied immediately (200) unless the asset is published, in which case the change is queued for review (202) and the live version keeps serving unchanged.","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"sourceUrl":{"type":"string","nullable":true},"aiGenerated":{"type":"boolean"},"aiModel":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Applied","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"}}}}}},"202":{"description":"Queued for review; the published asset is unchanged","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Asset"},"pendingEdit":{"type":"object","properties":{"submittedAt":{"type":"string","format":"date-time"},"changes":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"label":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"}}}}}},"message":{"type":"string"}}}}}},"404":{"description":"Not found or not yours"},"409":{"description":"Still processing"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"summary":"Permanently withdraw your own asset","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"Not found or not yours"},"409":{"description":"Belongs to a curated pack"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/assets/{slug}/edit":{"delete":{"summary":"Withdraw changes you queued for review, keeping the published version","security":[{"bearerAuth":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Withdrawn"},"404":{"description":"Not found or not yours"},"409":{"description":"Nothing was waiting"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/uploads/presign":{"post":{"summary":"Presigned PUT URLs for a .glb (and optional PNG preview)","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["filename","contentLength"],"properties":{"filename":{"type":"string"},"contentLength":{"type":"integer"},"withPreview":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/categories":{"get":{"summary":"List categories","responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/tags":{"get":{"summary":"List tags","responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ai-models":{"get":{"summary":"Search hourly-refreshed OpenRouter model suggestions; custom names also accepted","parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"data: [{id, name}], source, available, refreshIntervalSeconds, customAllowed. available=false means suggestions are temporarily unavailable."},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/licenses":{"get":{"summary":"Get the accepted submission dedication (CC0 1.0 Universal only)","responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/packs":{"get":{"summary":"Find curated game packs with file counts, byte budgets and starter scenes","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"theme","in":"query","schema":{"type":"string"}},{"name":"style","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Published pack summaries with coverUrl, assetCount, totalBytes, totalTriangles and starterScene"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/packs/{slug}":{"get":{"summary":"Get a pack manifest with every published asset, CDN URLs, licences and loader snippets","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pack details with assets as Asset objects and an optional starterScene Asset"},"404":{"description":"No published pack found"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts":{"post":{"summary":"Create a contributor account (emails a 6-digit code)","description":"There are no passwords: a username and an email are all that is needed, and everything afterwards uses emailed codes.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","username"],"properties":{"email":{"type":"string","format":"email"},"username":{"type":"string"},"name":{"type":"string","description":"Optional display name; defaults to the username"},"website":{"type":"string"},"source":{"type":"string","enum":["web","api","mcp"]},"turnstileToken":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"409":{"description":"Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts/verify":{"post":{"summary":"Exchange the emailed code for an API key (shown once) and a session","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","code"],"properties":{"email":{"type":"string"},"code":{"type":"string","pattern":"^\\d{6}$"}}}}}},"responses":{"200":{"description":"OK"},"410":{"description":"Code expired or spent"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts/resend":{"post":{"summary":"Re-send the verification code","responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts/login-code":{"post":{"summary":"Email a 6-digit sign-in code","description":"Always answers 200 with the same body, whether or not the address has an account.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"source":{"type":"string","enum":["web","api","mcp"]},"turnstileToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Sent if the account exists"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/accounts/session":{"post":{"summary":"Exchange a sign-in code for a session cookie","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","code"],"properties":{"email":{"type":"string"},"code":{"type":"string","pattern":"^\\d{6}$"}}}}}},"responses":{"200":{"description":"Signed in; sets the session cookie"},"410":{"description":"Code expired or spent after five wrong guesses"},"422":{"description":"Wrong code"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/me":{"get":{"summary":"Current account","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"summary":"Edit your display name, website or bio","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"website":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/me/assets":{"get":{"summary":"My submissions (any status)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/packs/submissions":{"post":{"summary":"Propose a pack made of your own uploads","description":"Groups 2–50 of your assets. Each model is still reviewed individually; staff approve the pack as a whole, which publishes any members still pending and creates the pack. At most 5 undecided proposals per account.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitPack"}}}},"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackSubmission"}}}},"409":{"description":"Too many open proposals"},"422":{"description":"Assets not yours, not viable, or too few"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/packs/submissions/{id}":{"get":{"summary":"One of your pack proposals with member statuses","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PackSubmission"}}}}}},"404":{"description":"Not found or not yours"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"summary":"Change the text or members while the proposal is still open","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitPack"}}}},"responses":{"200":{"description":"Updated"},"409":{"description":"Already decided"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"summary":"Withdraw an open proposal; the models in it are untouched","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Withdrawn"},"409":{"description":"Already decided"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/me/packs":{"get":{"summary":"My pack proposals (any status)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PackSubmission"}},"total":{"type":"integer"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/reports":{"post":{"summary":"Report an asset","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["asset","reason"],"properties":{"asset":{"type":"string","description":"slug"},"reason":{"type":"string","enum":["stolen","nsfw","broken","other"]},"details":{"type":"string"},"evidenceUrl":{"type":"string"},"email":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}