How to send Woolf assets (file attachments)

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