Manage case files
This page complements the Cases GraphQL API guide. Use it for the file operations that support the case workflow.
To create a case or add evidence during its lifecycle, see Manage the case lifecycle.
Upload, retrieve, download, and delete files attached to a case.
What this covers¶
This guide shows how to upload a file through its presigned URL. It also shows how to check status, retrieve files, and delete a file.
Prerequisites¶
- Create a service principal and get a bearer token. See the Cases GraphQL quickstart.
- Get the full case ID. File uploads require an open case.
- Keep the local file available so its size and content type match the upload request.
Workflow¶
Managing file attachments with the Cases GraphQL API consists of the following steps:
- Initialize an upload and save the returned file ID and presigned URL.
- Upload the file content to the presigned URL.
- Query the file until its status is
UPLOADED. - List, download, or delete the file as needed.
Initialize file upload¶
mutation startCaseFileUpload($input: StartCaseFileUploadInput!) {
startCaseFileUpload(input: $input) {
file {
id
name
size
status
}
presignedUrl
}
}
Variables¶
{
"input": {
"caseId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "investigation_report.pdf",
"size": 1024000,
"contentType": "application/pdf",
"isEmbedded": false
}
}
Response¶
{
"data": {
"startCaseFileUpload": {
"file": {
"id": "550e8400-e29b-41d4-a716-446655440500",
"name": "investigation_report.pdf",
"size": 1024000,
"status": "SCHEDULED"
},
"presignedUrl": "https://files.example.com/upload-url..."
}
}
}
Upload the file before the presigned URL expires. Use the presignedUrl from the response.
Upload the file¶
curl --request PUT \
--header "Content-Type: application/pdf" \
--upload-file ./investigation_report.pdf \
"<presigned-url>"
The content type and file size must match the values sent to startCaseFileUpload. The service updates the file status after it processes the object-storage event.
Delete file¶
mutation deleteCaseFile($input: DeleteCaseFileInput!) {
deleteCaseFile(input: $input) {
id
name
deletedAt
}
}
Variables¶
{
"input": {
"fileId": "<file_id>"
}
}
Response example¶
{
"data": {
"deleteCaseFile": {
"id": "<file_id>",
"name": "investigation_report.pdf",
"deletedAt": "2024-08-14T16:05:00Z"
}
}
}
Get case files¶
List files attached to a case. Request downloadURL to get a signed URL for retrieving the file's contents.
query caseFiles($arguments: CaseFilesArguments!) {
caseFiles(arguments: $arguments) {
files {
id
name
size
status
isEmbedded
createdAt
downloadURL
}
totalCount
}
}
Variables¶
{
"arguments": {
"query": "investigationId = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'",
"page": 1,
"perPage": 20
}
}
Response example¶
{
"data": {
"caseFiles": {
"files": [
{
"id": "550e8400-e29b-41d4-a716-446655440500",
"name": "investigation_report.pdf",
"size": 1024000,
"status": "UPLOADED",
"isEmbedded": false,
"createdAt": "2024-08-14T15:52:30Z",
"downloadURL": "https://files.example.com/signed-url..."
}
],
"totalCount": 1
}
}
}
Get a single file¶
Use caseFile to fetch one file by ID, for example, to refresh an expired downloadURL.
query caseFile($arguments: CaseFileArguments!) {
caseFile(arguments: $arguments) {
id
name
size
status
downloadURL
}
}
Variables¶
{
"arguments": {
"fileId": "550e8400-e29b-41d4-a716-446655440500"
}
}
Response example¶
{
"data": {
"caseFile": {
"id": "550e8400-e29b-41d4-a716-446655440500",
"name": "investigation_report.pdf",
"size": 1024000,
"status": "UPLOADED",
"downloadURL": "https://files.example.com/download-url..."
}
}
}
Repeat this query until status is UPLOADED or ERROR_UPLOAD. Use downloadURL only after the status is UPLOADED.
Error handling¶
Check the HTTP status and the GraphQL response body. A request can return HTTP 200 with an errors array.
If the upload fails, check that the file size and content type match the initialization input. An expired presigned URL requires a new upload initialization.
Constraints and considerations¶
isEmbeddedindicates whether the file is embedded in case content (for example, images in key findings). Embedded files don't generate audit log entries on download.statusis one ofSCHEDULED(upload URL issued, file not yet uploaded),UPLOADED,ERROR_UPLOAD, orDELETED.- Download URLs are signed and valid for 15 minutes. Re-query
caseFileorcaseFileswithdownloadURLselected to refresh the URL. - Requesting download URLs generates audit logs (except for embedded files).
caseFilesisn't scoped to a case by default — you must filter it with thequeryargument using QL. Match the case'sidwithinvestigationId = '<case id>', notcaseId. Add... and isEmbedded = falseto exclude embedded files.
Related operations¶
- Cases GraphQL API guide
- Manage the case lifecycle
startCaseFileUploadcaseFilecaseFilesdeleteCaseFile