> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.ada.cx/reference/conversations/upload-attachment/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ada.cx/_mcp/server. # Upload a file attachment POST https://example.ada.support/api/v2/conversations/{conversation_id}/attachments/ Content-Type: multipart/form-data Upload a temporary file attachment to a conversation. The file is stored on Ada-managed storage and a presigned URL is returned that is valid for up to 7 days. Use that URL to create a file message by calling the `/v2/conversations/{conversation_id}/messages/` endpoint with `content.type` set to `file`. The maximum file size is 50MB. This endpoint provides temporary media storage for use within a conversation. It is **not** equivalent to the native attachment experience in Ada's widget handoff integrations (for example, the paperclip in Zendesk Messaging). With native widget attachments, files are uploaded directly into your agent platform (such as Sunshine Conversations / Zendesk) and hosted there. That native path is only available to Ada's web channel and is not accessible through the Conversations API. If you are building a headless Conversations API integration and want to send an attachment from an end user to a human agent mid-conversation so that it appears natively in your agent platform, upload the file using your agent platform's own attachment endpoints (for example, the Sunshine Conversations Attachments API for Zendesk) and consult that platform's documentation. **Note:** Attachments can only be uploaded when the conversation is in a handoff state. **Allowed file types:** TXT, LOG, CSV, EML, PNG, SVG, JPEG, JPG, GIF, HEIF, HEIC, AVIF, WAV, M4A, MP3, MP4, M4V, MOV, MPEG, MPG, ZIP, PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, Keynote, Pages, Numbers Reference: https://docs.ada.cx/reference/conversations/upload-attachment ## Authentication - `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer `, where token is your auth token. ## Request ### Path parameters - `conversation_id` (string, required) — The ID of the conversation ### Body (multipart/form-data) This endpoint expects a multipart form containing a file. - `file` (file, required) — The file to upload (max 50MB) ## Response ### 201 Attachment uploaded - `url` (string, required) — Presigned URL to access the uploaded file (valid for 7 days) - `mime_type` (string, required) — MIME type of the uploaded file - `filename` (string, required) — Name of the uploaded file ## Errors ### 400 Bad Request Error Bad Request - `errors` (list of ErrorsErrorsItems, required) — A list of errors ### 401 Unauthorized Error Unauthorized - `errors` (list of ErrorsErrorsItems, required) — A list of errors ### 404 Not Found Error Not Found - `errors` (list of ErrorsErrorsItems, required) — A list of errors ### 429 Too Many Requests Error Too Many Requests - `errors` (list of ErrorsErrorsItems, required) — A list of errors ### 500 Internal Server Error Internal Server Error - `errors` (list of ErrorsErrorsItems, required) — A list of errors ## Types ### ErrorsErrorsItems - `type` (string, required) — The error type - `message` (string, required) — The error message - `details` (string, optional, nullable) — Extra information about the error ## Examples **Request** ```json { "file": "" } ``` **Response** ```json { "url": "https://s3.amazonaws.com/bucket/conversations/5df263b7db5a7e6ea03fae9b/5df263b7db5a7e6ea03fae9b/a1b2c3d4-e5f6-7890-abcd-ef1234567890/document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256", "mime_type": "application/pdf", "filename": "document.pdf" } ``` **SDK Code** ```python import requests url = "https://example.ada.support/api/v2/conversations/conversation_id/attachments/" files = { "file": "open('string', 'rb')" } headers = {"Authorization": "Bearer "} response = requests.post(url, files=files, headers=headers) print(response.json()) ``` ```javascript const url = 'https://example.ada.support/api/v2/conversations/conversation_id/attachments/'; const form = new FormData(); form.append('file', 'string'); const options = {method: 'POST', headers: {Authorization: 'Bearer '}}; options.body = form; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://example.ada.support/api/v2/conversations/conversation_id/attachments/" payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001--\r\n") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Authorization", "Bearer ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://example.ada.support/api/v2/conversations/conversation_id/attachments/") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = 'Bearer ' request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001--\r\n" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://example.ada.support/api/v2/conversations/conversation_id/attachments/") .header("Authorization", "Bearer ") .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001--\r\n") .asString(); ``` ```php request('POST', 'https://example.ada.support/api/v2/conversations/conversation_id/attachments/', [ 'multipart' => [ [ 'name' => 'file', 'filename' => 'string', 'contents' => null ] ] 'headers' => [ 'Authorization' => 'Bearer ', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://example.ada.support/api/v2/conversations/conversation_id/attachments/"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer "); request.AddParameter("undefined", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"string\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["Authorization": "Bearer "] let parameters = [ [ "name": "file", "fileName": "string" ] ] let boundary = "---011000010111000001101001" var body = "" var error: NSError? = nil for param in parameters { let paramName = param["name"]! body += "--\(boundary)\r\n" body += "Content-Disposition:form-data; name=\"\(paramName)\"" if let filename = param["fileName"] { let contentType = param["content-type"]! let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8) if (error != nil) { print(error as Any) } body += "; filename=\"\(filename)\"\r\n" body += "Content-Type: \(contentType)\r\n\r\n" body += fileContent } else if let paramValue = param["value"] { body += "\r\n\r\n\(paramValue)" } } let request = NSMutableURLRequest(url: NSURL(string: "https://example.ada.support/api/v2/conversations/conversation_id/attachments/")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```