API: Attachments
Attachments use a three-legged, content-addressed upload: you register the file with its SHA-256 checksum, upload the bytes to a presigned URL, then confirm. If the workspace already stores identical content, the upload leg is skipped entirely.
1. Register the upload
Section titled “1. Register the upload”POST /api/workspaces/{workspaceId}/tasks/{taskId}/attachments{ "checksum": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "fileName": "color-sample.jpg", "mediaType": "image/jpeg", "sizeBytes": 182734}checksum is the lowercase SHA-256 hex of the file content. Returns 201:
{ "id": "019f…", "uploadUrl": "https://…storage…?X-Amz-Signature=…"}uploadUrlisnullwhen the workspace already stores this content — the attachment is complete, skip steps 2 and 3.- Errors:
409if this file is already attached to this task,413if the workspace storage limit would be exceeded.
2. Upload the bytes
Section titled “2. Upload the bytes”PUT the raw file to uploadUrl with the same Content-Type you
registered:
curl -X PUT --data-binary @color-sample.jpg \ -H "Content-Type: image/jpeg" "$UPLOAD_URL"The URL is presigned and short-lived; no Todomino token is sent here.
3. Complete
Section titled “3. Complete”POST /api/workspaces/{workspaceId}/tasks/{taskId}/attachments/{attachmentId}/completeReturns 200 after the server verifies the stored object’s size. 400 if
the upload never arrived.
Download
Section titled “Download”GET /api/workspaces/{workspaceId}/tasks/{taskId}/attachments/{attachmentId}/downloadAnswers 302 Found with a short-lived presigned URL in the Location
header. Follow the redirect without forwarding your Authorization
header (most HTTP clients do this correctly by default).
Delete
Section titled “Delete”DELETE /api/workspaces/{workspaceId}/tasks/{taskId}/attachments/{attachmentId}Returns 204. Removes the attachment from the task; the stored file is
deleted only when no other task references the same content.
