Bulk upload of student activities
This guide explains how to bulk upload student activities (grades, feedback, submissions, and content consumption) using the bulk upload API.
Overview
The bulk upload flow is asynchronous and file-based:
Request an upload session
Receive a jobId and uploadUrl
Upload an NDJSON file with activity records
Track results using the jobId via API or webhook
Step 1: Request upload session
Call the bulkUploadActivity API.
Request
No input required.
Response
//request { "query": "mutation { bulkUploadActivity}" } //response { "data": { "bulkUploadActivity": { "jobId": "bf9003b3-a943-475f-92ff-7c44dd344282", "uploadUrl": "https://storage.googleapis.com/woolf-local-filestore/bulk-upload/bf9003b3-a943-475f-92ff-7c44dd344282/bulk-activity-import-d30354b1-1f0f-4845-b8a9-8bfe57966ec4-2025-10-13T07-09-27-715Z.ndjson?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=stackdriver-exporter%40graphic-fiber-237613.iam.gserviceaccount.com%2F20251013%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20251013T070939Z&X-Goog-Expires=7200&X-Goog-SignedHeaders=content-disposition%3Bcontent-type%3Bhost%3Bx-goog-meta-name%3Bx-goog-meta-type&X-Goog-Signature=9e50b8597a1c4aeb83ebfcbf24b465f25f9c8ef65f0db24679b1937a6718d6ef9edca36460186eec982184b1017bec4c6aeda6b3e308acacca92a5918e872f5fd326ce8b5621fa0a6c71f429ac32305c99dfc7373eb179adf7b9f7e664f71ac0688caa6b97be191765eec917e272b2d7f759c7428f1c8ea6756f6113e96374fd5bfbd327e76db29f69d5b192b52b62da87f8adb7fcca2a2c3144b8a850aabe6c2759d380097c094f908e4f4ed4f124bdb91079f6362914146480ba02f6ae40fb52d82fa1d32775f4d67a0a9f7951bb587ac75ddc5e3aec1c36f61d9b3425352743f6e23263a6383ac5bd9d25a1cb5b83648a56a23bf259aa3284dbc88e7c5522", "headers": { "Content-Disposition": "inline; filename=\"bulk-activity-import-d30354b1-1f0f-4845-b8a9-8bfe57966ec4-2025-10-13T07-09-27-715Z.ndjson\"", "x-goog-meta-name": "bulk-activity-import-d30354b1-1f0f-4845-b8a9-8bfe57966ec4-2025-10-13T07-09-27-715Z.ndjson", "Content-Type": "application/x-ndjson", "x-goog-meta-type": "application/x-ndjson" } } } }
What to do next
Store the jobId on your side — this is required to track results via API or webhook
Use the uploadUrl to upload your file
Step 2: Prepare your NDJSON file
File requirements
Format: NDJSON (Newline Delimited JSON)
Max file size: 20 MB
Each line = one activity record
No enclosing array — each JSON object must be on a separate line
NDJSON structure
Each line must follow this structure:
{ "mutationType": "Grade" | "Feedback" | "Submission" | "Consumption", "payload": { ... } }
Unified payload schema
// ndjson row input schema { mutationType: "Grade" | "Feedback" | "Submission" | "Consumption", payload: AddGradeInput | AddFeedBackInput | AddSubmissionInput | AddConsumptionInput } // AddGradeInput { resourceId: String studentId: String! teacherId: String weightId: ID value: Float! assets: [{ importUrl: String }] // url to asset that Woolf can upload evidenceAssets: [{ importUrl: String }] // url to asset that Woolf can upload } // AddFeedBackInput { resourceId: String studentId: String! teacherId: String content: String assets: [{ importUrl: String }] evidenceAssets: [{ importUrl: String }] } // AddSubmissionInput { resourceId: String studentId: String! content: String assets: [{ importUrl: String }] evidenceAssets: [{ importUrl: String }] } // AddConsumptionInput { studentId: String resourceId: String createdAt: Date evidenceAssets: [{ importUrl: String }] assets: [{ importUrl: String }] }
Step 3: Upload file
Upload to uploadUrl.
Step 4: Results
Processing is asynchronous
Use jobId to track the upload
You can get results in two ways:
query the job status using API jobDetails(jobId: String!)
subscribe to webhook events and receive notifications automatically
The jobId returned by bulkUploadActivity must be stored on your side. It is the identifier used to check the upload result later.
Query upload results
Use the jobDetails API to check the status and result of a bulk upload job.
API
jobDetails(jobId: String!): JobDetails!
Receive results by webhook
If you do not want to repeatedly call the query API, you can subscribe to webhook events and receive notifications when the job finishes processing.
Learn how to manage webhooks here.
Recommended approach
Recommended flow for bulk upload results:
Call bulkUploadActivity
Store the returned jobId
Upload the NDJSON file to uploadUrl
Subscribe to webhook notifications if you want automatic updates
Optionally call jobDetails(jobId) to check progress or confirm final results