lib/docusign_rest/client.rb in docusign_rest-0.1.1 vs lib/docusign_rest/client.rb in docusign_rest-0.2.0
- old
+ new
@@ -1,6 +1,7 @@
require 'openssl'
+require 'open-uri'
module DocusignRest
class Client
# Define the same set of accessors as the DocusignRest module
@@ -125,17 +126,17 @@
# password - password of user authenticating
#
# Examples:
#
# client = DocusignRest::Client.new
- # response = client.get_token('someone@example.com', 'p@ssw0rd01')
+ # response = client.get_token(integrator_key, 'someone@example.com', 'p@ssw0rd01')
#
# Returns:
# access_token - Access token information
# scope - This should always be "api"
# token_type - This should always be "bearer"
- def get_token(account_id, email, password)
+ def get_token(integrator_key, email, password)
content_type = { 'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json' }
uri = build_uri('/oauth2/token')
request = Net::HTTP::Post.new(uri.request_uri, content_type)
request.body = "grant_type=password&client_id=#{integrator_key}&username=#{email}&password=#{password}&scope=api"
@@ -186,11 +187,11 @@
def get_account_id
unless acct_id
response = get_login_information.body
hashed_response = JSON.parse(response)
login_accounts = hashed_response['loginAccounts']
- acct_id ||= login_accounts.first['accountId']
+ @acct_id ||= login_accounts.first['accountId']
end
acct_id
end
@@ -219,11 +220,14 @@
name: signer[:name],
email: signer[:email],
roleName: signer[:role_name],
tabs: {
textTabs: get_signer_tabs(signer[:text_tabs]),
- checkboxTabs: get_signer_tabs(signer[:checkbox_tabs])
+ checkboxTabs: get_signer_tabs(signer[:checkbox_tabs]),
+ numberTabs: get_signer_tabs(signer[:number_tabs]),
+ fullNameTabs: get_signer_tabs(signer[:fullname_tabs]),
+ dateTabs: get_signer_tabs(signer[:date_tabs])
}
}
if signer[:email_notification]
template_role[:emailNotification] = signer[:email_notification]
@@ -242,11 +246,12 @@
{
'tabLabel' => tab[:label],
'name' => tab[:name],
'value' => tab[:value],
'documentId' => tab[:document_id],
- 'selected' => tab[:selected]
+ 'selected' => tab[:selected],
+ 'locked' => tab[:locked]
}
end
end
@@ -349,11 +354,11 @@
envelopeIdTabs: nil,
fullNameTabs: get_tabs(signer[:full_name_tabs], options, index),
listTabs: get_tabs(signer[:list_tabs], options, index),
noteTabs: nil,
numberTabs: nil,
- radioGroupTabs: nil,
+ radioGroupTabs: get_tabs(signer[:radio_group_tabs], options, index),
initialHereTabs: get_tabs(signer[:initial_here_tabs], options.merge!(initial_here_tab: true), index),
signHereTabs: get_tabs(signer[:sign_here_tabs], options.merge!(sign_here_tab: true), index),
signerAttachmentTabs: nil,
ssnTabs: nil,
textTabs: get_tabs(signer[:text_tabs], options, index),
@@ -381,12 +386,12 @@
tab_hash[:anchorYOffset] = tab[:anchor_y_offset] || '0'
tab_hash[:anchorIgnoreIfNotPresent] = tab[:ignore_anchor_if_not_present] || false
tab_hash[:anchorUnits] = 'pixels'
end
- tab_hash[:conditionalParentLabel] = nil
- tab_hash[:conditionalParentValue] = nil
+ tab_hash[:conditionalParentLabel] = tab[:conditional_parent_label] if tab.key?(:conditional_parent_label)
+ tab_hash[:conditionalParentValue] = tab[:conditional_parent_value] if tab.key?(:conditional_parent_value)
tab_hash[:documentId] = tab[:document_id] || '1'
tab_hash[:pageNumber] = tab[:page_number] || '1'
tab_hash[:recipientId] = index + 1
tab_hash[:required] = tab[:required] || false
@@ -394,26 +399,30 @@
tab_hash[:templateLocked] = tab[:template_locked].nil? ? true : tab[:template_locked]
tab_hash[:templateRequired] = tab[:template_required].nil? ? true : tab[:template_required]
end
if options[:sign_here_tab] == true || options[:initial_here_tab] == true
- tab_hash[:scaleValue] = tab_hash[:scaleValue] || 1
+ tab_hash[:scaleValue] = tab[:scale_value] || 1
end
tab_hash[:xPosition] = tab[:x_position] || '0'
tab_hash[:yPosition] = tab[:y_position] || '0'
tab_hash[:name] = tab[:name] if tab[:name]
- tab_hash[:optional] = false
+ tab_hash[:optional] = tab[:optional] || false
tab_hash[:tabLabel] = tab[:label] || 'Signature 1'
tab_hash[:width] = tab[:width] if tab[:width]
- tab_hash[:height] = tab[:height] if tab[:width]
+ tab_hash[:height] = tab[:height] if tab[:height]
tab_hash[:value] = tab[:value] if tab[:value]
+ tab_hash[:selected] = tab[:selected] if tab[:selected]
tab_hash[:locked] = tab[:locked] || false
tab_hash[:list_items] = tab[:list_items] if tab[:list_items]
+ tab_hash[:groupName] = tab[:group_name] if tab.key?(:group_name)
+ tab_hash[:radios] = get_tabs(tab[:radios], options, index) if tab.key?(:radios)
+
tab_array << tab_hash
end
tab_array
end
@@ -489,11 +498,70 @@
name: io.original_filename
}
end
end
+ # Internal: takes in an array of server template ids and an array of the signers
+ # and sets up the composite template
+ #
+ # Takes an optional array of files, which consist of documents to be used instead of templates
+ #
+ # Returns an array of server template hashes
+ def get_composite_template(server_template_ids, signers, files)
+ composite_array = []
+ index = 0
+ server_template_ids.each_with_index do |template_id, idx|
+ server_template_hash = {
+ sequence: (idx+1).to_s,
+ templateId: template_id,
+ templateRoles: get_template_roles(signers),
+ }
+ templates_hash = {
+ serverTemplates: [server_template_hash],
+ inlineTemplates: get_inline_signers(signers, (idx+1).to_s)
+ }
+ if files
+ document_hash = {
+ documentId: (idx+1).to_s,
+ name: "#{files[idx][:name] if files[idx]}"
+ }
+ templates_hash[:document] = document_hash
+ end
+ composite_array << templates_hash
+ end
+ composite_array
+ end
+
+ # Internal: takes signer info and the inline template sequence number
+ # and sets up the inline template
+ #
+ # Returns an array of signers
+ def get_inline_signers(signers, sequence)
+ signers_array = []
+ signers.each do |signer|
+ signers_hash = {
+ email: signer[:email],
+ name: signer[:name],
+ recipientId: signer[:recipient_id],
+ roleName: signer[:role_name],
+ clientUserId: signer[:client_id] || signer[:email],
+ tabs: {
+ textTabs: get_signer_tabs(signer[:text_tabs]),
+ checkboxTabs: get_signer_tabs(signer[:checkbox_tabs]),
+ numberTabs: get_signer_tabs(signer[:number_tabs]),
+ fullNameTabs: get_signer_tabs(signer[:fullname_tabs]),
+ dateTabs: get_signer_tabs(signer[:date_tabs])
+ }
+ }
+ signers_array << signers_hash
+ end
+ template_hash = {sequence: sequence, recipients: { signers: signers_array }}
+ [template_hash]
+ end
+
+
# Internal sets up the Net::HTTP request
#
# uri - The fully qualified final URI
# post_body - The custom post body including the signers, etc
# file_params - Formatted hash of ios to merge into the post body
@@ -542,10 +610,13 @@
# to sign it. More info about the options available for
# this method are documented above it's method definition.
# status - Options include: 'sent', 'created', 'voided' and determine
# if the envelope is sent out immediately or stored for
# sending at a later time
+ # customFields - (Optional) A hash of listCustomFields and textCustomFields.
+ # Each contains an array of corresponding customField hashes.
+ # For details, please see: http://bit.ly/1FnmRJx
# headers - Allows a client to pass in some
#
# Returns a JSON parsed response object containing:
# envelopeId - The envelope's ID
# status - Sent, created, or voided
@@ -560,11 +631,12 @@
emailSubject: "#{options[:email][:subject] if options[:email]}",
documents: get_documents(ios),
recipients: {
signers: get_signers(options[:signers])
},
- status: "#{options[:status]}"
+ status: "#{options[:status]}",
+ customFields: options[:custom_fields]
}.to_json
uri = build_uri("/accounts/#{acct_id}/envelopes")
http = initialize_net_http_ssl(uri)
@@ -682,12 +754,13 @@
status: options[:status],
emailBlurb: options[:email][:body],
emailSubject: options[:email][:subject],
templateId: options[:template_id],
eventNotification: get_event_notification(options[:event_notification]),
- templateRoles: get_template_roles(options[:signers])
- }.to_json
+ templateRoles: get_template_roles(options[:signers]),
+ customFields: options[:custom_fields]
+ }.to_json
uri = build_uri("/accounts/#{acct_id}/envelopes")
http = initialize_net_http_ssl(uri)
@@ -697,10 +770,62 @@
response = http.request(request)
JSON.parse(response.body)
end
+ # Public: create an envelope for delivery from a composite template
+ #
+ # headers - Optional hash of headers to merge into the existing
+ # required headers for a POST request.
+ # status - Options include: 'sent', or 'created' and
+ # determine if the envelope is sent out immediately or
+ # stored for sending at a later time
+ # email/body - Sets the text in the email body
+ # email/subject - Sets the text in the email subject line
+ # files - Sets documents to be used instead of inline or server templates
+ # template_roles - See the get_template_roles method definition for a list
+ # of options to pass. Note: for consistency sake we call
+ # this 'signers' and not 'templateRoles' when we build up
+ # the request in client code.
+ # headers - Optional hash of headers to merge into the existing
+ # required headers for a multipart request.
+ # server_template_ids - Array of ids for templates uploaded to DocuSign. Templates
+ # will be added in the order they appear in the array.
+ #
+ # Returns a JSON parsed response body containing the envelope's:
+ # envelopeId - autogenerated ID provided by Docusign
+ # uri - the URI where the template is located on the DocuSign servers
+ # statusDateTime - The date/time the envelope was created
+ # status - Sent, created, or voided
+ def create_envelope_from_composite_template(options={})
+ file_params = {}
+
+ if options[:files]
+ ios = create_file_ios(options[:files])
+ file_params = create_file_params(ios)
+ end
+
+ post_body = {
+ emailBlurb: "#{options[:email][:body] if options[:email]}",
+ emailSubject: "#{options[:email][:subject] if options[:email]}",
+ status: options[:status],
+ compositeTemplates: get_composite_template(options[:server_template_ids], options[:signers], options[:files])
+ }.to_json
+
+ uri = build_uri("/accounts/#{acct_id}/envelopes")
+
+ http = initialize_net_http_ssl(uri)
+
+ request = initialize_net_http_multipart_post_request(
+ uri, post_body, file_params, headers(options[:headers])
+ )
+
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
+
# Public returns the names specified for a given email address (existing docusign user)
#
# email - the email of the recipient
# headers - optional hash of headers to merge into the existing
# required headers for a multipart request.
@@ -753,11 +878,34 @@
response = http.request(request)
JSON.parse(response.body)
end
+ # Public returns the URL for embedded sending
+ #
+ # envelope_id - the ID of the envelope you wish to use
+ # return_url - the URL you want the user to be directed to after he or she
+ # closes the view
+ # headers - optional hash of headers to merge into the existing
+ # required headers for a multipart request.
+ #
+ # Returns the URL string for embedded sending
+ def get_sender_view(options = {})
+ content_type = { 'Content-Type' => 'application/json' }
+ content_type.merge(options[:headers]) if options[:headers]
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:envelope_id]}/views/sender")
+
+ http = initialize_net_http_ssl(uri)
+
+ request = Net::HTTP::Post.new(uri.request_uri, headers(content_type))
+ request.body = { returnUrl: options[:return_url] }.to_json
+
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
# Public returns the URL for embedded console
#
# envelope_id - the ID of the envelope you wish to use for embedded signing
# headers - optional hash of headers to merge into the existing
# required headers for a multipart request.
@@ -787,11 +935,11 @@
# Public returns the envelope recipients for a given envelope
#
# include_tabs - boolean, determines if the tabs for each signer will be
# returned in the response, defaults to false.
- # envelope_id - ID of the envelope for which you want to retrive the
+ # envelope_id - ID of the envelope for which you want to retrieve the
# signer info
# headers - optional hash of headers to merge into the existing
# required headers for a multipart request.
#
# Returns a hash of detailed info about the envelope including the signer
@@ -913,10 +1061,50 @@
JSON.parse(response.body)
end
+ # Public retrieves a PDF containing the combined content of all
+ # documents and the certificate for the given envelope.
+ #
+ # envelope_id - ID of the envelope from which the doc will be retrieved
+ # local_save_path - Local absolute path to save the doc to including the
+ # filename itself
+ # headers - Optional hash of headers to merge into the existing
+ # required headers for a multipart request.
+ #
+ # Example
+ #
+ # client.get_combined_document_from_envelope(
+ # envelope_id: @envelope_response['envelopeId'],
+ # local_save_path: 'docusign_docs/file_name.pdf',
+ # return_stream: true/false # will return the bytestream instead of saving doc to file system.
+ # )
+ #
+ # Returns the PDF document as a byte stream.
+ def get_combined_document_from_envelope(options={})
+ content_type = { 'Content-Type' => 'application/json' }
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:envelope_id]}/documents/combined")
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
+ response = http.request(request)
+ return response.body if options[:return_stream]
+
+ split_path = options[:local_save_path].split('/')
+ split_path.pop #removes the document name and extension from the array
+ path = split_path.join("/") #rejoins the array to form path to the folder that will contain the file
+
+ FileUtils.mkdir_p(path)
+ File.open(options[:local_save_path], 'wb') do |output|
+ output << response.body
+ end
+ end
+
+
# Public moves the specified envelopes to the given folder
#
# envelope_ids - IDs of the envelopes to be moved
# folder_id - ID of the folder to move the envelopes to
# headers - Optional hash of headers to merge into the existing
@@ -947,10 +1135,46 @@
response
end
+ # Public returns a hash of audit events for a given envelope
+ #
+ # envelope_id - ID of the envelope to get audit events from
+ #
+ #
+ # Example
+ # client.get_envelope_audit_events(
+ # envelope_id: "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
+ # )
+ # Returns a hash of the events that have happened to the envelope.
+ def get_envelope_audit_events(options = {})
+ content_type = { 'Content-Type' => 'application/json' }
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:envelope_id]}/audit_events")
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
+ response = http.request(request)
+
+ JSON.parse(response.body)
+ end
+
+ # Public retrieves folder information. Helpful to use before client.search_folder_for_envelopes
+ def get_folder_list(options={})
+ content_type = { 'Content-Type' => 'application/json' }
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{@acct_id}/folders/")
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
# Public retrieves the envelope(s) from a specific folder based on search params.
#
# Option Query Terms(none are required):
# query_params:
# start_position: Integer The position of the folder items to return. This is used for repeated calls, when the number of envelopes returned is too much for one return (calls return 100 envelopes at a time). The default value is 0.
@@ -1051,10 +1275,24 @@
request = Net::HTTP::Get.new(uri.request_uri, headers({ 'Content-Type' => 'application/json' }))
JSON.parse(http.request(request).body)
end
+ # Public: Retrieves a list of templates used in an envelope
+ #
+ # Returns templateId, name and uri for each template found.
+ #
+ # envelope_id - DS id of envelope with templates.
+ def get_templates_in_envelope(envelope_id)
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{envelope_id}/templates")
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Get.new(uri.request_uri, headers({ 'Content-Type' => 'application/json' }))
+ JSON.parse(http.request(request).body)
+ end
+
+
# Grabs envelope data.
# Equivalent to the following call in the API explorer:
# Get Envelopev2/accounts/:accountId/envelopes/:envelopeId
#
# envelope_id- DS id of envelope to be retrieved.
@@ -1062,9 +1300,194 @@
content_type = { 'Content-Type' => 'application/json' }
uri = build_uri("/accounts/#{acct_id}/envelopes/#{envelope_id}")
http = initialize_net_http_ssl(uri)
request = Net::HTTP::Get.new(uri.request_uri, headers(content_type))
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
+
+ # Public deletes a recipient for a given envelope
+ #
+ # envelope_id - ID of the envelope for which you want to retrieve the
+ # signer info
+ # recipient_id - ID of the recipient to delete
+ #
+ # Returns a hash of recipients with an error code for any recipients that
+ # were not successfully deleted.
+ def delete_envelope_recipient(options={})
+ content_type = {'Content-Type' => 'application/json'}
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{@acct_id}/envelopes/#{options[:envelope_id]}/recipients")
+ post_body = "{
+ \"signers\" : [{\"recipientId\" : \"#{options[:recipient_id]}\"}]
+ }"
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Delete.new(uri.request_uri, headers(content_type))
+ request.body = post_body
+
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
+
+ # Public voids an in-process envelope
+ #
+ # envelope_id - ID of the envelope to be voided
+ # voided_reason - Optional reason for the envelope being voided
+ #
+ # Returns the response (success or failure).
+ def void_envelope(options = {})
+ content_type = { 'Content-Type' => 'application/json' }
+ content_type.merge(options[:headers]) if options[:headers]
+
+ post_body = {
+ "status" =>"voided",
+ "voidedReason" => options[:voided_reason] || "No reason provided."
+ }.to_json
+
+ uri = build_uri("/accounts/#{acct_id}/envelopes/#{options[:folder_id]}")
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Put.new(uri.request_uri, headers(content_type))
+ request.body = post_body
+ http.request(request)
+ end
+
+ # Public deletes a document for a given envelope
+ # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Remove Documents from a Draft Envelope.htm%3FTocPath%3DREST%2520API%2520References%7C_____54
+ #
+ # envelope_id - ID of the envelope from which the doc will be retrieved
+ # document_id - ID of the document to delete
+ #
+ # Returns the success or failure of each document being added to the envelope and
+ # the envelope ID. Failed operations on array elements will add the "errorDetails"
+ # structure containing an error code and message. If "errorDetails" is null, then
+ # the operation was successful for that item.
+ def delete_envelope_document(options={})
+ content_type = {'Content-Type' => 'application/json'}
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{@acct_id}/envelopes/#{options[:envelope_id]}/documents")
+ post_body = {
+ documents: [
+ { documentId: options[:document_id] }
+ ]
+ }.to_json
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Delete.new(uri.request_uri, headers(content_type))
+ request.body = post_body
+
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
+ # Public adds a document to a given envelope
+ # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Add Document.htm%3FTocPath%3DREST%2520API%2520References%7C_____56
+ #
+ # envelope_id - ID of the envelope from which the doc will be added
+ # document_id - ID of the document to add
+ # file_path - Local or remote path to file
+ # content_type - optional content type for file. Defaults to application/pdf.
+ # file_name - optional name for file. Defaults to basename of file_path.
+ # file_extension - optional extension for file. Defaults to extname of file_name.
+ #
+ # The response only returns a success or failure.
+ def add_envelope_document(options={})
+ options[:content_type] ||= 'application/pdf'
+ options[:file_name] ||= File.basename(options[:file_path])
+ options[:file_extension] ||= File.extname(options[:file_name])[1..-1]
+
+ headers = {
+ 'Content-Type' => options[:content_type],
+ 'Content-Disposition' => "file; filename=\"#{options[:file_name]}\"; documentid=#{options[:document_id]}; fileExtension=\"#{options[:file_extension]}\""
+ }
+
+ uri = build_uri("/accounts/#{@acct_id}/envelopes/#{options[:envelope_id]}/documents/#{options[:document_id]}")
+ post_body = open(options[:file_path]).read
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Put.new(uri.request_uri, headers(headers))
+ request.body = post_body
+
+ http.request(request)
+ end
+
+ # Public adds signers to a given envelope
+ # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Add%20Recipients%20to%20an%20Envelope.htm%3FTocPath%3DREST%2520API%2520References|_____77
+ #
+ # envelope_id - ID of the envelope to which the recipient will be added
+ # signers - Array of hashes
+ # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Recipients/Signers%20Recipient.htm%3FTocPath%3DREST%2520API%2520References|Send%2520an%2520Envelope%2520or%2520Create%2520a%2520Draft%2520Envelope|Recipient%2520Parameters|_____7
+ #
+ # TODO: This could be made more general as an add_envelope_recipient method
+ # to handle recipient types other than Signer
+ # See: https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Recipient%20Parameter.htm%3FTocPath%3DREST%2520API%2520References|Send%2520an%2520Envelope%2520or%2520Create%2520a%2520Draft%2520Envelope|Recipient%2520Parameters|_____0
+ def add_envelope_signers(options = {})
+ content_type = { "Content-Type" => "application/json" }
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{@acct_id}/envelopes/#{options[:envelope_id]}/recipients")
+ post_body = { signers: options[:signers] }.to_json
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Put.new(uri.request_uri, headers(content_type))
+ request.body = post_body
+
+ response = http.request(request)
+ JSON.parse(response.body)
+ end
+
+ # Public adds recipient tabs to a given envelope
+ # See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST API References/Add Tabs for a Recipient.htm%3FTocPath%3DREST%2520API%2520References%7C_____86
+ #
+ # envelope_id - ID of the envelope from which the doc will be added
+ # recipient - ID of the recipient to add tabs to
+ # tabs - hash of tab (see example below)
+ # {
+ # signHereTabs: [
+ # {
+ # anchorString: '/s1/',
+ # anchorXOffset: '5',
+ # anchorYOffset: '8',
+ # anchorIgnoreIfNotPresent: 'true',
+ # documentId: '1',
+ # pageNumber: '1',
+ # recipientId: '1'
+ # }
+ # ],
+ # initialHereTabs: [
+ # {
+ # anchorString: '/i1/',
+ # anchorXOffset: '5',
+ # anchorYOffset: '8',
+ # anchorIgnoreIfNotPresent: 'true',
+ # documentId: '1',
+ # pageNumber: '1',
+ # recipientId: '1'
+ # }
+ # ]
+ # }
+ #
+ # The response returns the success or failure of each document being added
+ # to the envelope and the envelope ID. Failed operations on array elements
+ # will add the "errorDetails" structure containing an error code and message.
+ # If "errorDetails" is null, then the operation was successful for that item.
+ def add_recipient_tabs(options={})
+ content_type = {'Content-Type' => 'application/json'}
+ content_type.merge(options[:headers]) if options[:headers]
+
+ uri = build_uri("/accounts/#{@acct_id}/envelopes/#{options[:envelope_id]}/recipients/#{options[:recipient_id]}/tabs")
+ post_body = options[:tabs].to_json
+
+ http = initialize_net_http_ssl(uri)
+ request = Net::HTTP::Post.new(uri.request_uri, headers(content_type))
+ request.body = post_body
+
response = http.request(request)
JSON.parse(response.body)
end
end
end