How to submit assets as file attachments in resources
In this article
In this article group
- Inviting Students to a Degree using API
- Tracking Activities in LMS with Airlock SDK
- Understanding Activity Events
- Resources API Guide
- Grade Management using API
- How to Add Students?
- Changing Email Addresses for Integrated Colleges
- What does the Degree Application Process Look like for a Student?
- Manage webhook subscriptions
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