BookmarkSubscribeRSS Feed
Fluorite | Level 6


I am new to use PROC HTTP. I found a post here is very useful to my situation but I couldn't make it work for me. I have successfully uploaded an excel file via cURL as below: 

curl -H "Authorization: Bearer <my token>" -X POST \
 -F attributes="{\"name\":\"test.xlsx\", \"parent\":{\"id\":\"43742861365\"}}" \
 -F file=@c:\temp\test.xlsx
So my environment is not an issue. 

I can upload text files successfully using below codes, but get '400 Bad Request' when I try to upload an excel file or other binary files:


filename copyfile "c:\temp\test.xlsx" ;
filename request TEMP ;
%let boundary=foobar;
%let boxfolderID=43742861365;
%let updestfile=upload.xlsx;
%let my_token=12345dfdgrfhggfnhgn;

filename resptext temp;
filename resphdrs temp;


* upload require json two parts for multipart/form-data;

data _null_;
    file request termstr=CRLF;
    if _n_ = 1 then do;
        put "--&boundary";
        put 'Content-Disposition: form-data; name="attributes"';
        put ;
        put '{"name":"' "&updestfile" '", "parent":{"id":"' "&boxfolderID" '"}}';
        put "--&boundary";
        put 'Content-Disposition: form-data; name="file"; filename="' "&updestfile" '"';
        put "Content-Type: application/";
        /*put "Content-Type: application/octet-stream";*/

       put ;


*append my binary file;
data _null_;  
    file request mod recfm=n;
    infile copyfile recfm=n;
    input c $CHAR1.;
    put c $CHAR1. @@;


data _null_;
    file request mod termstr=CRLF;
    put "--&boundary--";

data _null_;
    length bytes $1024;
    fid = fopen("request");
    rc = fread(fid);
    bytes = finfo(fid, 'File Size (bytes)');
    call symput("FileSize",trim(bytes));
    rc = fclose(fid);
    put bytes;

proc http
        method    = "POST"
        out       = resptext
        headerout = resphdrs
        in        = request
        ct        = "multipart/form-data; boundary=&boundary;Content-Length=&filesize;Content-MD5"   ;
    headers      "Authorization"  = "Bearer &my_token"    ;


 I am not sure why it is not working. The same codes works fine for .csv files, but not .xlsx files. Thanks in advance.




Assuming that you have a local SAS installation: have to tried using x-command with the tested curl-command?

Fluorite | Level 6

Hi Andrea,


Yes. I tested it using x command on my local SAS and it works well. But I would like to use PROC HTTP since I will use it on our SAS server environment eventually. Any ideas something wrong with my codes on PROC HTTP part? Thanks again,



Calcite | Level 5

Helen: Can you please share the piece of code you submitted via X command. I'm curious how you dealt with quotes.

I'm doing something similar Thanks. 

Fluorite | Level 6

of course. For windows, you need to add '\' before double quotes:


x 'curl \
 -H "Authorization: Bearer <my_token>" -X POST \
 -F attributes="{\"Content-Disposition\": \"form-data\",\"Content-Type\": \"application/octet-stream\",\"name\":\"test.xlsx\", \"parent\":{\"id\":\"<folder_ID>\"}}" \
 -F file=@c:\temp\test.xlsx' ;


Can anybody explain why my proc http codes is not working? Thanks,



Community Manager

If it works with CSV but not Excel, then I'm suspicious of the DATA step that copies the binary content.  Your version:


data _null_;   
    file request mod recfm=n;
    infile copyfile recfm=n;
    input c $CHAR1.; 
    put c $CHAR1. @@; 

Any reason you didn't go with the version in the thread you cited?


data _null_;
    file request mod recfm=f lrecl=1;
    infile copyfile  recfm=f lrecl=1;
    put _infile_;

The CHAR format does not trim spaces, but with a width of 1 that shouldn't cause an issue.  And I think the width of 1 would be just 1 byte even on UTF-8 sessions, but I haven't tested.

Fluorite | Level 6

Hi Chris,


I tried that codes in the first place and got same 400 bad request.  I suspect something wrong when I combine plain texts with binary file contents inserted between. So I played different copy binary codes without any luck. The codes for copying binary file which I have tried as below:

data _null_; file request mod recfm=f lrecl=1; infile copyfile recfm=f lrecl=1; input; put _infile_; run;

data _null_; file request mod recfm=n; infile copyfile recfm=n; input c $CHAR1.; put c $CHAR1. @@; run;

data _null_; file request mod recfm=n; infile copyfile recfm=n; input c $CHAR1.@; put c $CHAR1. ; run;

Is there anything I can try further? thanks,




Community Manager

I notice that you also have "Content-MD5" in the POST, but I didn't see where you computed/specified the MD5 hash for the file.  Is it required for this Box API?  I don't see reference to it in the cURL command, but maybe that's handled by cURL under the covers.


And to be clear, the headersout file is consistently just "400 bad request" -- not a more specific error? 


And if you have the latest SAS 9.4 maint 5, you could try the DEBUG statement in PROC HTTP.



Fluorite | Level 6

Hi Chris,


Actually I saw (here) saying 'A different Box URL,, handles uploads. This API uses the multipart post method to complete all upload tasks. You can optionally specify a Content-MD5 header with the SHA-1 hash of the file to ensure that the file is not corrupted in transit.' 'Content-MD5' is just my part of playing options. With or without it, it doesn't make any difference. Below is the contents from log (unfortunately I don't have SAS 9.4M5, my SAS version is 9.4M4, but I will ask our IT to get M5 and use DEBUG once I have it):

