Uploads
Two endpoints. Both requireuploads:write.
Entrypoints
POST /v1/uploads — multipart
POST /v1/uploads/from-url
FileUploadResponse shape. Use when the file is already hosted publicly and you don’t want to proxy it through your own machine.
SSRF-validated server-side — internal / localhost / metadata URLs are rejected with 422.
Supported types
- Images: PNG, JPEG, WebP
- Documents: PDF, PPTX
422 unprocessable.
Deduplication
Content-hash dedupe. Uploading the same bytes twice returns:id / url / filename / mime_type / size_bytes point at the existing record. Safe to call repeatedly — no duplicate storage, no duplicate billing.
Using in a task
Roles
Pick the right role — it determines what the agent does with the file. See
moda-mcp/references/attachments.md for details; the attachment shape is identical between MCP and REST.
URL-form attachment (legacy, less preferred)
Worked example
Common wrong guesses
- Posting files as JSON-encoded base64 into
POST /v1/uploads. Use multipart (multipart/form-data). - Using the proxy URL (
/api/v2/images/ref/…) as if it were stable public content. It includes an auth hash; it’s a stable reference for use in Moda-side operations, not a CDN URL. - Re-uploading on every run when content hasn’t changed. Dedupe handles it server-side, but you still pay a roundtrip. Cache
file_idin your app. - Skipping
rolein the attachment. It drops back to a generic “reference” semantic, which is usually not what you want. Always setrole. - Mixing
file_idandurlin one attachment item. Pick one per item. Mix items within the array is fine.