Skip to main content
Participant
November 1, 2024
Question

Struggeling with Formfileds on an agreement

  • November 1, 2024
  • 1 reply
  • 822 views

Hi all, I am really struggeling with getting the formfields working from a custom C# app, I have tried adding the formfiels on create of the agreement and nothing show, I have tried the Post and the PUT on "

https://api.na3.adobesign.com:443/api/rest/v6/agreements/{agreementID}/formFields
"Post" returs error "Invalid Agreement ID"

Put Just does not add antying on the agreement, I always only get a signature box on the last page, I want a signature box on each page for mutiple documents, please see my nethod as cureent:

public async Task<string> UploadDocumentsReturnAgreementId(string _OauthUrl, string _ClientId, string _ClientSecret, string _RefreshToken, string _initialApiAccessPoint, string _apiUserEmail, string pstrDelimitedDocumentPaths, string pstrToEmail, long pintProcessInstanceID)
{
try
{
TimeSpan currentTimeOnly = DateTime.Now.TimeOfDay;
string[] larrDocumentPaths = pstrDelimitedDocumentPaths.Split('|');
List<string> pstrDocumentPaths = new List<string>(larrDocumentPaths);

_bearerToken = RefreshToken(_OauthUrl, _ClientId, _ClientSecret, _RefreshToken);
_apiAccessPoint = await GetApiAccessPoint(_initialApiAccessPoint, _bearerToken);
_apiAccessPoint = _apiAccessPoint.Replace(".com/", ".com");

var transientDocumentIds = new List<string>();
var pageCounts = new List<int>();

// Upload documents and get transient document IDs
foreach (var documentPath in pstrDocumentPaths)
{
if (!String.IsNullOrEmpty(documentPath))
{
var pageCount = GetPageCount(documentPath);
pageCounts.Add(pageCount);

var request = (HttpWebRequest)WebRequest.Create($"{_apiAccessPoint}/api/rest/v6/transientDocuments");
request.Method = "POST";
request.Headers["Authorization"] = $"Bearer {_bearerToken}";
request.Headers["x-api-user"] = "email:" + _apiUserEmail;

var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
request.ContentType = $"multipart/form-data; boundary={boundary}";

using (var requestStream = request.GetRequestStream())
{
var fileHeader = Encoding.ASCII.GetBytes($"\r\n--{boundary}\r\nContent-Disposition: form-data; name=\"File\"; filename=\"{Path.GetFileName(documentPath)}\"\r\nContent-Type: application/octet-stream\r\n\r\n");
requestStream.Write(fileHeader, 0, fileHeader.Length);

var fileBytes = File.ReadAllBytes(documentPath);
requestStream.Write(fileBytes, 0, fileBytes.Length);

var boundaryBytes = Encoding.ASCII.GetBytes($"\r\n--{boundary}--\r\n");
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
}

using (var response = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
var responseContent = reader.ReadToEnd();
var transientDocumentId = JObject.Parse(responseContent)["transientDocumentId"].ToString();
transientDocumentIds.Add(transientDocumentId);
}
}
}

// Create agreement without form fields
var agreementRequest = (HttpWebRequest)WebRequest.Create($"{_apiAccessPoint}/api/rest/v6/agreements");
agreementRequest.Method = "POST";
agreementRequest.Headers["Authorization"] = $"Bearer {_bearerToken}";
agreementRequest.Headers["x-api-user"] = "email:" + _apiUserEmail;
agreementRequest.ContentType = "application/json";

var fileInfos = transientDocumentIds.Select(id => new { transientDocumentId = id }).ToArray();

var agreementBody = new
{
fileInfos = fileInfos,
name = "FC Agreement " + pintProcessInstanceID.ToString() + "-" + currentTimeOnly.ToString(),
participantSetsInfo = new[]
{
new
{
memberInfos = new[] { new { email = pstrToEmail } },
order = 1,
role = "SIGNER"
}
},
signatureType = "ESIGN",
state = "AUTHORING"
};

using (var agreementStream = agreementRequest.GetRequestStream())
{
var bodyBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(agreementBody));
agreementStream.Write(bodyBytes, 0, bodyBytes.Length);
}

string agreementId;
using (var agreementResponse = (HttpWebResponse)agreementRequest.GetResponse())
using (var reader = new StreamReader(agreementResponse.GetResponseStream()))
{
var agreementResponseContent = reader.ReadToEnd();
agreementId = JObject.Parse(agreementResponseContent)["id"].ToString();
}

// Use PUT request for form fields with new schema
var formFieldsRequest = (HttpWebRequest)WebRequest.Create($"{_apiAccessPoint}/api/rest/v6/agreements/{agreementId}/formFields");
formFieldsRequest.Method = "PUT";
formFieldsRequest.Headers["Authorization"] = $"Bearer {_bearerToken}";
formFieldsRequest.Headers["x-api-user"] = "email:" + _apiUserEmail;
formFieldsRequest.ContentType = "application/json";

var fields = new List<object>();
for (int i = 0; i < transientDocumentIds.Count; i++)
{
int numPages = pageCounts[i];
for (int page = 1; page <= numPages; page++)
{
fields.Add(new
{
locations = new[]
{
new
{
height = 30,
left = 162,
pageNumber = page,
top = 100,
width = 280
}
},
name = $"Signature (Document-{i + 1}, Page-{page})",
alignment = "LEFT",
backgroundColor = "TRANSPARENT",
borderColor = "BLACK",
borderStyle = "SOLID",
borderWidth = 1,
calculated = false,
conditionalAction = new
{
action = "SHOW",
anyOrAll = "ANY",
predicates = new[]
{
new
{
fieldLocationIndex = 1,
fieldName = "test 1",
value = ""
}
}
},
contentType = "SIGNATURE",
inputType = "SIGNATURE",
readOnly = false,
required = true,
visible = true
});
}
}

var formFieldsBody = new { fields };
using (var formFieldsStream = formFieldsRequest.GetRequestStream())
{
var formFieldsBodyBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(formFieldsBody));
formFieldsStream.Write(formFieldsBodyBytes, 0, formFieldsBodyBytes.Length);
}

