How to submit assets as file attachments in resources
Use assets when you need to attach files (PDFs, images, videos, spreadsheets, etc.) to an entity (resource, student submission, teacher feedback).
Text still goes in content (HTML/Markdown). Files go in assets.
Assets Field Basics
All relevant create/update mutations accept:
assets: [AssetInput!]
assets is always an array.
Even if you attach a single file, you must still pass an array with one item.
Two Supported Ways to Send Assets
Option A: Import by URL (Woolf downloads the file)
Use this when your file is already hosted somewhere reachable via URL and you want Woolf to download it.
Send assets with:
importUrl — required (HTTP(S); or M3U8 / GitHub URL for special handling)
contentType — optional
fileName — optional
Example:
assets: [ { importUrl: "https://example.com/final-report.pdf" }, { importUrl: "https://example.com/supporting-data.xlsx" } ]
Requirements:
URLs must be accessible for download (public or shared with download permissions)
Direct download URLs (not pages that require login or require clicking a download button)
Option B: Direct Upload (client uploads file to Woolf storage)
Use this when you want Woolf to provide upload instructions (upload URL + required headers), and you upload the file bytes directly to Woolf’s bucket/storage.
AssetInput (direct upload):
contentType — required (example: "image/png", "application/pdf")
fileName — optional
importUrl — must be omitted or null
Example (requesting upload instructions for 2 files):
assets: [ { contentType: "application/pdf", fileName: "Final_Report.pdf" }, { contentType: "image/png", fileName: "Screenshot.png" } ]
What the API returns:
assets: [AssetUpload!]!
In the mutation response, you will receive an array of AssetUpload objects.
Each AssetUpload includes:
uploadUrl: String (where to upload the file bytes)
headers: Json (headers you must include in the upload request)
Upload step (important):
You upload each file to its uploadUrl
You must include the returned headers (these are required to upload to the bucket)
One AssetUpload = one file upload
Key rule: The number of objects in assets that you send in the mutation equals the number of upload URLs you receive back.
If you need 5 upload URLs, send 5 AssetInput items (each with contentType).
Common Mistakes to Avoid
Passing assets as a single object instead of an array
Direct upload flow: forgetting contentType (required)
Direct upload flow: sending importUrl (must be omitted or null)
Uploading without the required headers returned by the API (these are required to upload to the bucket)
Import flow: using URLs that are not actually downloadable