@matt_price
The file submission lives at the quiz question level, but you are fetching information about the entire quiz with either of those endpoints. That means that it doesn't have the level of detail needed to get you the answer you want.
The quiz questions API allows you to fetch the information about the quiz question, but does not provide information about what the student answered, just about the question in the first place.
The quiz submissions includes a result_url, but it is a link inside Canvas (that is, you get HTML instead of JSON). It's not an HTML page that makes a XHR request to get the JSON, the stuff comes as part of the page. You could parse the page and look for the link. Let's avoid that if we can.
Here's how I know to get the information.
The Submission API has List assignment submissions and List submissions for multiple assignments endpoints that supports include[]=submission_history.
I need to use the assignment ID, not the quiz ID to do this.
Here's an example. You will obviously need to make the numbers match your data and include your Canvas instance hostname at the beginning of any calls.
Let's say that I have course_id=896751 that has a quiz with quiz_id=3249889 that corresponds to assignment_id=9284082.
GET /api/v1/courses/896851/assignments/9284082/submissions?include[]=submission_history
This returns an array with one submission per student. Inside each entry is a submission_history object that contains a submission_data array. The submission_data array contains one entry for each question with information about the student's response.
You will need to find the correct question based off of the question_id. This can be done for questions, provided they are not linked to a question bank, using the List questions in a quiz or submission endpoint of the Quiz Questions API.
GET /api/v1/courses/896851/quizzes/3249889/questions
If you're looking up the quiz questions, the file upload questions will have question_type="file_upload_question"
Alternatively, you may not need to look up the question since the submission_history.submission_data entries have attachment_ids when it is a file upload. I'm not sure if other types allow attachments as well.
As mentioned, for file upload question types, there is an attachment_ids array that contains the numeric ID of the attachment.
In my test data, I got 175323619 as an attachment ID.
To get information about the file, I need to use the Get file endpoint of the Files API.
GET /api/v1/files/175323619
The JSON returned there has an URL that is a non-API call and contains a verifier code to allow access outside of Canvas.
Retrieving that URL will get you the file. You should not send the API Authorization Token since it is not an API call. The verifier contains the code that Canvas needs for authorization.
It seems that a recent change started allowing quiz responses by some other method, but I cannot think of what it was (or if I'm thinking of something else). The API change log doesn't mention anything similar to what I'm thinking of. There is very little development going on in the way of classic quizzes as Canvas moves to new quizzes.
Another way to get the information is to use Puppeteer or Selenium (or other headless browser) to automate the process of going to the quiz moderation page and clicking on Download All Files. You really don't even have to get that far, once you're authenticated, you can send the link directly.
GET /courses/896851/quizzes/3249889/submissions?zip=1
This process has to generate and zip the files for you, so you will need to wait for the download link to become available. Trying to turn that link into an API call does not work.