Flowscript Multipart form-data

I am trying to upload a document to a REST endpoint using flowscript. The call requires me to use multipart/form-data. The documentation on this is sparce and I cannot get a straightforward answer.

I am attempting to do Retrieval Augmented Generation (RAG) on a document. The curl call is:

curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Accept: application/json" \
-F "file=@/path/to/your/file" http://localhost:3000/api/v1/files/

When I run in Connect, I get this error:

HTTP Code: 400
Error: Bad Request
Message: The Content-Disposition header field "name" must be provided.

My code:

let url  = `/api/v1/files/`;
type ErrorType1 = {
  detail: {
    type: text,
    loc: text*,
    msg: text,
    input: null
  }*
};
type ErrorType = {
  detail: text
};
type ResponseType = {
  "id": text,
  "user_id": text,
  "hash": text?,
  "filename": text,
  "data": {
    "status": text
  },
  "meta": {
    "name": text,
    "content_type": text,
    "size": number
  },
  "created_at": number,
  "updated_at": number,
  "status": boolean,
  "path": text
};

let Response1 = HTTP.request(
    url,
    {
        method: 'POST',
        headers: {"Accept":"application/json"},
        continueOnError: true,
        body: HTTP.multipart('form-data',
            //{ contentType: 'application/octet-stream', content: FirstDoc.data, name: "file", filename: '"'& FirstDoc.filename & '"' }
            //{ name: "file", filename: '"'& FirstDoc.filename & '"', content: FirstDoc.data }
            { content: 'name="file"; filename="' & FirstDoc.filename & '"' }
        )
    }
);
let SuccessResponse1 = case when Response1.statusCode = 200 then
                           JSON.deserialize<ResponseType>(Response1.asText())
                           else default(ResponseType)
                       end;
let ErrorResponse1   = case when Response1.statusCode != 200 then
                           JSON.deserialize<ErrorType>(Response1.asText())
                           else default(ErrorType)
                       end;

return {
    HttpStatusCode       : Response1.statusCode,
    ErrorMessage         : Response1.reasonPhrase,
    DetailedErrorMessage : ErrorResponse1.detail,
    Headers              : Response1.headers,
    Result               : SuccessResponse1
};

Postman raw log (working):

POST /api/v1/files/ HTTP/1.1
Accept: application/json
Authorization: Bearer sk-07b9bd38fe914310a35d0a803a8e9e50
User-Agent: PostmanRuntime/7.51.0
Postman-Token: d068f64e-0684-4bed-91eb-f9708402dce4
Host: localhost:3000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=--------------------------831347693450459289231793
Content-Length: 293989
 
----------------------------831347693450459289231793
Content-Disposition: form-data; name="file"; filename="Changes to Production for Shifts.pdf"
<Changes to Production for Shifts.pdf>
----------------------------831347693450459289231793--
 
HTTP/1.1 200 OK
Date: Mon, 29 Dec 2025 06:30:18 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
x-process-time: 0
Server: Cloudflare
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Robots-Tag: noindex, nofollow
X-XSS-Protection: 1; mode=block
Permissions-Policy: geolocation=(self), midi=(self), sync-xhr=(self), microphone=(self), camera=(self), magnetometer=(self), gyroscope=(self), fullscreen=(self), payment=(self), interest-cohort=()
Content-Encoding: br
 
{"id":"9aeb3358-2de7-4503-b81e-95542ce55abd","user_id":"a7dbe76a-0ab2-4b67-a23b-c478bcddf082","hash":null,"filename":"Changes to Production for Shifts.pdf","data":{"status":"pending"},"meta":{"name":"Changes to Production for Shifts.pdf","content_type":"application/pdf","size":293750,"data":{}},"created_at":1766989818,"updated_at":1766989818,"status":true,"path":"/app/backend/data/uploads/9aeb3358-2de7-4503-b81e-95542ce55abd_Changes to Production for Shifts.pdf","access_control":null}

Has anyone done this before? How can I get the fields required? Any help is appreciated.

Hi @daniel :slight_smile:
i will give you a example for that

type ErrorResponseType = {
    Status: number,
    URL: text,
    Method: text,
    Exception: {
        Name: text,
        Message: text,
        InnerException: {
            Name: text,
            Message: text,
            StackText: text
        }
    },
    Stack: text,
    Message: text,
    IsLoggedToVault: boolean,
    IsLoggedToApplication: boolean,
    ExceptionName: text
}

if(fetchAttachment.Results != null){
    let Response = HTTP.request(
                                "/REST/objects/0/"&objid&"/latest/files",
                                 {
                                    method:"POST",
                                    body:HTTP.multipart("form-data", 
                                   // { contentType: 'text/plain', content: newFileName },  
                                    { contentType: 'application/octet-stream', content: fetchAttachment.Results ,contentDisposition: `form-data; name="file"; filename="{newFileName}"`}),
                                    headers:{
                                        "Cookie"      : cookie,
                                        "Accept"      :"application/json",
                                        "X-Authentication" : token.Result.Value}
                                    }
                               );  
    return {
        HttpStatusCode       : Response.statusCode,
        ReasonPhrase         : Response.reasonPhrase
    };
}                        

return default({
        HttpStatusCode,
        ReasonPhrase  
})

Using this code, I receive the same error message. What version of the connector agent are you using?