Since DocuSign API have limitations on the max size of 25 MB per request, we have to split our envelope creation into multiple request, initially the envelope will be created as draft. Then the documents will be updated to the same envelope using envelope Documents update call.
However we are getting a 'FORMAT_CONVERSION_ERROR' error for each Word doc I add using multi part request. PDF docs can be added successfully
"errorDetails": {
"errorCode": "FORMAT_CONVERSION_ERROR",
"message": "The data could not be converted."
}
Is there a work around to make it work for multi-part request?
Here are the steps I followed:
I am creating envelope(without documents) in the first POST API call(https://demo.docusign.net/restapi/v2/accounts/{accountid}/envelopes)
Adding documents(both pdf and docx) to the envelope (multipart method) by making PUT API call for each document(https://demo.docusign.net/restapi/v2/accounts/{accountid}/envelopes/{envelopeId}/documents/{docId})
Only PDF files are uploaded to the docusign, whereas getting 400 error "FORMAT_CONVERSION_ERROR - The data could not be converted" error for docx type file upload
I am adding this header "Content-Disposition", "file; filename={filename};fileExtension={ext};documentId={id}"
Any suggestion/solution will be appreciated.
Log details:
PUT https://demo.docusign.net:7801/restapi/v2/accounts/{myaccountid}/envelopes/{myenvelopeid}/documents/1
TraceToken: d0d9eae1-01d3-4c56-928d-da38a7ac30fc
Timestamp: 2020-01-09T08:48:52.7616114Z
Content-Type: multipart/form-data; boundary=LV-qEHBRJq6zprmD52mUZfeNsrT5alHGfkE8w
Content-Disposition: file; filename=MyTemplate.docx; fileExtension=docx; documentId=1
Content-Length: 12998
Connection: Keep-Alive
Transfer-Encoding: chunked
Authorization: bearer [omitted]
Expect: 100-continue
Host: demo.docusign.net
User-Agent: Apache-HttpClient/4.0.3(java 1.5)
X-SecurityProtocol-Version: TLSv1.2
X-SecurityProtocol-CipherSuite: ECDHE-RSA-AES256-GCM-SHA384
x-forwarded-for: 106.51.84.53
--LV-qEHBRJq6zprmD52mUZfeNsrT5alHGfkE8w
Content-Disposition: form-data; name="MyTemplate.docx"; filename="MyTemplate.docx"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
//Some binary data here.
--LV-qEHBRJq6zprmD52mUZfeNsrT5alHGfkE8w--
400 BadRequest
Content-Type: application/json; charset=utf-8
Content-Length: 96
X-DocuSign-TraceToken: d0d9eae1-01d3-4c56-928d-da38a7ac30fc
{
"errorCode": "FORMAT_CONVERSION_ERROR",
"message": "The data could not be converted."
}
Few things to check:
Does this happen with any word document or just a specific one?
Can you upload the same Word document directly to DocuSign web app and it works fine?
how large is the file in question? Is it possible it's still over 25M?
Consider using binary file transfer. Here is an example of code showing you how to do this:
https://developers.docusign.com/esign-rest-api/code-examples/code-example-send-binary
You can use multi-part mime encoding of the envelope with the individual files either BASE64 encoded or sent in binary format.
Check that you're using binary format and that the entire request to DocuSign is not over 25 MB.
Download and run a version of the eg-03- example software repository for your favorite language. These repos are stored in github.com/docusign they are documented here: https://developers.docusign.com/esign-rest-api/code-examples/code-example-send-binary.
Within the example code, workflow #10 shows how to send in binary mode. The example sends a Word document so you can substitute your own to check that it works ok.
I'm working on a chatbot project. I want users to be able to enter list items onto a Google Sheet. The chatbot is on DialogFlow, I created the intent, and toggled the webhook on. I am now in Google Cloud Functions and creating a function to POST the new item on the google sheet. I have already been successfully able to read (GET) the list of items from the sheet to be displayed to the user in the chatbot.
I am new to nodejs and admittedly don't know much about Oauth, but I set my sheet to be able to be edited by anyone on the internet and I have a working API key as well. To try to just get down to basics, I went on https://apitester.com to test the HTTP request there. I can GET a response easily that returns the list of items I already have. However, my POST response is still returning issues, although the site did indicate that the request "PASS"ed.
My POST request
https://sheets.google.com/v4/spreadsheet/<SPREADSHEETID>/values/A1:append?includeValuesInResponse=true&key=<MY_API_KEY>
where <SPREADSHEETID> and <MY_API_KEY> match my credentials.
My request body:
{
"values": [ ["Hello", "World"] ],
"range": "Sheet1!A1:B1",
"majorDimension": "ROWS"
}
Response:
HTTP/1.1 301 Moved Permanently
Location: https://docs.google.com/spreadsheets?usp=direct_url
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Thu, 18 Oct 2018 07:31:14 GMT
Expires: Sat, 17 Nov 2018 07:31:14 GMT
Cache-Control: public, max-age=2592000
Server: sffe
Content-Length: 248
X-XSS-Protection: 1; mode=block
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
I looked up the 301 error code and found that it is a redirection message that signifies a server-side error. I read that it should be self-fixing as your request will just be-redirected to the appropriate site in the Location value above. But I also copied the Location link and found it just took me to my personal Google Drive. I read elsewhere that this may occur because Google is communicating over a secure link. I checked my Google sheet just in case, but nothing had changed there.
Anyway, is it possible to test the append request before I code it into my Google Cloud Function? If so, where can I test and how can I make sure that the request goes through (with hopefully just an API key and no Oauth creds)?
I tried doing this on the documentation page (https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append) ("Try This API" on the right-hand side) but I just get a never-ending red progress circle.
Please help! If the only answer is Oauth, please help me past directing me to the Oauth documentation, as I have not found that very helpful.
Thank you!
EDIT 1
Okay, I have been trying some things out. Oauth playground wasn't working for me, but this website (https://developers.google.com/apis-explorer/#p/sheets/v4/sheets.spreadsheets.values.append) allowed me to POST a new row to my spreadsheet. (I had to toggle Authorize OAuth 2.0 to ON.)
So now I have the Oauth working, how can I translate this into my Google Cloud Function using node.js? Do I save my Oauth tokens to certain variables and then add them to headers?
I tried to add webhook in servicem8 as the document at http://developer.servicem8.com/docs/platform-services/webhooks/
But i got this error {"success":false,"message":"Object material does not support subscription"} .
I tried both job and material object but still same error.
I am using trial account.
Anyone have experience with this , please help.
Here is detail POST via postman
POST /webhook_subscriptions HTTP/1.1
Host: api.servicem8.com
Authorization: {Hide information}
Cache-Control: no-cache
Postman-Token: 64b8e5ea-55c3-6fc9-1936-c19436bd72c9
Content-Type: application/x-www-form-urlencoded
object=jobmaterial&callback_url=http%253A%252F%252Frequestb.in%252Fzkqdd1zk&fields=status
Try varying the object name and see if that solves the issue, instead of material, try Material.
Also ensure your callback_url is a valid and reachable URL, as the webhook subscription will fail if it's not reachable/valid.
I want to find samples of how to work with Mobile/Web App by sending POST.
Previously in Mobile Services it was possible to send POST like this:
POST /tables/table_name HTTP/1.1
Host: http://arduinounoserver.azure-mobile.net/
X-ZUMO-APPLICATION: YaRWxxxxzKGRxxxxLPiNxxxxXYOvxxxx
{"value": 234}
But now authentication was absolutely changed.
How to do it now and is it possible to find somewhere POST samples?
Have found only Table Service REST API but it's still not clear for me
you can still use next URL notation to access tables:
https://yoursite/tables/tablename
but, you can get an error:
{"error":"An invalid API version was specified in the request, this request needs to specify a ZUMO-API-VERSION of 2.0.0."}
so with Web App Easy Table you should use next ZUMO-header, for example
POST https://vyutest.azurewebsites.net/Tables/Test HTTP/1.1
Accept: application/json
Content-Type: application/json
Content-Length: 49
ZUMO-API-VERSION: 2.0.0
Host: vyutest.azurewebsites.net
{"text":"Complete the tutorial","complete":false}
It works.
I am developing SharePoint 2013 Provider hosted app using javascript REST Api. In order to perform create (POST), or update (MERGE) operations on sharepoint items I need to set the 'X-RequestDigest' header with the request.
When in SharePoint-hosted apps I was able to use the http://contoso.sharepoint.com/SharePointHostedApp/_api/contextinfo service to retrieve the request digest value; however, I am having trouble getting that value when in a provider hosted app.
The first difference of provider hosted app is that now we need to make a cross-domain request since we are not running in a sharepoint site, but in a different domain hosted on a different server. To be clear: instead of
$.ajax({
url: appWebUrl + '/_api/contextinfo',
method: "POST",
headers: { "Accept": "application/json; odata=verbose" }
})
I assumed we need to use the SP.RequestExecutor to execute a cross domain request.
When I construct the request it looks like the following (I've changed the actual urls to something fake, but basically we're telling the proxy to use the host web has the target and get the /_api/contextinfo endpoint):
https://contoso-6f921c6addc19f.sharepoint.com/ProviderHostedApp/_api/SP.AppContextSite(#target)/contextinfo?#target=%27https://contoso.sharepoint.com%27
However, I receive this error: Cannot find resource for the request contextinfo. meaning that the endpoint does not exist.
I made sure to use the POST method with the correct application/json;odata=verbose headers with an empty body.
How do I get the request digest value from the /_api/contextinfo service to the provider hosted app?
Based on what I've researched:
We can't use $('#__REQUESTDIGEST').val(); because that is not available to a provider hosted app.
We need to use some from of cross-domain request since I'm running outside of sharepoint.
I have tried setting the target of the cross-domain request to both the hostWebUrl and the appWebUrl and both give the same error.
There must be some way to get this value, otherwise we would only be limited to read operations when using JavaScript. Has anyone else solved this using javascript?
Technically I could try to implement the needed services using the CSOM on server and exposing them using WebAPI or WCF but it seem unreasonable to have to implement that.
UPDATE:
I went ahead and tried adding a WebAPI controller which exposes a service that retrieves the request digest value. This actually does retrieve a request digest value; however, when attempting to use this in the header of future calls I receive the error: "The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again." I'm guessing that the request digest value has some referer header information in it which indicates it was requested by the server; however, the future requests made with it are from the browser, and this mismatch might be an acceptable reason for it be invalid.
Few more notes on the attempt at adding the webAPI controller.
I based my code off of this example: http://code.msdn.microsoft.com/SharePoint-2013-Perform-335d925b but converted it to use the newer HttpClient.
I overloaded the Page_Load method, stored the contextTokenString in a variable that could be accessed by the WebAPI controller then parsed/used it when requesting the contextinfo.
Does anyone know if this is a correct diagnosis of that error? Is there something encoded in the request digest value that would prevent it from be able to be retrieved like I suggested?
I have also opened a related question on the MSDN forums since I'm desperate to find an answer:
http://social.msdn.microsoft.com/Forums/sharepoint/en-US/f601fddd-3747-4152-b2d1-4e89f0a771c4/question-about-limitation-of-providerhosted-apps-is-it-possible-to-make-rest-calls-with-javascript?forum=sharepointdevelopmentprevious
I find it very hard to believe this could be a limitation of provider hosted applications, but given all testing I've done, I'm starting to doubt the viability of provider-hosted applications when you want to write in javascript.
Begging for Help!
I realize you've already answered your own question within the context of a provider-hosted app, but for developers like myself who need to access the REST API from a language not based in the .NET framework, (and who cannot write their project as a web app) I'd like to expand on the subject a bit more. I was tasked with writing an iPad app recently that required this functionality, and ended up reverse-engineering the following:
Step 1 - Authentication
Not going to actually cover this, as there are plenty of examples online that demonstrate the more common methods. The Microsoft.SharePoint.Client libraries mostly seem to use claims-based authentication when working with SharePoint Online, with the token being requested through the endpoint found at: https://login.microsoftonline.com/RST2.srf
Step 2 - Acquiring the Request Digest (Dumb Approach)
If you're feeling lazy, you can always take your authenticated cookies, make a GET request to the homepage of the target web, and use a regular expression like:
/(<input (?:[^>]*?)name="?__REQUESTDIGEST"?(?:[^>]*?)\/>)/i
to scrape the HTML from the response. From there, it'd just be a matter of extracting the value attribute for your digest.
Step 2 - Acquiring the Request Digest (SOAP Approach)
The CSOM libraries currently use a SOAP endpoint when acquiring the request digest it uses for its API calls. You can do the same by making a SOAP request to the $(SPWebUrl)/_vti_bin/sites.asmx web service similar to the following:
POST $(SPWebUrl)/_vti_bin/sites.asmx HTTP/1.1
Content-Type: text/xml
SOAPAction: http://schemas.microsoft.com/sharepoint/soap/GetUpdatedFormDigestInformation
X-RequestForceAuthentication: true
Host: $(SPSiteHostname)
Expect: 100-continue
Accept-Encoding: gzip, deflate
Cookie: $(Authenticated Cookies - Either "FedAuth=...; rtFa=..." or "SPOIDCRL=...")
Content-Length: $(Whatever)
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetUpdatedFormDigestInformation xmlns="http://schemas.microsoft.com/sharepoint/soap/" />
</soap:Body>
</soap:Envelope>
When executed successfully, the response body will look something like:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUpdatedFormDigestInformationResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<GetUpdatedFormDigestInformationResult>
<DigestValue>0x1122334455 ... FF,27 Jul 2015 03:06:54 -0000</DigestValue>
<TimeoutSeconds>1800</TimeoutSeconds>
<WebFullUrl>$(SPWebUrl)</WebFullUrl>
<LibraryVersion>16.0.3208.1222</LibraryVersion>
<SupportedSchemaVersions>14.0.0.0,15.0.0.0</SupportedSchemaVersions>
</GetUpdatedFormDigestInformationResult>
</GetUpdatedFormDigestInformationResponse>
</soap:Body>
</soap:Envelope>
At that point, you can just extract your request digest from the DigestValue block.
Step 2 - Acquiring the Request Digest (REST Approach)
The last approach I'm aware of uses an OData request made to the $(SPWebUrl)/_api/contextinfo endpoint:
POST $(SPWebUrl)/_api/contextinfo HTTP/1.1
Host: $(SPSiteHostname)
DataServiceVersion: 3.0
Accept: application/json; odata=nometadata
Content-Type: application/json; odata=verbose
Cookie: $(Authenticated Cookies)
Content-Length: 2
{}
When executed successfully, the response body will look like the following:
{
"FormDigestTimeoutSeconds" : 1800,
"FormDigestValue" : "0x1122334455 ... FF,27 Jul 2015 03:06:54 -0000",
"LibraryVersion" : "16.0.4230.1217",
"SiteFullUrl" : "$(SPSiteUrl)",
"SupportedSchemaVersions" : ["14.0.0.0", "15.0.0.0"],
"WebFullUrl" : "$(SPWebUrl)"
}
The request digest can then be extracted from the FormDigestValue property.
Step 2 - Acquiring the Request Digest (CSOM Approach)
If you're using CSOM, you have functionality for dealing with this built-in. (probably JSOM, too, unless it uses the __REQUESTDIGEST input) Microsoft.SharePoint.Client.ClientContext uses the SOAP approach internally to manage its request digest and publicly exposes this functionality through its GetFormDigestDirect method.
ClientContext clientContext = new ClientContext(webUrl);
// ...
FormDigestInfo formDigest = clientContext.GetFormDigestDirect();
// X-RequestDigest header value
string headerValue = formDigest.DigestValue;
// Digest expiration
DateTime expirationDate = formDigest.Expiration;
Usage Notes: While ClientContext maintains and reuses a cached form digest for its requests, this method does not give you access to that cached value. Instead, this method requests a brand new form digest with each call, so you'll want to setup your own caching mechanism in order to re-use unexpired digests across multiple requests.
Step 2 - Acquiring the Request Digest (JSOM Approach)
If you're using the JSOM API and don't have access to a __REQUESTDIGEST input value, you can access the ClientContext's cached digest with the following extensions. (Thanks to bdimag for pointing out the cache)
Step 3 - Acquiring New Request Digests
Assuming you use the request digest before the TimeoutSeconds have elapsed, a valid REST request made like the following:
POST $(SPWebUrl)/_api/web/lists/getByTitle('MyList')/getchanges HTTP/1.1
Host: $(SPSiteHostname)
DataServiceVersion: 3.0
Accept: application/json; odata=nometadata
Content-Type: application/json; odata=verbose
X-RequestDigest: $(Request Digest)
Cookie: $(Authenticated Cookies)
Content-Length: 140
{
"query" : {
"__metadata" : {
"type" : "SP.ChangeQuery"
},
"Add" : "True",
"Item" : "True",
"Update" : "True"
}
}
should result in a successful response. If you inspect the headers of that response, you'll find something like:
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: application/json;odata=fullmetadata;streaming=true;charset=utf-8
...
X-RequestDigest: 0xAABBCC...00,03 Sep 2014 18:09:34 -0000
...
Extracting the X-RequestDigest response header will allow you to use it in a subsequent call. (I'm guessing that the timeout starts over from the time of your new response + $(TimeoutSeconds) from the original digest request, but I've yet to confirm)
Unfortunately, the X-RequestDigest header is only returned by REST requests that actually require a request digest. You will not receive the header for requests where a request digest is unrequired, such as: $(SPWebUrl)/_api/web/lists/getByTitle('MyList')/items. Should you find yourself needing a new digest after the original has timed out, you'll need to make another request to the $(SPWebUrl)/_vti_bin/sites.asmx web service.
Step ??? - Handling Errors
A few example responses from when our requests fail:
The following response comes from a REST request made to the $(SPWebUrl)/_api/contextinfo endpoint. (no authentication cookies specified)
HTTP/1.1 403 Forbidden
Cache-Control: private, max-age=0
Content-Type: application/json;odata=nometadata;charset=utf-8
...
Server: Microsoft-IIS/8.5
X-SharePointHealthScore: 0
X-Forms_Based_Auth_Required: $(SPRootSiteUrl)/_forms/default.aspx?ReturnUrl=/_layouts/15/error.aspx&Source=%2f_vti_bin%2fclient.svc%2fcontextinfo
X-Forms_Based_Auth_Return_Url: $(SPRootSiteUrl)/_layouts/15/error.aspx
X-MSDAVEXT_Error: 917656; Access+denied.+Before+opening+files+in+this+location%2c+you+must+first+browse+to+the+web+site+and+select+the+option+to+login+automatically.
DATASERVICEVERSION: 3.0
X-AspNet-Version: 4.0.30319
X-IDCRL_AUTH_PARAMS_V1: IDCRL Type="BPOSIDCRL", EndPoint="$(SiteRelativeUrl)/_vti_bin/idcrl.svc/", RootDomain="sharepoint.com", Policy="MBI"
...
Date: Wed, 12 Aug 2015 02:27:35 GMT
Content-Length: 201
{
"odata.error" : {
"code" : "-2147024891, System.UnauthorizedAccessException",
"message" : {
"lang" : "en-US",
"value" : "Access denied. You do not have permission to perform this action or access this resource."
}
}
}
Next, a response originating from a REST request made with an expired request digest (Note the X-RequestDigest header specified in the response.. Not sure if that's usable, but it's worth a shot):
HTTP/1.1 403 FORBIDDEN
Cache-Control: private, max-age=0
Content-Type: application/json;odata=fullmetadata;charset=utf-8
...
Server: Microsoft-IIS/8.5
Set-Cookie: rtFa=$(RtfaAuthCookie)
Set-Cookie: FedAuth=$(FedAuth)
X-SharePointHealthScore: 0
X-RequestDigest: 0x19EFFF80617AB2E48B0A9FF0ABA1440B5301E7445F3859177771BF6A39C7E4A74643108D862505A2C99350B0EDB871EF3DDE960BB68060601268818027F04956,12 Aug 2015 02:39:22 -0000
DATASERVICEVERSION: 3.0
X-AspNet-Version: 4.0.30319
...
Date: Wed, 12 Aug 2015 02:39:22 GMT
Content-Length: 253
{
"odata.error" : {
"code" : "-2130575251, Microsoft.SharePoint.SPException",
"message" : {
"lang" : "en-US",
"value" : "The security validation for this page is invalid and might be corrupted. Please use your web browser's Back button to try your operation again."
}
}
}
Ok, I made a fresh provider hosted application to re-test the problem.
You can view the repository here:
https://github.com/mattmazzola/providerhosted_01
After comparing this new application and the old one, I realized I had a misunderstanding of how the SP.RequestExecutor expected urls to be constructed. I thought it was required to use the SP.AppContextSite() endpoint.
I was incorrectly constructing a request to the appWeb with a url similar to the following:
https://contoso-6f921c6addc19f.sharepoint.com/ProviderHostedApp/_api/SP.AppContextSite(#target)/contextinfo?#target=%27https%3A%2F%2Fcontoso-6f921c6addc19f.sharepoint.com%2FProviderHostedApp%27
As you can see, the #target was set to the appWeb url but infact when making request to the appWeb using RequestExecutor you do no need to do this. It is simply appweburl + "/_api/contextinfo". It is only when making requests for resources existing on the hostWeb that you need use the AppContextSite and set the #target.
You can see the full code in the linked solution for more details. I have added a screenshot of the solution.
You mus remember that in permissions level exist a check that disable all service under _api
_api/web/lists
_api/search/query?querytext=’SharePoint’
_api/SP.UserProfiles.PeopleManager
You enable that ensure
site settings->site permissions->permissions level->read->
Integration client features
Use remote interface
I found the solution in
https://letrasandnumeros.com/2017/02/28/unauthorizedaccessexception-sharepoint-_api/
The RequestExecutor actually takes care of the RequestDigest for you. You don't have to get it.
If for some reason, you still want to get the RequestDigest value, try doing the call without changing the context site.