63 %put filesize=&filesize;



65 *Submit the Upload request to Box ;

66 proc http

67 url=""

68 method = "POST"

69 out = resptext

70 headerout = resphdrs

71 in = request

72 ct = "multipart/form-data; boundary=&boundary;Content-Length=&filesize"

73 ;

74 headers "Authorization" = "Bearer &my_token";

75 run;

NOTE: PROCEDURE HTTP used (Total process time):

real time 2.59 seconds

cpu time 2.26 seconds

NOTE: 400 Bad Request


77 /* Macro that simply echoes the contents of a fileref to the SAS log */

78 %macro echofile(file);

79 data _null_; infile &file; input; put _infile_; run;

80 %mend;

81 %echofile(resphdrs);

NOTE: The infile RESPHDRS is:

Filename=C:\Users\user\AppData\Local\Temp\SAS Temporary Files\_TD23544_DTOP90_\#LN00013,

RECFM=V,LRECL=32767,File Size (bytes)=156,

Last Modified=03Jan2018:13:32:47,

Create Time=03Jan2018:13:32:47

HTTP/1.1 400 Bad Request

Date: Wed, 03 Jan 2018 18:32:45 GMT

Content-Type: text/html; charset=UTF-8

Content-Length: 0

Age: 7

Connection: keep-alive

NOTE: 7 records were read from the infile RESPHDRS.

The minimum record length was 0.

The maximum record length was 38.

NOTE: DATA statement used (Total process time):

real time 0.01 seconds

cpu time 0.01 seconds

Fluorite | Level 6

Update: I have sas9.4 M5 installed. First I used 'debug level=1; the log has no difference comparing with without this statement; when I changed to 'level=2', SAS crashed as below:


My SAS version:image.png

Any ideas?


Fluorite | Level 6

below is the log when I am using 'debug level=1;':image.png

Thanks for any thoguhts again!


Obsidian | Level 7

Hi - I have a similar problem. 


Also XLSX, DOCX, PDF files I would like to POST


And I have a CURL statement that works - but would very much like to convert it to PROC HTTP.


So - Is this community-post solved?

Obsidian | Level 7

As mentioned earlier I had a similar problem, this code works. The real problem was to detect how to build the Multipart form with the rigt bondary an content types. Feel free to copy.Smiley Happy


However I have the same problem in M5 when using "debug level=2" - SAS crashes.



filename req "F:\SASNykredit\CURL-HTTP\HTTP trial\Datafiler\request.txt";
filename resp "F:\SASNykredit\CURL_HTTP\HTTP trial\Datafiler\response.txt";
filename binfile "F:\SASNykredit\CURL-HTTP\HTTP trial\Datafiler\testdata.xlsx";


%let _boundary=3fbd04f5-b1ed-4060-99b9-fca7ff59c113;
%let _cat=Testliste;
%let _publdate=%sysfunc(today(), yymmddd10.);
%let _unpubldate=%sysfunc(intnx(MONTH,%sysfunc(today(),8.),12,S),yymmddd10.);
%let _binname=%scan(%sysfunc(pathname(binfile)),-1,'\');
%let _title=%upcase(&sysuserid) TEST &_publdate.;

%put &=_boundary &=_cat &=_publdate &=_unpubldate &=_title &=_binname;

/*** Fanger fejlkode fra PROC HTTP ***/
%macro prochttp_check_return(_exp_code);
%if %symexist(SYS_PROCHTTP_STATUS_CODE) ne 1 %then
%put ERROR: Expected &_exp_code., but a response was not received from the HTTP Procedure;
%if &SYS_PROCHTTP_STATUS_CODE. ne &_exp_code. %then
%put ERROR: Expected &_exp_code., but received &SYS_PROCHTTP_STATUS_CODE.;
%put NOTE: Alt i orden, forventet returkode: &SYS_PROCHTTP_STATUS_CODE. &SYS_PROCHTTP_STATUS_PHRASE.;
%mend prochttp_check_return;

/*** MULTIPART-FORM data ***/
data _null_;
file req termstr=CRLF;
put "--&_boundary.";
put 'Content-Disposition: form-data; name="publish"';
put "&_publdate";
put "--&_boundary.";
put 'Content-Disposition: form-data; name="unpublish"';
put "&_unpubldate";
put "--&_boundary.";
put 'Content-Disposition: form-data; name="category"';
put "&_cat";
put "--&_boundary.";
put 'Content-Disposition: form-data; name="title"';
put "&_title";
put "--&_boundary.";
put 'Content-Disposition: form-data; name="uploadfile"; filename='"&_binname.";
put 'Content-Type: application/octet-stream';

/*** Tilføjer binær fil ***/
data _null_;
file req mod recfm=n;
infile binfile recfm=n;
input c $CHAR1.;
put c $CHAR1. @@;

/*** Afslutning ***/
data _null_;
file req mod termstr=CRLF;
put / "--&_boundary.--";

proc http
CT="multipart/form-data; boundary=&_boundary"
*DEBUG Level=1;

%put &=sys_prochttp_status_code.;
%put &=sys_prochttp_status_phrase.;


filename req clear;
filename resp clear;
filename binfile clear;

Quartz | Level 8

where do i get the value for macro variable _boundary, or is it any constant  ?

Thank you for sharing your code



Registration is open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.

If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website. 

Register now!

What is Bayesian Analysis?

Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.

Find more tutorials on the SAS Users YouTube channel.

Get the $99 certification deal.jpg



Back in the Classroom!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 13 replies
  • 6 in conversation