using (var formFieldsResponse = (HttpWebResponse)formFieldsRequest.GetResponse())
using (var formFieldsReader = new StreamReader(formFieldsResponse.GetResponseStream()))
{
var formFieldsResponseContent = formFieldsReader.ReadToEnd();
Console.WriteLine($"Form fields added: {formFieldsResponseContent}");
}

// Send the agreement for signing
var sendRequest = (HttpWebRequest)WebRequest.Create($"{_apiAccessPoint}/api/rest/v6/agreements/{agreementId}/state");
sendRequest.Method = "PUT";
sendRequest.Headers["Authorization"] = $"Bearer {_bearerToken}";
sendRequest.ContentType = "application/json";

var sendBody = new { state = "IN_PROCESS" };
using (var sendStream = sendRequest.GetRequestStream())
{
var sendBodyBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(sendBody));
sendStream.Write(sendBodyBytes, 0, sendBodyBytes.Length);
}

using (var sendResponse = (HttpWebResponse)sendRequest.GetResponse())
using (var sendReader = new StreamReader(sendResponse.GetResponseStream()))
{
var sendResponseContent = sendReader.ReadToEnd();
Console.WriteLine($"Agreement sent for signing: {sendResponseContent}");
}

return agreementId;
}
catch (Exception ex)
{
return "Error:" + ex.Message;
}
}

 

This topic has been closed for replies.

1 reply

Participating Frequently
November 19, 2024

Struggling with this API as well!

I am assuming you tried debugging this to ensure the agreementId value you obtained was received and extracted correctly, and not blank?

 

I did discover that you need to set the assignee property when you create the form fields. This is a unique ID assigned to the first participant who is signing. You can only get this by using a GET to download the agreement after you created it. It only gets set if you set the status to AUTHORING (which you do). Not sure if this is the correct approach in the absence of any documentation about this.

 

I then run into the issue that when I call the state PUT method to change to IN_PROCESS I get an 'OPERATION_NOT_ALLOWED' (despite the document going out??!).

Community Manager
November 19, 2024

Signature fields indeed need the assignee property to be used. Regular fields don't need to be assigned.
You need the participantSetID which you can get by calling GET/agreements/{agreementId}/members
A successful PUT call moves the agreement to IN_PROGRESS, no need to call the state end point.

 

Participating Frequently
November 21, 2024

Aaaaah..!!!

Wish this was DOCUMENTED or shown in an example using FormFields somewhere! Finally makes sense.

Feedback for your dev team on my experience:

1. Your Swagger JSON is out of date (v1.2). Swagger 2.0 was ten years ago, and it's now OpenAPI.

2. Upgrading it to v2 or v3 shows that it's also invalid: some definitions are missing or differ in casing. I had to manually edit the agreements.json to get it to work.

3. Documentation/examples do need to be updated to be more helpful.

4. A single POST that uploads, creates and sends an Agreement would be a good idea. As it is I have to execute four API calls to send a single agreement if I used form fields, rather than the generators.