Uploading a file using Power Automate

I have files stored in a SharePoint library, and want to use Power Automate ¶ to upload them to HubSpot. I can’t use the async import from URL API as these would be sensitive files.

Ideally I’d like to use the new API (CMS API | Files (hubspot.com)) POST /files/v3/files instead of the legacy one Upload a new file | COS Files API (hubspot.com) but after trying so much, at this point, either would be fine.

I’m unsure how to provide the file information for the API calls, and keep getting:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 415 Unsupported Media Type</title>
</head>
<body><h2>HTTP ERROR 415</h2>
<p>Reason:
<pre> Unsupported Media Type</pre></p>
</body>
</html>

My HTTP request (with the legacy API) in PA looks like this:

The file is the $content output of the Get File Content block, which outputs the content type and content like so:

I’ve checked all the other posts I could find with people experiencing similar issues and can’t seem to get it to work…One person posted their Powershell code and even replicating that resulted in the same error:

clear
$apiKey = 'Bearer **key_here**'
$uri = "https://api.hubapi.com/filemanager/api/v3/files/upload?hapikey=$apiKey"

$fileOptions = @{
 access = 'PRIVATE'
 overwrite = 'true'
 duplicateValidationStrategy = 'NONE'
 duplicateValidationScope = 'EXACT_FOLDER'
}

$body = @{
 fileName = 'testfile.txt'
 file = Get-Item C:\temp\testfile.txt
 folderPath = '/Uploaded Documents'
 charsetHunch = 'UTF-8'
 options = $fileOptions | ConvertTo-Json
}

$response = Invoke-WebRequest -Uri $uri -Method Post -Body $body -Verbose 
$response.results

Is it the charsetHunch that I’m not setting properly? I’m stumped…and I must say, the documentation is relly not helpfull at all CMS API | Files (hubspot.com) No example is provided, doesn’t say which params are necessary for the upload file endpoint, and isn’t sufficiently explanatory at all :persevering_face:

Any help would be greatly appreciated.

Hey @AKhan786,

I think the issue is to do with the “Content-Type” header. Regardless of whether you are using the legacy endpoint or the newer endpoint the correct header to use is “multipart/form-data” vs “application/pdf” which you seem to be referencing.

I’ve tried that header as-well, but I got Bad Request HTTP 400 error:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 400 Bad Request</title>
</head>
<body><h2>HTTP ERROR 400</h2>
<p>Reason:
<pre> Bad Request</pre></p>
</body>
</html>

For reference, my HTTP request inputs look like this:

{
 "uri": "https://api.hubapi.com/files/v3/files",
 "method": "POST",
 "headers": {
 "Content-Type": "multipart/form-data"
 },
 "retryPolicy": {
 "type": "Fixed",
 "interval": "PT5S",
 "count": 5
 },
 "authentication": {
 "value": "*sanitized*",
 "type": "Raw"
 },
 "body": {
 "file": "*really looooong jumble of text here from "Get Item" block in PA*",
 "fileName": "SoWTest.xlsx",
 "folderPath": "/Uploaded Documents",
 "charsetHunch": "UTF-8",
 "options": {
 "access": "PRIVATE",
 "duplicateValidationStrategy": "NONE",
 "duplicateValidationScope": "EXACT_FOLDER",
 "overwrite": true
 }
 }
}

I’ve posted on the slack dev api chat and still can’t figure it out :disappointed_face:

Was told there to put quotes around my “options” values, as it doesn’t take a JSON.

So I’ve done so (and escaped the other “” via \) so PA accepts it as a valid JSON.

{
 "uri": "https://api.hubapi.com/files/v3/files",
 "method": "POST",
 "headers": {
 "Content-Type": "multipart/form-data"
 },
 "retryPolicy": {
 "type": "Fixed",
 "interval": "PT5S",
 "count": 5
 },
 "authentication": {
 "value": "*sanitized*",
 "type": "Raw"
 },
 "body": {
 "file": "I think it's a base64 string of the file content here"
 "fileName": "SoWTest.xlsx",
 "folderPath": "/",
 "charsetHunch": "UTF-8",
 "options": "{\"access\": \"PRIVATE\", \"duplicateValidationStrategy\": \"NONE\", \"overwrite\": true, \"duplicateValidationScope\": \"EXACT_FOLDER\"}"
 }
}

But now I get HTTP 400 Error

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 400 Bad Request</title>
</head>
<body><h2>HTTP ERROR 400</h2>
<p>Reason:
<pre> Bad Request</pre></p>
</body>
</html>

Hey @AKhan786,

I found this post on the PowerAutomate Community discussing how to POST files with multipart/form-data. It’s not specific to HubSpot but it might help in terms of how the HTTP request was configured.

From what I can see your request looks fine and should work. I think the issue might be how the HTTP module in PowerAutomate is processing the file and hence the 400 error being returned.

Hallelujah! You pointed me on the right path, and after a lot more googling along that line, trial & error testing, I stumbled accross the answer :grinning_face_with_smiling_eyes:

The key things are:

  1. Format the request body as a multi-part form.
    • It’s confusing and complex, and I don’t fully understand (like why certain things like the fileName works in the header, but folderPath needs to be in the body) but hey - it works!
  2. The file content needs to be converted from Base64 (or whatever format you might have gotten it in) into Binary.

This is what the request looks like:

And this is the code for copy/paste:

(Bear in mind the file body is dynamic content so you’d replace that with your binary file data)

{
"$content-type": "multipart/form-data",
"$multipart": [
{
"headers": {
 "Content-Disposition": "form-data; name=\"options\""
 },
 "body": "{\"access\": \"PRIVATE\"}"
},
 {
 "headers": {
 "Content-Disposition": "form-data; name=\"file\"; fileName=\"Test.pdf\""
 },
 "body": @{base64ToBinary(outputs('Get_file_content')?['body']?['$content'])}
 },
 {
 "headers": {
 "Content-Disposition": "form-data; name=\"folderPath\""
 },
 "body": "/Uploaded Documents"
 }
 ]
}

Glad you got it working @AKhan786 :blush:

Thank you this is amazing just solved 8 hours of hair pulling not sure why it works but my god it does well done!!