I am using the following code to call the docusign api. I got the information from this link.
<soap:Body>
<ns:CreateEnvelopeFromTemplates>
<ns:TemplateReferences>
<ns:TemplateReference>
<ns:TemplateLocation>Server</ns:TemplateLocation>
<ns:Template>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</ns:Template>
<ns:RoleAssignments>
<ns:RoleAssignment>
<ns:RoleName>Company</ns:RoleName>
<ns:RecipientID>1</ns:RecipientID>
</ns:RoleAssignment>
</ns:RoleAssignments>
</ns:TemplateReference>
</ns:TemplateReferences>
<ns:Recipients>
<ns:Recipient>
<ns:ID>1</ns:ID>
<ns:UserName>Fred Flintstone</ns:UserName>
<ns:Email>fred.flintstone#...</ns:Email>
<ns:Type>Signer</ns:Type>
<ns:RoleName>Caveman</ns:RoleName>
<ns:RoutingOrder>1</ns:RoutingOrder>
</ns:Recipient>
</ns:Recipients>
<ns:EnvelopeInformation>
<ns:AccountId>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</ns:AccountId>
<ns:EmailBlurb>This Envelope was sent through the DocuSign API using ColdFusion</ns:EmailBlurb>
<ns:Subject>DocuSign it! using ColdFusion</ns:Subject>
</ns:EnvelopeInformation>
<ns:ActivateEnvelope>true</ns:ActivateEnvelope>
</ns:CreateEnvelopeFromTemplates>
</soap:Body>
I am unable to understand what the RoleAssignment tag under Template is used for. I have gone through the documentation here but did not understand it.
I think this is the only reason I am not getting a response. I commented this portion in my code but I am getting the following output after changing all of the credentials.
An error occurred!
struct
Charset [empty string]
ErrorDetail Unknown host: demo.docusign.net
Filecontent Connection Failure
Header [empty string]
Mimetype Unable to determine MIME type of file.
Responseheader
struct [empty]
Statuscode Connection Failure. Status code unavailable.
Text YES
Can anyone please help me out with this?
I don't think the RoleAssignment has anything to do with that particular error. You need to combine the SOAP Header and the SOAP Body from their example. The SOAP Body should be contained with the SOAP Header block.
Notice that their example for the SOAP Header contains the <soap:Body> block. Then their example for the SOAP Body is also surrounded by the <soap:Body> block. They should be combined like this for your <cfhttp> call:
<cfset UserName = "[XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX]XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX" />
<cfset Password = "SuperSecret" />
<cfscript>
strNonce = ToBase64(createUUID());
</cfscript>
<!--- create the request body XML block --->
<cfsavecontent variable="request_xml">
<cfoutput>
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.docusign.net/API/3.0">
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>#UserName#</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0##PasswordText">#Password#</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0##Base64Binary">#strNonce#</wsse:Nonce>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<ns:CreateEnvelopeFromTemplates>
<ns:TemplateReferences>
<ns:TemplateReference>
<ns:TemplateLocation>Server</ns:TemplateLocation>
<ns:Template>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</ns:Template>
<ns:RoleAssignments>
<ns:RoleAssignment>
<ns:RoleName>Company</ns:RoleName>
<ns:RecipientID>1</ns:RecipientID>
</ns:RoleAssignment>
</ns:RoleAssignments>
</ns:TemplateReference>
</ns:TemplateReferences>
<ns:Recipients>
<ns:Recipient>
<ns:ID>1</ns:ID>
<ns:UserName>Fred Flintstone</ns:UserName>
<ns:Email>fred.flintstone#...</ns:Email>
<ns:Type>Signer</ns:Type>
<ns:RoleName>Caveman</ns:RoleName>
<ns:RoutingOrder>1</ns:RoutingOrder>
</ns:Recipient>
</ns:Recipients>
<ns:EnvelopeInformation>
<ns:AccountId>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</ns:AccountId>
<ns:EmailBlurb>This Envelope was sent through the DocuSign API using ColdFusion</ns:EmailBlurb>
<ns:Subject>DocuSign it! using ColdFusion</ns:Subject>
</ns:EnvelopeInformation>
<ns:ActivateEnvelope>true</ns:ActivateEnvelope>
</ns:CreateEnvelopeFromTemplates>
</soap:Body>
</soap:Envelope>
</cfoutput>
</cfsavecontent>
(This example was taken directly from their documentation. I only combined the two blocks.)
Then send that request (from their example):
<!--- send the request to the DocuSign service --->
<cfhttp url="https://demo.docusign.net/api/3.0/api.asmx" method="post" result="http_response">
<!--- make sure you set this correctly for the call you are making --->
<cfhttpparam type="header" name="SOAPAction" value="http://www.docusign.net/API/3.0/CreateEnvelopeFromTemplates" />
<cfhttpparam type="header" name="accept-encoding" value="no-compression" />
<cfhttpparam type="xml" value="#trim(request_xml)#" />
</cfhttp>
And finally handle the response (from their example):
<!--- if we received a successful response --->
<cfif find("200", http_response.statusCode)>
<cfscript>
response_xml = xmlParse(http_response.fileContent);
// use XPath to get the top level element you want from the SOAP response
result_node = xmlSearch(response_xml, "//*[local-name() = 'CreateEnvelopeFromTemplatesResult']")[1];
// use dot notation to navigate the XML structure
envelope_id = result_node.EnvelopeID.xmlText;
</cfscript>
<cfoutput>
EnvelopeID: #envelope_id#
</cfoutput>
<cfelse>
<cfoutput>
An error occurred!
</cfoutput>
<cfdump var="#http_response#">
</cfif>
If this is a POST request (submitting data), it looks as though the webservice is not recognising the submission of the actual SOAP XML file.
Are you sending the XML as an XML type as shown in the documentation?
<cfhttpparam type="xml" value="#trim(request_xml)#" />
The RoleAssignment tags are used for assigning your recipient to a particular template role. When you send an envelope that uses a template, you are referencing a template that you have created through the DocuSign console (demo.docusign.net). When you created the template, you had to specify at least one template role for the template, which contains a role name, recipient name, and recipient email. The value you use for the role here needs to match the role name you provide in the api call. So if you called your role "Signer1" for instance, you need to have
<ns:RoleName>Signer1</ns:RoleName>
If you named the role "Company" the keep like you have it.
Related
I'm trying to test the Bloomberg webservice for the getFields operation but its throwing an error.
Web service parameter name parameters cannot be found in the provided parameters {CRITERIA}.
Code so far.
<cfset FieldSearchCriteria = structNew()>
<cfset FieldSearchCriteria.mnemonic = "NAME">
<cfset GetFieldsRequest = structNew()>
<cfset getFieldsRequest.criteria = FieldSearchCriteria>
<cfinvoke
webservice="https://service.bloomberg.com/assets/dl/dlws.wsdl"
proxyserver="***"
proxyport="***"
proxyuser="***"
proxypassword="***"
method="getFields"
refreshwsdl="false"
wsVersion="1"
argumentcollection="#getFieldsRequest#"
returnvariable="aTemp">
<cfdump var="#aTemp#">
Below is the corresponding soapUI request which worked
<soapenv:Body>
<ns:getFieldsRequest>
<ns:criteria>
<!--Optional:-->
<ns:mnemonic>NAME</ns:mnemonic>
</ns:criteria>
</ns:getFieldsRequest>
Any pointers?
Update 1: createobject() worked to an extent with the change in arguments. But now throwing the handshake error.
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Code:
<cfscript>
ws = createObject("webservice", "https://service.bloomberg.com/assets/dl/dlws.wsdl",{refreshwsdl=true,proxyserver="***",proxyport="***",proxyuser="***",proxypassword="***",wsversion=1});
//show web service methods for debugging purposes
//writeDump(ws);
// construct arguments
args = {parameters={criteria={mnemonic="NAME"}}
};
writeDump(args);
// call the method
result = ws.getFields(argumentCollection=args);
writeDump(result)
</cfscript>
We were given a x.509 .p12 certificate and have encoded to DER using OpenSSL.
At the moment, not sure if the stored certificate has an issue.
Final Update:
Finally, managed to make the webservice run using the cfhttp call instead.
Ben's blog post was an excellent guide. I was unable to resolve the certificate issues with the keystore for cfinvoke.
<cfsavecontent variable="soapBody">
<soapenv:Envelope
xxmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://services.bloomberg.com/datalicense/dlws/ps/20071001">
<soapenv:Header/>
<soapenv:Body>
<ns:getFieldsRequest>
<ns:criteria>
<!--Optional:-->
<ns:mnemonic>NAME</ns:mnemonic>
</ns:criteria>
</ns:getFieldsRequest>
</soapenv:Body>
</soapenv:Envelope>
<cfhttp
url="https://dlws.bloomberg.com/dlps"
method="post"
result="httpResponse"
clientcert="#ExpandPath(".")#\cert.p12"
clientcertpassword="****">
<!---
Most SOAP action require some sort of SOAP Action header
to be used.
--->
<cfhttpparam
type="header"
name="SOAPAction"
value="""getFields"""
/>
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
</cfhttp>
<cfdump var="#XmlParse(httpResponse.filecontent)#">
Try using createObject() and invoking the getFields() method instead. It seemed to get past the "cannot find parameter error".
<cfset svc = createObject("webservice"
, "https://service.bloomberg.com/assets/dl/dlws.wsdl"
, {wsVersion=1}
)>
<cfset getFieldsRequest = {criteria={mnemonic="NAME"}}>
<cfset result = svc.getFields(getFieldsRequest)>
<cfdump var="#result#">
(Nothing to do with the issue, but CF11 supports the shortcut syntax for structures, i.e. {})
Managed to make the webservice run using the cfhttp call instead. Ben's blog post was an excellent guide. I was unable to resolve the certificate issues with the keystore for cfinvoke method.
<cfsavecontent variable="soapBody">
<soapenv:Envelope
xxmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns="http://services.bloomberg.com/datalicense/dlws/ps/20071001">
<soapenv:Header/>
<soapenv:Body>
<ns:getFieldsRequest>
<ns:criteria>
<!--Optional:-->
<ns:mnemonic>NAME</ns:mnemonic>
</ns:criteria>
</ns:getFieldsRequest>
</soapenv:Body>
</soapenv:Envelope>
<cfhttp
url="https://dlws.bloomberg.com/dlps"
method="post"
result="httpResponse"
clientcert="#ExpandPath(".")#\cert.p12"
clientcertpassword="****">
<!---
Most SOAP action require some sort of SOAP Action header
to be used.
--->
<cfhttpparam
type="header"
name="SOAPAction"
value="""getFields""" <!--- Note : extra pair of quotes are required --->
/>
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
Twilio newbie here.
I have a Twilio voice application that collects a bunch of data (international topup sales) - and there is a point where the actual process of purchasing the topup takes place.
This process can last anywhere from 10 to 30 seconds, where most of them are about 15 seconds. Sounds to me like I need to use the Twilio <ENQUEUE> tag (https://www.twilio.com/docs/voice/twiml/enqueue), but it does not work.
I am simply calling it like this (happens to be ColdFusion):
<Enqueue
waitUrl="processtopup.cfm"
method="POST"
action="topupdone.cfm">processTopup</Enqueue>
Within the processtopup.cfm file is the <PLAY> tag (which won't work because that is the page that takes more than 15 seconds.
Sorry - but I'm just confused on ho this should work. Thanks in advance!
Here is a possible solution. I've tested this and it works.
The main idea is to play some message/music in a loop until ColdFusion does the job, then, when ColdFusion is done, instruct the call to execute a different Twilio XML by making a POST request to Twilio's API call resource.
When a call comes in, and Twilio hits your endpoint, capture the call id, it will be used to switch the call to a different XML. The call id it's passed as FORM.CALLSID or URL.CALLSID depending on your webhook configuration at Twilio.
The call id looks something like CAdecbfa7e8e2a9d09336abcd57044cf74.
Pass the call id trough your flow (as url parameter should be fine) so it reaches processtopup.cfm.
Move the long running code from processtopup.cfm to let's say
processtopup-action.cfm
Code in processtopup.cfm should now return immediately XML for playing loop (or you can play some .mp3), I'm showing with a message:
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say loop="0">Please wait while we process your request...</Say>
</Response>
</cfoutput>
<cfhttp
url="http://www.yourwebsite.com/processtopup-action.cfm?callsid=#FORM.CALLSID#"
method="get"
timeout="1" />
The code for processtopup-action.cfm
<!--- // place your long running code here --->
<cfset accountSid = '{your account sid}' />
<cfset authToken = '{your auth token}' />
<cfhttp
url="https://api.twilio.com/2010-04-01/Accounts/#variables.accountSid#/Calls/#URL.CALLSID#.json"
method="POST"
username="#variables.accountSid#"
password="#variables.authToken#"
result="http_result">
<cfhttpparam
name="Url"
value="http://www.yourwebsite.com/finish.cfm"
type="formfield" />
</cfhttp>
Code for finish.cfm
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>This is the data you're looking for.</Say>
<Say>Thank you. Goodbye!</Say>
<Hangup />
</Response>
</cfoutput>
Of course, you can pass other parameters as you need.
Again, the main idea is that processtopup-action.cfm, after executing your long running code, makes a POST request to Twilio's API and instructs the call to switch to execute new TwiML located at http://www.yourwebsite.com/finish.cfm
Docs:
Call Redirection via the Twilio REST API
(https://www.twilio.com/blog/2009/09/call-queueing-putting-callers-on-hold-calll-redirect-new-url-new-feature.html)
Modifying Live Calls
(https://www.twilio.com/docs/voice/modify-live-calls)
I am trying to run a webservice using coldfusion. I can run the wsdl in the browser fine. When I try to run it via coldfusion I get:
Unable to parse WSDL as an XML document.
Parsing error: Fatal Error: URI=null Line=-1: Premature end of file.
It is recommended that you use a web browser to retrieve and examine the requested WSDL document to ensure it is correct.
I have tried multiple methods:
wsargs.login='******';
wsargs.password='******';
ws = CreateObject("webservice", "https://correcturl.com/dswsbobje/qaawsservices/biws?WSDL=1&cuid-******", wsargs);
req = getSOAPRequest(ws);
</cfscript>
<cfdump var="#req#">
<cfset wsargs = structNew()>
<cfset wsargs["login"]="******">
<cfset wsargs["password"]="******">
<cfinvoke webservice="https://correcturl.com/dswsbobje/qaawsservices/biws?WSDL=1&cuid=******"
method="runQueryAsAService"
returnvariable="results"
argumentCollection="#wsargs#">
</cfinvoke>
<cfinvoke webservice="https://correcturl.com/dswsbobje/qaawsservices/biws?WSDL=1&cuid=******"
method="runQueryAsAService"
returnvariable="results">
<cfinvokeargument name="login" value="******"/>
<cfinvokeargument name="password" value="******"/>
</cfinvoke>
But all give me this error. I have see other related errors and have tried the solutions in them, such as clearing out the Application.cfc/cfm and adding refreshwsdl='true' to the cfinvoke, none of which have done anything. Can anyone help me with this?
Thanks.
I guess I didnt have a full understanding of how this works. The url I was trying to use was to what I guess was the wsdl definition. I ran url an via wizdler ran the method. That then gave me a soap request that I then saved in a cfcsave content tag. My final code that worked looks like:
<cfset strURL = "https://correcturl.com/dswsbobje/qaawsservices/biws?WSDL=1&cuid=******">
<cfsavecontent variable="strXML">
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Header>
<QaaWSHeader xmlns="VendorInfo">
<sessionID>[string?]</sessionID>
<serializedSession>[string?]</serializedSession>
<ClientType>[string?]</ClientType>
<AuditingObjectID>[string?]</AuditingObjectID>
<AuditingObjectName>[string?]</AuditingObjectName>
</QaaWSHeader>
</Header>
<Body>
<runQueryAsAService xmlns="VendorInfoLR">
<login>******</login>
<password>******</password>
</runQueryAsAService>
</Body>
</Envelope>
</cfsavecontent>
<cfhttp url="#strURL#" method="post" useragent="#CGI.http_user_agent#" result="objGet">
<cfhttpparam type="XML" value="#strXML.Trim()#" />
</cfhttp>
Idea from :http://www.experts-exchange.com/Software/Server_Software/Web_Servers/Q_24311762.html
This soap stuff is new to me, and I have more research to do to fully understand it. :)
I have a CFC (call it proxy.cfc) that I'm using as a proxy for a simple API that I've written. Everything has been going along just fine and a few partners are starting to use the API effectively.
However, one site that is attempting to post data isn't sending valid JSON and I can't seem tho figure how to gracefully handle this error.
A valid JSON string that is posted as a URL param may look like this:
{"apicomponent":"proxyRemoteAdd","apimethod":"add","apiarguments":{"ph_num":1212,"rbpid":999,"ph_exch":555,"state":"HI","address_1":"123 Main Street","address_2":"","rmtid":"PON83","last_name":"Smith","test":1,"zip":999999,"first_name":"Joe","email":"test#test.com","city":"Honolulu","type":"SP","ph_area":995},"apiauthkey":"abc123"}
And that works just fine.
However, if that string is truncated for any reason:
{"apicomponent":"proxyRemoteAdd","apimethod":"add","apiarguments":{"ph_num":1212,"rbpid":999,"ph_exch":555,"state":"HI"
I catch an exception as follows: Exception: JSON parsing failure: Unexpected end of JSON string
This is coming from my onError in Application.cfc. I did add some code to isolate it in Application.cfc as follows:
<cfif ARGUMENTS.EXCEPTION.MESSAGE IS "JSON parsing failure: Unexpected end of JSON string">
<!--- do some stuff here --->
</cfif>
Is that the best way to handle that sort of error? Is there anyway to pass it off to the proxy.cfc file so I can return an error message back to the posting client? As it is now the Application.cfc is catching it and not even letting me get to the proxy.cfc file.
UPDATE - here's some specific code samples. This is how I've been testing and will illustrate how the data gets posted:
<cfhttp url="https://www.domain.com/api/proxy.cfc" method="post" result="httpResult" charset="UTF-8">
<cfhttpparam type="url" name="method" value="apiauth"/>
<cfhttpparam type="url" name="argumentCollection" value="#jsData#"/>
</cfhttp>
"apiauth" is the method in the CFC that acts as the authorization and proxy.
The argument collection is a JSON string as shown below. It lists a component (a different CFC), the method in that component, the authkey of the user accessing the AP, and then a JSON string called apiarguments which contains the arguments and data that get passed to the apicomponent listed.
The proxy CFC file looks like this:
<cffunction name="apiauth" access="remote" returntype="any" output="false" returnFormat="JSON">
<cfargument name="apicomponent" required="yes" type="string"/>
<cfargument name="apimethod" required="yes" type="string"/>
<cfargument name="apiauthkey" required="yes" type="string"/>
<cfargument name="apiarguments" required="yes" type="struct"/>
<cfset var LOCAL = {}/>
<cfif not isDefined("ARGUMENTS.apiauthkey")>
<cfreturn THIS.NewErrorResponse("Error 401 Malformed Request.") />
</cfif>
<cfif not isDefined("ARGUMENTS.apicomponent")>
<cfreturn THIS.NewErrorResponse("Error 402 Malformed Request.") />
</cfif>
<cfif not isDefined("ARGUMENTS.apimethod")>
<cfreturn THIS.NewErrorResponse("Error 403 Malformed Request.") />
</cfif>
<cfset LOCAL.checkpwResult = FALSE/>
<cfset LOCAL.apicomponent = ARGUMENTS.apicomponent />
<cfset LOCAL.apimethod = ARGUMENTS.apimethod />
At this point some other CFCs are access to check the API key and user ID # to make sure they can access the API. If everything checks out there the data gets passed off to the correct component/method:
<cfinvoke component="#LOCAL.apicomponent#" method="#LOCAL.apimethod#" argumentcollection="#apiarguments#" returnvariable="LOCAL.Response.Data"/>
However the JSON exception is being thrown before this CFC can even be accessed by the Application.cfc file. If I drop a quick cfmail in proxy.cfc to just dump and mail the arguments it doesn't even hit that.
Here's a chunk of the stack trace:
coldfusion.runtime.JSONUtils$JSONParseOverflowException: JSON parsing failure: Unexpected end of JSON string at
coldfusion.runtime.JSONUtils$ParserState.incrementOffset(JSONUtils.java:1999) at coldfusion.runtime.JSONUtils$ParserState.incrementOffset(JSONUtils.java:1980) at coldfusion.runtime.JSONUtils.parseString(JSONUtils.java:1385) at coldfusion.runtime.JSONUtils.parseObject(JSONUtils.java:1074) at coldfusion.runtime.JSONUtils.parseStruct(JSONUtils.java:1178) at coldfusion.runtime.JSONUtils.parseObject(JSONUtils.java:1059) at coldfusion.runtime.JSONUtils.parseStruct(JSONUtils.java:1178) at coldfusion.runtime.JSONUtils.parseObject(JSONUtils.java:1059) at coldfusion.runtime.JSONUtils.parseJSON(JSONUtils.java:1028) at coldfusion.runtime.JSONUtils.deserializeJSON(JSONUtils.java:168) at coldfusion.runtime.JSONUtils.deserializeJSON(JSONUtils.java:128) at coldfusion.filter.FilterUtils.GetArgumentCollection(FilterUtils.java:50) at coldfusion.filter.ComponentFilter.invoke(ComponentFilter.java:193) at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:442) at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48) at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
coldfusion.filter.PathFilter.invoke(PathFilter.java:112) at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:94) at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28) at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:58) at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at coldfusion.xml.rpc.CFCServlet.invoke(CFCServlet.java:155) at coldfusion.xml.rpc.CFCServlet.doPost(CFCServlet.java:331) at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at
If your argument is always a JSON string, you should be able to change the argument type to string, and pass it in that way (it will make it through Application.cfc) and then validate it within your apiAuth function using isJSON() - you should be validating it against malicious JSON anyways, so it won't be much code to initially check against isJSON(). This way, your API will give meaningful feedback and keep all the code where it should be.
However if you have other users passing an actual struct into your method, that won't work.
And you will definitely want to find out why the JSON string is being truncated. At a guess I would suggest there might be some un-escaped characters being passed in which is truncating the string early...
UPDATED WITH WORKING SOLUTION
I'm trying to integrate the DocuSign API using ColdFusion and keep running into an issue. I am able to authenticate successfully and retrieve the base URL. However, when trying to create the envelope with a single recipient and document, I get an error stating that the "boundary terminator" is not found in the request (when it clearly is).
I know this questions is similar to another post here but that was from a while ago and was never completely answered.
I first read in the PDF document:
<cffile action="READBINARY" file="Agreement.pdf" variable="docData">
<cfset docData = BinaryEncode(docData,"Base64")>
I then create the envelope definition in XML using the element to include the encoded binary PDF data:
<cfset envelope = "<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
<status>Sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<recipientId>1</recipientId>
<name>eCS Buyer</name>
<email>XXX#XXXX.com</email>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>3</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>#docData#</documentBase64>
</document>
</documents>
</envelopeDefinition>">
Lastly, I POST the information:
<cfhttp url="#baseURL#/envelopes" method="POST" resolveurl="Yes" throwonerror="No">
<cfhttpparam name="X-DocuSign-Authentication" type="HEADER" value="<DocuSignCredentials><Username>#userName#</Username><Password>#password#</Password><IntegratorKey>#integratorKey#</IntegratorKey></DocuSignCredentials>">
<cfhttpparam name="Content-Type" type="HEADER" value="application/xml">
<cfhttpparam name="Accept" type="HEADER" value="application/xml">
<cfhttpparam name="Content-Length" type="HEADER" value="#Len(envelope)#">
<cfhttpparam name="request_body" type="BODY" value="#envelope#">
</cfhttp>
I tried changing the TYPE attribute for the request body to XML and FORMFIELD but is still doesn't work. I even tried changing the envelope to JSON format to no avail.
The error that is generated is:
<errorCode>INVALID_REQUEST_BODY</errorCode><message>The request body is missing or improperly formatted. The XML request does not match the expected format. </message></errorDetails>
I have been struggling with this for weeks. Any guidance would be GREATLY appreciated.
Most likely an issue with extra CRLF (i.e., extra line breaks). See the answer in this other forum post for an example of what the full request structure should look like: Docusign : Unable to create envelope from document in restapi v2.
UPDATE #1
Looks like your XML request body is missing information about the Document. Try adding a documents element as a child element of envelopeDefinition (i.e., as a peer element to recipients):
<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
...
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
</document>
</documents>
...
</envelopeDefinition>
Also, make sure the document bytes that your sending in the subsequent part of the request are not encoded.
UPDATE #2
I don't know much about ColdFusion, but this line of your code makes it look like you're (base64) encoding the byte stream that you're including in the Request:
<cfset docData = BinaryEncode(docData,"Base64")>
This could be causing your latest issue, as I don't believe DocuSign will accept an encoded byte stream when it's included in the manner you're currently utilizing.
If you must base64-encode the byte stream, you could add a documentBase64 property under the document element to contain the base64-encoded byte stream. (See page 104 of the DocuSign REST API Guide -- http://www.docusign.com/sites/default/files/REST_API_Guide_v2.pdf.) If you utilized this approach, your request would no longer need to be a 'multipart' request, since the document bytes would be included in the XML portion of the Request Body (not in a subsequent/separate part). Here's an example of what the Request would look like, if the base64-encoded byte stream was included within the documentBase64 element:
POST /restapi/v2/accounts/ACCOUNT_NUMBER/envelopes HTTP/1.1
Host: demo.docusign.net
X-DocuSign-Authentication: {"Username":"SENDER_EMAIL_ADDRESS","Password":"PASSWORD","IntegratorKey":"INT_KEY"}
Content-Type: application/xml
<envelopeDefinition xmlns="http://www.docusign.com/restapi">
<accountId>ACCOUNT_ID</accountId>
<status>sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<email>johnsEmail#outlook.com</email>
<name>John Doe</name>
<recipientId>1</recipientId>
<routingOrder>1</routingOrder>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>1</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>BASE64-ENCODED-BYTE-STREAM</documentBase64>
</document>
</documents>
</envelopeDefinition>
Since the document bytes are included within the XML portion of the request, the request no longer needs to be multi-part -- simply pass the XML Request body as I've shown above, and that's it.
The error is most likely due to the extra CRLF you have after the document bytes and before your closing boundary --MYBOUNDARY--. You have this:
#docData#
--MYBOUNDARY--
Try changing that to this without that extra CRLF:
#docData#
--MYBOUNDARY--
For reference you can check out the DocuSign API Walkthrough for sending a signature request on a document. Each of the different language versions shows you how the outgoing request body should be formatted.