Add file to Notes via REST API

I'm trying to post a file via the REST API. I already create the note, I have the note ID and now I'm trying to upload a file to the note.

Documentation is not so clear to me.

When I cal the API like this:

Notes/0df989f0-7453-11ec-838a-065b9161e400/file/test.pdf how does the object need to be like? Is it a Note object? Where to add the file byte array?

  • Just have a look on my little php script which creates an outer note and then adds an attachment.

    <?php
    //////////////////////////////////////////////////////////
    // Create Note with Attachement Version 11.x ++
    //////////////////////////////////////////////////////////
    
    
    $name     = "testnote";
    $filename = "testnote.pdf";
    $description = "uploaded file to sugar note";
    $node_id  = "";
    
    $username = "jim";
    $password = "jim";
    $migrator = "1"; 
    $base_url = "http://localhost/sugarent1120/rest/v10";
    $platform = "integration";
    
    if(file_exists('auth.php')) include 'auth.php';
    
    ini_set('max_execution_time', 0);
    
    $script_start = time();
    $time_start = time();					 
    
    //////////////////////////////////////////////////////////
    //Login - POST /oauth2/token
    //////////////////////////////////////////////////////////
    
    $login_url = $base_url . "/oauth2/token";
    $logout_url = $base_url . "/oauth2/logout";										   
    
    $oauth2_token_arguments = array(
        "grant_type" => "password",
        //client id/secret you created in Admin > OAuth Keys
        "client_id" => "sugar",
        "client_secret" => "",
        "username" => $username,
        "password" => $password,
        "platform" => $platform
    );
    
    $oauth2_token_response = call($login_url, '', 'POST', $oauth2_token_arguments);
    print_r($oauth2_token_response);
    echo "<hr>";
    
    if ($oauth2_token_response->access_token == "") die("No Login");
    
    
    $time_max = $oauth2_token_response->expires_in - 60;
    		
    //////////////////////////////////////////////////////////   			
    // STEP 1 - Create outer note record - POST /<module>/:record
    //////////////////////////////////////////////////////////   			
    if ($note_id == "") {
    
    	$url = $base_url . "/Notes";
    	
    	if ($name == "") $name = "-- no subject --";
    	
    	$note_arguments = array(	
    		"note_parent_id" => "",
    		"set_created_by" => true,
    		"description" => $description,
    		"name" => $name,
    		"assigned_user_id" => "1",
    		"team_id" => "1",
    		"team_set_id" => "1",
    		"acl_team_set_id" => "1",
            "portal_flag" => false,
            "embed_flag" => false,
            "following" => false,
            "my_favorite" => false,
    		"modified_user_id" => "1",
    		"created_by" => "1",
    	    "erased_fields" => true,
    	);
    	$DEBUG .= "## CREATE NOTE: ".print_r($note_arguments,true)." ##</br>\n";
    
    	$note_response = call($url, $oauth2_token_response->access_token, 'POST', $note_arguments);
    	$DEBUG .= "## CREATED: ".print_r($note_response,true)." ##</br>\n";
    	$DEBUG .= "## CREATED RESPONSE: ".$note_response->id . "<br>\n";
    
        $note_id = $note_response->id;
    }
    
    //////////////////////////////////////////////////////////   			
    //STEP 2 - Create attachment record - POST /<module>/:record
    //////////////////////////////////////////////////////////   			
    if ($note_id != "") {
    
    	$url = $base_url . "/Notes";
    	
    	$note_arguments = array(	
    		"note_parent_id" => $note_id,
    		"set_created_by" => true,
    		"description" => "",
    		"name" => $filename,
    		"assigned_user_id" => "1",
    		"team_id" => "1",
    		"team_set_id" => "1",
    		"acl_team_set_id" => "1",
            "portal_flag" => false,
            "embed_flag" => false,
            "following" => false,
            "my_favorite" => false,
    		"modified_user_id" => "1",
    		"created_by" => "1",
    	    "erased_fields" => true,
    	);
    	if ($filename != ""){  
    	   $note_arguments["filename"] = $filename;
    	   $note_arguments["attachment_flag"] = 1;
    	   
    	}
    	$DEBUG .= "## CREATE NOTE: ".print_r($note_arguments,true)." ##</br>\n";
    
    	$note_response = call($url, $oauth2_token_response->access_token, 'POST', $note_arguments);
    	$DEBUG .= "## CREATED: ".print_r($note_response,true)." ##</br>\n";
    	$DEBUG .= "## CREATED RESPONSE: ".$note_response->id . "<br>\n";
    
        $attachment_id = $note_response->id;
    }
    		
    if ($attachment_id != "") {
    	
    	//////////////////////////////////////////////////////////   			
    	// STEP 3 - Upload note file - POST /Notes/<id>/file/filename
    	//////////////////////////////////////////////////////////   			
    	
    	if ($filename != "") { 
    		$url = $base_url . "/Notes/".$attachment_id."/file/filename";
    		
    		$file_name = $filename;  // new naming schema
    		$filepath = realpath($file_name);
    		$DEBUG .= "## FILEPATH: ".$filepath . "<br>\n";
    		
    		if ((version_compare(PHP_VERSION, '5.5') >= 0)) {
    			$DEBUG .= "##CURLFILE##\n<br>";
    			$filedata = new CURLFile($filepath,"",$data[2]);
    			$DEBUG .= "## FILEDATA: ".print_r($filedata,true) . "<br>\n";
    		} else {
    			$DEBUG .= "##REALPATH##\n<br>";
    			$filedata = '@'.$filepath;
    		    $DEBUG .= "## FILEDATA: ".$filedata . "<br>\n";
    		}
    		$file_arguments = array(
    			"format" => "sugar-html-json",
    			"delete_if_fails" => true,
    			"oauth_token" => $oauth2_token_response->access_token,
    			'filename' => $filedata,
    		);
    		$DEBUG .= "## UPLOAD FILE: ".$attachment_id. "#" .print_r($file_arguments,true) . "<br>\n";
    		$file_response = call($url, $oauth2_token_response->access_token, 'POST', $file_arguments, false,false,true);
    		$DEBUG .= "## UPLOAD RESPONSE: ".print_r($file_response->filename,true) . "<br>\n";
    		$DEBUG .= "<hr>";	
    	}
    }	
    
    $script_runtime = time()-$script_start;
    $DEBUG .= "TIME needed: ".$script_runtime."<br>\n";
    echo $DEBUG; $DEBUG="";
    
    
    ////////////////////////////////////////////////////////////////////
    // END OF MAIN
    ////////////////////////////////////////////////////////////////////
    
    
    /**
     * Generic function to make cURL request.
     * @param $url - The URL route to use.
     * @param string $oauthtoken - The oauth token.
     * @param string $type - GET, POST, PUT, DELETE. Defaults to GET.
     * @param array $arguments - Endpoint arguments.
     * @param array $encodeData - Whether or not to JSON encode the data.
     * @param array $returnHeaders - Whether or not to return the headers.
     * @param array $filenHeader - Whether or not to upload a file
     * @return mixed
     */
    function call(
        $url,
        $oauthtoken='',
        $type='GET',
        $arguments=array(),
        $encodeData=true,
        $returnHeaders=false,
    	$fileHeader=false
    )
    {
        $type = strtoupper($type);
    
        if ($type == 'GET')
        {
            $url .= "?" . http_build_query($arguments);
        }
    
        $curl_request = curl_init($url);
    
        if ($type == 'POST')
        {
            curl_setopt($curl_request, CURLOPT_POST, 1);
        }
        elseif ($type == 'PUT')
        {
            curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "PUT");
        }
        elseif ($type == 'DELETE')
        {
            curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "DELETE");
        }
    
        curl_setopt($curl_request, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($curl_request, CURLOPT_HEADER, $returnHeaders);
        curl_setopt($curl_request, CURLOPT_SSL_VERIFYHOST, 0);  // wichtig
        curl_setopt($curl_request, CURLOPT_SSL_VERIFYPEER, 0);  // wichtig
        curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl_request, CURLOPT_FOLLOWLOCATION, 0);
    
        if (!empty($oauthtoken)) 
        {
    		if ($fileHeader) {
    			curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    				"oauth-token: {$oauthtoken}"));
    		} else {
                curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    				"oauth-token: {$oauthtoken}",
    				"Content-Type: application/json"));
    		}		
        }
        else
        {
            curl_setopt($curl_request, CURLOPT_HTTPHEADER, array(
    			"Content-Type: application/json"));
        }
    
        if (!empty($arguments) && $type !== 'GET')
        {
            if ($encodeData)
            {
                //encode the arguments as JSON
                $arguments = json_encode($arguments);
            }
            curl_setopt($curl_request, CURLOPT_POSTFIELDS, $arguments);
        }
    
        $result = curl_exec($curl_request);
    	
        if ($returnHeaders)
        {
            //set headers from response
            list($headers, $content) = explode("\r\n\r\n", $result ,2);
            foreach (explode("\r\n",$headers) as $header)
            {
                header($header);
            }
    
            //return the nonheader data
            return trim($content);
        }
    
        curl_close($curl_request);
    
        //decode the response from JSON
        $response = json_decode($result);
    
        return $response;
    }
    ?>

    Harald Kuske
    Principal Solution Architect – Professional Services, EMEA
    hkuske@sugarcrm.com
    SugarCRM Deutschland GmbH

  • Thanks for the clear answer. It was hard to find from the documentation that I had to use the end point  "/Notes/"{id}"/file/filename". But now I have it. I transformed curl to c# and got it working finally, halelujah! After creating the note I use this method to add the attachment to the note:

    public async Task<bool> AddFileToNote(string token, string id, string fileUrl)
            {
                try
                {
                    using (var apiClient = new HttpClient())
                    {
                        apiClient.Timeout = new TimeSpan(0, 0, 10);
                        
                        using (var request = new HttpRequestMessage(new HttpMethod("POST"), $"{_baseUrl}/Notes/{id}/file/filename"))
                        {
                            request.Headers.TryAddWithoutValidation("OAuth-Token", token);
                            request.Headers.TryAddWithoutValidation("Cache-Control", "no-cache");
    
                            var multipartContent = new MultipartFormDataContent
                            {
                                { new ByteArrayContent(File.ReadAllBytes(fileUrl)), "filename", Path.GetFileName(fileUrl) }
                            };
                            request.Content = multipartContent;
    
                            var response = await apiClient.SendAsync(request);
                            string result = await response.Content.ReadAsStringAsync();
                            return true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    EnconLogger.Logger.Log.Error(ex);
                    //throw;
                    return false;
                }
            }