hellosign / hellosign-python-sdk Goto Github PK
View Code? Open in Web Editor NEWA Python SDK for HelloSign's API
License: MIT License
A Python SDK for HelloSign's API
License: MIT License
Hi,
Ive been working on a project that uses HelloSign and HelloWork. The backend server is written using Flask and deployed on Azure.
While using hellosign-python-sdk to run SignatureRequestSendWithTemplateRequest, I always end up encountering the following error.
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.hellosign.com', port=443): Max retries exceeded with url: /v3/signature_request/send_with_template (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
The above error is only seen on the server that is being run on Azure. This doesn't happen in my local system.
When I try to use requests and run requests.post with necessary headers, it ends up working both on local system and the virtual machine.
Are there any potential work arounds?
I have shifted the hosted site from http to https by adding necessary certificates.
Is it a necessity that my instance should have a TLS/SSL certificate or can I turn off the verification when in debug mode?
re:
@api.hellosign.com/v3/signature_request/send_with_template endpoint
https://app.hellosign.com/api/reference#send_with_template
Needs to be expanded to include the ability to also send a this parameter:
file[] or file_url[] optional Append additional files to the signature request. HelloSign will parse the files for text tags. Text tags for signers not on the template will be ignored.
Use file[] to pass the uploaded file(s). Use file_url[] to have HelloSign download the file(s). We currently only support use of either the file[] parameter or file_url[] parameter, not both.
NOTE: internal issue AS-97
The following changes have been made to the API:
3.8.5
v3
The reason for this issue is the following functionality for signature request files: https://app.hellosign.com/api/signature_request/files
get_url optional Boolean.
If true, the response will contain a url link to the file instead. Links are only available for PDFs and have a TTL of 3 days. (default = false)
By providing an optional get parameter one could receive a temporary public url to view the document
I've submitted a pull request with a possible solution to return the temporary file url
This is a proof of concept solution, as I stated in the PR, and I'm open for discussion if there's a better way to achieve the same result.
v3/unclaimed_draft/create_embedded is defaulting to 1 not 0.
-F 'is_for_embedded_signing=0' \
And it will not set is_for_embedded_signing = 0 no matter under any set of conditions.
This is just for create_embedded
response = client.create_embedded_unclaimed_draft
When using the function as suggested in the documentation, I get permission errors that suggest using test_mode=1, but the function in the python sdk won't take it as a parameter. Is there another way I should be using the test mode?
The method get_template_list()
only takes the page
argument even though the documentation lists more parameters:
https://www.hellosign.com/api/reference#Template
It would be great to be able to pass account_id
, page_size
and query
as well.
def send_signature_request_with_template(self, test_mode=False, template_id=None, template_ids=None, title=None, subject=None, message=None, signing_redirect_url=None, signers=None, ccs=None, custom_fields=None, metadata=None, ux_version=None): ''' Creates and sends a new SignatureRequest based off of a Template
Right away, within this method definition we can see two glaring PEP8 violations:
def send..
) goes on beyond the 120 character limit.PEP8 style guide can be found here: https://www.python.org/dev/peps/pep-0008/
Add get_url param to GET /signature_request/files/:signature_request_id
Endpoint:
GET /signature_request/files/[:signature_request_id]
The API documentation for this endpoint includes a parameter called:
get_url
It is marked optional. It is a boolean. It goes on to say....."If true, the response will contain a url link to the file instead. Links are only available for PDFs and have a TTL of 3 days. (default = false)"
However,
python SDK
https://github.com/HelloFax/hellosign-python-sdk/blob/v3/hellosign_sdk/hsclient.py
line: 317 does not have a get_url parameter
If you try to use it then you get the following error message:
TypeError: get_signature_request_file() got an unexpected keyword argument 'get_url'
When trying to edit an embedded template, get_template_edit_url()
returns an edit_url
. It is able to be used to open the iFrame on the client side, however, upon making any changes, an error is thrown via the iFrame. The error number is js409b72b56
. While trying to find a solution, I opted to use the requests
library and was able to successfully edit an embedded template. For reference, here is the call being done by the requests library:
post_data = {
"test_mode": 1,
}
edit_obj = requests.post(f'https://{current_app.config.get("HS_API_KEY")}:@api.hellosign.com/v3/embedded/edit_url/{template_record.template_id}', data=post_data)
resp_dict = edit_obj.json()
print(edit_obj.json())
edit_url = edit_obj.json()["embedded"]["edit_url"]
print(edit_url)
This allows you to edit and save changes via the iFrame.
The get_signature_request_list() method only takes page and page_size as arguments, which prevents the use of some of the optional request parameters. account_id and query should be added as arguments as well.
ie:
def get_signature_request_list(self, page=1, page_size=None, account_id=None, query=None):
Currently the only workaround is to use the requests library and query that way.
When updating the SDKs to include editable merge fields, please also update the SDK git repos README examples (if necessary) and the following in the API docs:
The code mentioned in the notes do not work,
client.account.callback_url='http://example.com/my_HelloSign_callback_endpoint'
Working code for me is the below code,
client.get_account_info().json_data['callback_url'] = 'http://example.com/my_HelloSign_callback_endpoint'
Is it ok?
Calling client.send_signature_request_embedded_with_template
with test_mode=True works from my remote development instance, but fails when run on my local machine with the message "This page can only be viewed from distribute.com, unless the Signature Request is a test and skipDomainVerification is set to true in HelloSign.open. See the documentation for more info." Which sounds fine, except it isn't clear from the documentation how to do this with the python sdk (if it's even possible).
field_options is described here: https://app.hellosign.com/api/reference#send_embedded_signature_request
It's not one of the fields that _send_signature_request
can put into the payload.
signing_options = {“draw”: True, “type”: True, “upload”: True, “phone”: False, “default”: “draw”},
python SDK version 3.8.8 is requiring signing options
However, that should not be a required field. This issue does not exist in python sdk version 3.8.7
https://faq.hellosign.com/hc/en-us/articles/115002371968-2-1-17-Release-35
API: Ability to add a file to embedded and non-embedded send from. See updated end points: template.signature_request/create_embedded_with_template & signature_request/send_with_template
Add these to the SDK parameter list.
Add attachment parameters when sending a signature request.
response = client.get_oauth_data(
client_id=clientID,
client_secret=secret,
code='0369fXXXXXXXXX',
state='b0XXX'
)
results in 'Failed No JSON object could be decoded' message
Non-embedded signature requests should send client id for white-labeling
Workaround:
import requests
buildTheRequest = 'https://' + apikey +
':@api.hellosign.com/v3/signature_request/send'
data = {
'client_id': clientID,
'file_url': 'https://i.ytimg.com/vi/JPA_rzHDy6o/maxresdefault.jpg',
'subject': 'test production',
'allow_decline': '1',
'message': 'test',
'signers[0][name]': 'George',
'signers[0][email_address]': '[email protected]',
'signers[1][name]': 'Ed',
'signers[1][email_address]': '[email protected]',
'test_mode': '1'
}
print(buildTheRequest)
r = requests.post(buildTheRequest, data)
print(r.text)
stringData = r.text
This seems like a pretty simple oversight - passing a plain old Python list into this named param causes a 400 Bad Request exception, because the server can't parse the JSON in this field (because it's never JSON to begin with). Manually running the list through json.dumps
before passing to the SDK fixes the problem.
3.8.5
In https://github.com/HelloFax/hellosign-python-sdk#embedded-requesting
2nd code example:
client = HSClient(api_key='your_api_key')
event_data = json.loads(request.POST.get('json'))
if event_data['event']['event_type'] == 'signature_request_sent':
sig_req = event_data['signature_request']
for sig in sig_req['signature_request']['signatures']
embedded_obj = client.get_embedded_object(sig['signature_id'])
sign_url = embedded_obj.sign_url
# Save sign_url somewhere
missing colon on line 5, should be
client = HSClient(api_key='your_api_key')
event_data = json.loads(request.POST.get('json'))
if event_data['event']['event_type'] == 'signature_request_sent':
sig_req = event_data['signature_request']
for sig in sig_req['signature_request']['signatures']:
embedded_obj = client.get_embedded_object(sig['signature_id'])
sign_url = embedded_obj.sign_url
# Save sign_url somewhere
The documentation says "coming soon": https://app.hellosign.com/api/textTagsWalkthrough
Section: Allowing a signer to edit pre-set values
Example: custom_fields:[{"name":"organization_name", "value":"Enter organization name", "editor":"1", "required":"true"}]
Hey y'all,
I am receiving the following error when trying to pass some file urls into the /template/update_files/[:template_id] endpoint.
/hellosign_sdk/utils/request.py", line 258, in _check_error
raise err_cls("%s error: %s" % (response.status_code, json_response["error"]["error_msg"]), response.status_code)
hellosign_sdk.utils.exception.BadRequest: 400 error: Invalid parameter: file_urls
SDK Version 4.0
File "/app/.heroku/src/hellosign-python-sdk/hellosign_sdk/utils/request.py" in _check_error
261. raise err_cls("%s error: %s" % (response.status_code, json_response["error_description"]), response.status_code)
Exception Value: 'NoneType' object is not subscriptable
HTTP error responses which do not contain json data trigger the above scenario.
response = client.get_signature_request_file(
signature_request_id='ID',
filename='=files.pdf',
file_type='pdf',
get_data_uri='true'
Results in
TypeError: get_signature_request_file() got an unexpected keyword argument 'get_data_uri'
Thank you
The draft_type
parameter used in requests to /unclaimed_draft/create_embedded
does not match the documentation.
Should be renamed from draft_type
to type
https://app.hellosign.com/api/reference#create_embedded_unclaimed_draft
When a signature request is created with multiple files, the SDK sends them in a manner that results in them appearing in random order when they have to be signed. I've been digging into this and have found the cause which I'll explain below.
When a signature request is created that includes files, the HSClient
class uses the HSFormat
class to convert them into a data structure used in the request: https://github.com/HelloFax/hellosign-python-sdk/blob/ac8a1fcea8f4c2fdc56a408bc4d50efa7c6bfd91/hellosign_sdk/hsclient.py#L1383 like so: https://github.com/HelloFax/hellosign-python-sdk/blob/ac8a1fcea8f4c2fdc56a408bc4d50efa7c6bfd91/hellosign_sdk/hsclient.py#L1427
However the HSFormat
creates an inappropriate data structure for this:https://github.com/HelloFax/hellosign-python-sdk/blob/ac8a1fcea8f4c2fdc56a408bc4d50efa7c6bfd91/hellosign_sdk/utils/hsformat.py#L40-L49
Basically, it creates a dictionary with a "file[j]"
key for each file. This dictionary is eventually fed into a call to the post
method of the Requests library as the files
argument: https://github.com/HelloFax/hellosign-python-sdk/blob/ac8a1fcea8f4c2fdc56a408bc4d50efa7c6bfd91/hellosign_sdk/utils/request.py#L167
However, the documentation for the Requests library states that a list (which is an ordered iterable) be used for this argument here and the example clearly is of a list
of tuple
s:
>>> url = 'http://httpbin.org/post'
>>> multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
>>> r = requests.post(url, files=multiple_files)
>>> r.text
What I'm guessing happens is that the Requests library converts the dictionary into a list, ignoring the keys and appending only the values in a random order because dict
is an unordered data structure.
create_embedded_unclaimed_draft() does not accept the hold_request request parameter, and throws the following error:
TypeError: create_embedded_unclaimed_draft() got an unexpected keyword argument 'hold_request'
The get_signature_request_file
method takes a filename, fetches the contents from the server and writes to this filename. This is a problem if the file is not stored locally (S3 in my case).
Potential solutions:
get_signature_request_file
also accept a writable file-like object.filename
parameter optional, and in it's absense return the contents as a string ?I'd be happy to submit a PR if we can decide on a solution. I prefer the first one above, unless anyone else can propose a better solution.
create_embedded_unclaimed_draft_with_template() does not accept the hold_request request parameter, and throws the following error:
TypeError: create_embedded_unclaimed_draft_with_template() got an unexpected keyword argument 'hold_request'
Currently the python SDK does not support
'custom_fields': '[{"name":"newline", "value":"$20,000", "editor":"Client", "required":true}]',
the editor and required fields for custom_fields. Please add this support.
The python SDK will work for templates and custom fields, but not in the case where you want to assign an editor or make it required.
Workaround:
import requests
buildTheRequest = 'https://' + apikey + ':@api.hellosign.com/v3/signature_request/create_embedded_with_template'
data = {
'client_id': 'YOUR_CLIENT_ID',
'template_id': 'YOUR_TEMPLATE_ID',
'subject': 'ticket214090',
'message': 'ticket214090',
'signers[Client][name]': 'George',
'signers[Client][email_address]':'YOUR_EMAIL',
'custom_fields': '[{"name":"newline", "value":"$20,000", "editor":"Client", "required":true}]',
'test_mode': '1'
}
print(buildTheRequest)
r = requests.post(buildTheRequest, data)
print(r.text)
Description is available (with broken Markdown - pypi doesn't supporting Markdown).
Download package is not available.
Latest available download package is 3.5
The only way to use get_template_files
is by providing a filename to save the template file to even though the API is capable of returning a URL with TTL to the file.
Since the merge yesterday any attempt to create a signature request will throw a malformed JSON error when attempting to process the request.
This is due to the json.dumps call during the payload creation on an empty dict. This causes the the payload to contain a null value which is returned as a 400 error.
I have a commit for this issue which I will push later tomorrow.
I'm looking to update a signature request ref https://app.hellosign.com/api/reference#update_signature_request. What is the recommended method to achieve this with this SDK?
When updating the SDKs to include editable merge fields, please also update the SDK git repos README examples (if necessary) and the following in the API docs:
Hello,
I was looking into setting a timeout for requests made with the hellosign python sdk so that our app can handle Hellosign outages more gracefully and timeout instead of hanging forever, but from what I can tell from the documentation and source code, that does not seem possible right now.
I am happy to submit a PR for this, but I wanted to make sure this repo is still actively maintained before investing the time to do that- it looks like the last commit to master at the time of this writing was on March 31: 43b0a5a
Is this library unmaintained?
There is multiple unreviewed and un merged pull requests.
Outdated API calls.
It would be great to use HTTP mocks for testing or enable some dev mode that doesn't actually hit the API. Something like this is working for me with Responses:
import responses
HS_SEND_SIGN_REQ_URL = 'https://api.hellosign.com/v3/signature_request/send'
HERE = os.path.dirname(os.path.abspath(__file__))
@responses.activate
def test_post_new_mail_signature_request():
mock_path = os.path.join(HERE, 'mocks/signature_request_send.json')
mock_response = open(mock_path, 'r').read()
responses.add(responses.POST, HS_SEND_SIGN_REQ_URL,
body=mock_response, status=200,
content_type='application/json')
client = HSClient(api_key='')
signature_request = client.send_signature_request(
test_mode=True,
title='',
subject='',
message='',
signers=[{'name': '', 'email_address': ''}],
files=[filepath]
)
And the file signature_request_send.json
looks something like this with the actual JSON response:
{
"signature_request": {
}
}
So an extra parameter called maybe when instancing a client like HSClient(api_key=api_key, mock_http=True)
would be nice and I think also for some tests, it might not be ideal to hit the actual API.
With a large-scale implementation where multiple users may be online with a platform at one time, there's a large probability that two or more users are going to trigger either GET /siganture_request/list or GET /template/list calls at the same time. Right now, the second+ of those users are going to trigger a 409 response, so it'd be helpful if you automatically handled 409 retries since my platform can't make the calls in parallel.
The method's signature does not support this parameter: https://github.com/hellosign/hellosign-python-sdk/blob/v3/hellosign_sdk/hsclient.py#L1509-L1516
However the API documentation mentions this parameter can be used to allow the requestor to modify signers, and we need to be able to access it.
How do you recommend we proceed?
Using file_url as a request parameter throws the following error:
TypeError: send_signature_request_embedded() got an unexpected keyword argument 'file_url'
The current workaround is to use file_urls instead.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.