signedly 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. signedly-0.1.0/LICENSE +21 -0
  2. signedly-0.1.0/PKG-INFO +18 -0
  3. signedly-0.1.0/README.md +453 -0
  4. signedly-0.1.0/pyproject.toml +89 -0
  5. signedly-0.1.0/setup.cfg +7 -0
  6. signedly-0.1.0/setup.py +51 -0
  7. signedly-0.1.0/signedly/__init__.py +92 -0
  8. signedly-0.1.0/signedly/api/__init__.py +14 -0
  9. signedly-0.1.0/signedly/api/api_request_logs_api.py +686 -0
  10. signedly-0.1.0/signedly/api/authentication_api.py +603 -0
  11. signedly-0.1.0/signedly/api/bulk_sending_api.py +858 -0
  12. signedly-0.1.0/signedly/api/documents_api.py +2465 -0
  13. signedly-0.1.0/signedly/api/downloads_api.py +840 -0
  14. signedly-0.1.0/signedly/api/fields_api.py +2308 -0
  15. signedly-0.1.0/signedly/api/sending_api.py +890 -0
  16. signedly-0.1.0/signedly/api/signatories_api.py +1165 -0
  17. signedly-0.1.0/signedly/api/templates_api.py +1452 -0
  18. signedly-0.1.0/signedly/api/webhooks_api.py +2582 -0
  19. signedly-0.1.0/signedly/api_client.py +798 -0
  20. signedly-0.1.0/signedly/api_response.py +21 -0
  21. signedly-0.1.0/signedly/configuration.py +596 -0
  22. signedly-0.1.0/signedly/exceptions.py +200 -0
  23. signedly-0.1.0/signedly/helpers.py +89 -0
  24. signedly-0.1.0/signedly/models/__init__.py +66 -0
  25. signedly-0.1.0/signedly/models/create_bulk_send202_response.py +105 -0
  26. signedly-0.1.0/signedly/models/create_bulk_send_request.py +101 -0
  27. signedly-0.1.0/signedly/models/create_document_fields_request_inner.py +156 -0
  28. signedly-0.1.0/signedly/models/create_document_from_template200_response.py +101 -0
  29. signedly-0.1.0/signedly/models/create_document_from_template_request.py +115 -0
  30. signedly-0.1.0/signedly/models/create_document_from_template_request_recipients_inner.py +92 -0
  31. signedly-0.1.0/signedly/models/create_signatories_request.py +100 -0
  32. signedly-0.1.0/signedly/models/create_signatories_request_signatories_inner.py +92 -0
  33. signedly-0.1.0/signedly/models/create_signatory_request.py +94 -0
  34. signedly-0.1.0/signedly/models/create_template_fields_request_inner.py +156 -0
  35. signedly-0.1.0/signedly/models/create_webhook_endpoint_request.py +103 -0
  36. signedly-0.1.0/signedly/models/delete_field_request.py +88 -0
  37. signedly-0.1.0/signedly/models/document.py +159 -0
  38. signedly-0.1.0/signedly/models/document_page.py +113 -0
  39. signedly-0.1.0/signedly/models/document_status_page.py +113 -0
  40. signedly-0.1.0/signedly/models/document_status_row.py +90 -0
  41. signedly-0.1.0/signedly/models/fill_and_send_document_request.py +116 -0
  42. signedly-0.1.0/signedly/models/fill_and_send_document_request_elements_inner.py +96 -0
  43. signedly-0.1.0/signedly/models/get_access_token_request.py +90 -0
  44. signedly-0.1.0/signedly/models/get_audit_trail_link200_response.py +88 -0
  45. signedly-0.1.0/signedly/models/get_download_status200_response.py +90 -0
  46. signedly-0.1.0/signedly/models/list_bulk_send_columns200_response_inner.py +92 -0
  47. signedly-0.1.0/signedly/models/model_field.py +202 -0
  48. signedly-0.1.0/signedly/models/page.py +102 -0
  49. signedly-0.1.0/signedly/models/refresh_access_token200_response.py +99 -0
  50. signedly-0.1.0/signedly/models/refresh_access_token_request.py +88 -0
  51. signedly-0.1.0/signedly/models/request_count_page.py +113 -0
  52. signedly-0.1.0/signedly/models/request_hit.py +93 -0
  53. signedly-0.1.0/signedly/models/request_log.py +108 -0
  54. signedly-0.1.0/signedly/models/request_log_page.py +113 -0
  55. signedly-0.1.0/signedly/models/send_document200_response.py +88 -0
  56. signedly-0.1.0/signedly/models/send_document_by_link200_response.py +90 -0
  57. signedly-0.1.0/signedly/models/send_document_by_link_request.py +91 -0
  58. signedly-0.1.0/signedly/models/send_document_request.py +102 -0
  59. signedly-0.1.0/signedly/models/signatory.py +119 -0
  60. signedly-0.1.0/signedly/models/template.py +124 -0
  61. signedly-0.1.0/signedly/models/template_field.py +202 -0
  62. signedly-0.1.0/signedly/models/template_page.py +113 -0
  63. signedly-0.1.0/signedly/models/update_document_field_by_body_request.py +158 -0
  64. signedly-0.1.0/signedly/models/update_document_field_by_body_request_items_inner.py +92 -0
  65. signedly-0.1.0/signedly/models/update_webhook_endpoint_request.py +105 -0
  66. signedly-0.1.0/signedly/models/upload.py +110 -0
  67. signedly-0.1.0/signedly/models/upload_document_for_one_signer200_response.py +90 -0
  68. signedly-0.1.0/signedly/models/upload_document_for_one_signer_request.py +96 -0
  69. signedly-0.1.0/signedly/models/upload_document_request.py +101 -0
  70. signedly-0.1.0/signedly/models/webhook_delivery.py +140 -0
  71. signedly-0.1.0/signedly/models/webhook_delivery_page.py +113 -0
  72. signedly-0.1.0/signedly/models/webhook_endpoint.py +116 -0
  73. signedly-0.1.0/signedly/models/webhook_endpoint_with_secret.py +120 -0
  74. signedly-0.1.0/signedly/py.typed +0 -0
  75. signedly-0.1.0/signedly/rest.py +258 -0
  76. signedly-0.1.0/signedly.egg-info/PKG-INFO +18 -0
  77. signedly-0.1.0/signedly.egg-info/SOURCES.txt +139 -0
  78. signedly-0.1.0/signedly.egg-info/dependency_links.txt +1 -0
  79. signedly-0.1.0/signedly.egg-info/requires.txt +4 -0
  80. signedly-0.1.0/signedly.egg-info/top_level.txt +1 -0
  81. signedly-0.1.0/test/test_api_request_logs_api.py +45 -0
  82. signedly-0.1.0/test/test_authentication_api.py +45 -0
  83. signedly-0.1.0/test/test_bulk_sending_api.py +52 -0
  84. signedly-0.1.0/test/test_create_bulk_send202_response.py +63 -0
  85. signedly-0.1.0/test/test_create_bulk_send_request.py +62 -0
  86. signedly-0.1.0/test/test_create_document_fields_request_inner.py +92 -0
  87. signedly-0.1.0/test/test_create_document_from_template200_response.py +57 -0
  88. signedly-0.1.0/test/test_create_document_from_template_request.py +61 -0
  89. signedly-0.1.0/test/test_create_document_from_template_request_recipients_inner.py +56 -0
  90. signedly-0.1.0/test/test_create_signatories_request.py +65 -0
  91. signedly-0.1.0/test/test_create_signatories_request_signatories_inner.py +55 -0
  92. signedly-0.1.0/test/test_create_signatory_request.py +57 -0
  93. signedly-0.1.0/test/test_create_template_fields_request_inner.py +91 -0
  94. signedly-0.1.0/test/test_create_webhook_endpoint_request.py +56 -0
  95. signedly-0.1.0/test/test_delete_field_request.py +52 -0
  96. signedly-0.1.0/test/test_document.py +123 -0
  97. signedly-0.1.0/test/test_document_page.py +208 -0
  98. signedly-0.1.0/test/test_document_status_page.py +66 -0
  99. signedly-0.1.0/test/test_document_status_row.py +54 -0
  100. signedly-0.1.0/test/test_documents_api.py +87 -0
  101. signedly-0.1.0/test/test_downloads_api.py +52 -0
  102. signedly-0.1.0/test/test_fields_api.py +87 -0
  103. signedly-0.1.0/test/test_fill_and_send_document_request.py +73 -0
  104. signedly-0.1.0/test/test_fill_and_send_document_request_elements_inner.py +56 -0
  105. signedly-0.1.0/test/test_get_access_token_request.py +54 -0
  106. signedly-0.1.0/test/test_get_audit_trail_link200_response.py +51 -0
  107. signedly-0.1.0/test/test_get_download_status200_response.py +52 -0
  108. signedly-0.1.0/test/test_helpers.py +62 -0
  109. signedly-0.1.0/test/test_list_bulk_send_columns200_response_inner.py +53 -0
  110. signedly-0.1.0/test/test_model_field.py +83 -0
  111. signedly-0.1.0/test/test_page.py +88 -0
  112. signedly-0.1.0/test/test_refresh_access_token200_response.py +56 -0
  113. signedly-0.1.0/test/test_refresh_access_token_request.py +52 -0
  114. signedly-0.1.0/test/test_request_count_page.py +68 -0
  115. signedly-0.1.0/test/test_request_hit.py +53 -0
  116. signedly-0.1.0/test/test_request_log.py +58 -0
  117. signedly-0.1.0/test/test_request_log_page.py +78 -0
  118. signedly-0.1.0/test/test_send_document200_response.py +51 -0
  119. signedly-0.1.0/test/test_send_document_by_link200_response.py +52 -0
  120. signedly-0.1.0/test/test_send_document_by_link_request.py +54 -0
  121. signedly-0.1.0/test/test_send_document_request.py +61 -0
  122. signedly-0.1.0/test/test_sending_api.py +52 -0
  123. signedly-0.1.0/test/test_signatories_api.py +59 -0
  124. signedly-0.1.0/test/test_signatory.py +59 -0
  125. signedly-0.1.0/test/test_template.py +105 -0
  126. signedly-0.1.0/test/test_template_field.py +83 -0
  127. signedly-0.1.0/test/test_template_page.py +172 -0
  128. signedly-0.1.0/test/test_templates_api.py +66 -0
  129. signedly-0.1.0/test/test_update_document_field_by_body_request.py +94 -0
  130. signedly-0.1.0/test/test_update_document_field_by_body_request_items_inner.py +56 -0
  131. signedly-0.1.0/test/test_update_webhook_endpoint_request.py +56 -0
  132. signedly-0.1.0/test/test_upload.py +58 -0
  133. signedly-0.1.0/test/test_upload_document_for_one_signer200_response.py +52 -0
  134. signedly-0.1.0/test/test_upload_document_for_one_signer_request.py +59 -0
  135. signedly-0.1.0/test/test_upload_document_request.py +57 -0
  136. signedly-0.1.0/test/test_webhook_delivery.py +63 -0
  137. signedly-0.1.0/test/test_webhook_delivery_page.py +88 -0
  138. signedly-0.1.0/test/test_webhook_endpoint.py +62 -0
  139. signedly-0.1.0/test/test_webhook_endpoint_with_secret.py +63 -0
  140. signedly-0.1.0/test/test_webhooks_api.py +94 -0
signedly-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Signedly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: signedly
3
+ Version: 0.1.0
4
+ Summary: Signedly API
5
+ Home-page: https://github.com/signedly/signedly-sdks
6
+ Author: Signedly
7
+ Author-email: info@signedly.com
8
+ License: MIT
9
+ Keywords: OpenAPI,OpenAPI-Generator,Signedly API
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: urllib3<3.0.0,>=1.25.3
13
+ Requires-Dist: python-dateutil>=2.8.2
14
+ Requires-Dist: pydantic>=2
15
+ Requires-Dist: typing-extensions>=4.7.1
16
+
17
+ The Signedly REST API lets your system upload documents, add signatories and fields, send them for signing and download the signed result. Every path starts with &#x60;/ap1/&#x60;, and every request and response body is JSON unless an endpoint says otherwise (the uploads are &#x60;multipart/form-data&#x60;). ## Authentication 1. In the Signedly web app, open **Account &amp; Settings → API** and generate a **client ID** and **client secret** for your organisation. 2. &#x60;POST /ap1/token/&#x60; with them. You get an &#x60;access_token&#x60; (valid **2 hours**) and a &#x60;refresh_token&#x60; (valid **7 days**). While both are still valid, calling &#x60;/ap1/token/&#x60; again returns the same pair. 3. Send the access token on every other call: &#x60;Authorization: Bearer &lt;access_token&gt;&#x60;. 4. When the access token expires, &#x60;POST /ap1/refreshtoken/&#x60; with the refresh token for a new access token. When the refresh token has expired too, call &#x60;/ap1/token/&#x60; again. &#x60;/ap1/token/&#x60; and &#x60;/ap1/refreshtoken/&#x60; allow 60 calls a minute per IP address; more answer 429. A missing, unknown or expired access token answers 403 (&#x60;\&quot;Client not found\&quot;&#x60; or &#x60;\&quot;Access token expired\&quot;&#x60;). The API acts for your **organisation&#39;s admin account**: documents you upload belong to it and appear in its Signedly web app, and you can reach only that account&#39;s documents, templates, signatories and fields. Another organisation&#39;s IDs answer 404, as if they didn&#39;t exist. ## Plans What the API allows depends on the Signedly plan of your **organisation&#39;s admin account** (Account &amp; Settings → Account &amp; Plan). The same rules apply to live and test keys. | What | Free | Personal Pro | Business Pro | Teams | |---|---|---|---|---| | Generate live and test keys (Account &amp; Settings → API) | – | ✓ | ✓ | ✓ | | Every endpoint, &#x60;/ap1/token/&#x60; and &#x60;/ap1/refreshtoken/&#x60; included | – | ✓ | ✓ | ✓ | | &#x60;require_email_otp&#x60; on &#x60;POST /ap1/signatories/&#x60; and &#x60;POST /ap1/signatories/bulk/&#x60; | – | ✓ | ✓ | ✓ | | Bulk send: &#x60;GET /ap1/bulk-sends/columns/&#x60; and &#x60;POST /ap1/bulk-sends/&#x60; | – | – | – | ✓ | The API is part of the paid plans. On Free (or with no plan) every call answers 403 &#x60;\&quot;... Your plan doesn&#39;t include API access.\&quot;&#x60;, with live or test keys, also with a token or keys made earlier; they work again once the plan is paid. On a paid plan, a feature it doesn&#39;t include answers 400 with &#x60;\&quot;Your plan doesn&#39;t include ...\&quot;&#x60; and changes nothing, and &#x60;GET /ap1/bulk-sends/{id}/&#x60; still reports bulk sends already made. Live documents also need an API contract with Signedly. Without one, or with an unpaid API invoice, &#x60;POST /ap1/upload/&#x60; (except templates), &#x60;/ap1/upload_app/&#x60;, &#x60;/ap1/documents/fromtemplate/&#x60; and &#x60;/ap1/bulk-sends/&#x60; answer 402 with live keys. Test keys work without a contract (see Sandbox). ## Sending a document for signing 1. &#x60;POST /ap1/upload/&#x60; a PDF or DOCX (&#x60;type&#x60; 2). The document is prepared in the background: find it in &#x60;GET /ap1/documents/?name&#x3D;&lt;name&gt;&#x60; (its &#x60;upload.id&#x60; is the upload&#39;s &#x60;id&#x60;), and wait until &#x60;GET /ap1/documents/{id}/pages/&#x60; lists its pages. 2. &#x60;POST /ap1/signatories/&#x60; (one) or &#x60;POST /ap1/signatories/bulk/&#x60; (several) to add the people who sign. 3. &#x60;POST /ap1/documents/fields/&#x60; to place the fields each signatory fills in. 4. Send it: - &#x60;POST /ap1/document/send/&#x60; emails every signatory a signing link (with ordered signing, only the first; each next one is emailed in turn), or - &#x60;POST /ap1/document/send_url/&#x60; sends no email and returns the first signatory&#39;s signing link, for you to show or send yourself. 5. Poll &#x60;GET /ap1/documents-status-list/&#x60; (or &#x60;GET /ap1/documents/&#x60;) until the status is 6 (Completed), then &#x60;GET /ap1/document/download-link/&#x60; for the signed PDF and &#x60;GET /ap1/document/download-audit-link/&#x60; for its audit trail. **From a template:** upload with &#x60;type&#x60; 4 and a &#x60;template_name&#x60; (or make the template in the web app), place its fields with &#x60;POST /ap1/templates/fields/&#x60;, then for each signing make a document with &#x60;POST /ap1/documents/fromtemplate/&#x60;, add its signatory, and send it. **One signer, one call:** &#x60;POST /ap1/upload_app/&#x60; uploads a PDF or DOCX for one signer and returns their signing link in &#x60;redirect_url&#x60;; the signer places their own signature. After signing they go to the &#x60;redirect_url&#x60; you sent, and the signed PDF and its audit trail are emailed to &#x60;final_email&#x60; (otherwise to your organisation&#39;s admin). ## Quick start with curl Each step uses an ID from the step before. &#x60;$API&#x60; is this server, e.g. &#x60;https://l0ads.signedly.com&#x60;. &#x60;&#x60;&#x60;bash # 1. Token curl -X POST $API/ap1/token/ -H &#39;Content-Type: application/json&#39; \ -d &#39;{\&quot;client_id\&quot;: \&quot;&lt;client id&gt;\&quot;, \&quot;client_secret\&quot;: \&quot;&lt;client secret&gt;\&quot;}&#39; TOKEN&#x3D;&lt;access_token from the answer&gt; # 2. Upload a PDF (answers with the upload&#39;s id) curl -X POST $API/ap1/upload/ -H \&quot;Authorization: Bearer $TOKEN\&quot; \ -F file&#x3D;@nda.pdf -F name&#x3D;nda-ann-lee -F type&#x3D;2 # 3. Find the document, then wait until it has pages curl \&quot;$API/ap1/documents/?name&#x3D;nda-ann-lee\&quot; -H \&quot;Authorization: Bearer $TOKEN\&quot; DOC&#x3D;&lt;results[0].id&gt; curl $API/ap1/documents/$DOC/pages/ -H \&quot;Authorization: Bearer $TOKEN\&quot; PAGE&#x3D;&lt;[0].id&gt; # 4. Add the signatory curl -X POST $API/ap1/signatories/ -H \&quot;Authorization: Bearer $TOKEN\&quot; \ -H &#39;Content-Type: application/json&#39; \ -d &#39;{\&quot;document_id\&quot;: \&quot;&#39;$DOC&#39;\&quot;, \&quot;name\&quot;: \&quot;Ann Lee\&quot;, \&quot;email\&quot;: \&quot;ann@example.com\&quot;}&#39; SIGNER&#x3D;&lt;id from the answer&gt; # 5. Place her signature: 150 × 40 points, 72 points from the left, 640 from the top curl -X POST $API/ap1/documents/fields/ -H \&quot;Authorization: Bearer $TOKEN\&quot; \ -H &#39;Content-Type: application/json&#39; \ -d &#39;[{\&quot;document_id\&quot;: \&quot;&#39;$DOC&#39;\&quot;, \&quot;signatory_id\&quot;: \&quot;&#39;$SIGNER&#39;\&quot;, \&quot;kind\&quot;: 2, \&quot;label\&quot;: \&quot;Signature\&quot;, \&quot;placeholder\&quot;: \&quot;Sign here\&quot;, \&quot;page\&quot;: \&quot;&#39;$PAGE&#39;\&quot;, \&quot;page_number\&quot;: 0, \&quot;x\&quot;: 72, \&quot;y\&quot;: 640, \&quot;width\&quot;: 150, \&quot;height\&quot;: 40}]&#39; # 6. Send it (Ann gets the signing email) curl -X POST $API/ap1/document/send/ -H \&quot;Authorization: Bearer $TOKEN\&quot; \ -H &#39;Content-Type: application/json&#39; \ -d &#39;{\&quot;document_id\&quot;: \&quot;&#39;$DOC&#39;\&quot;, \&quot;subject\&quot;: \&quot;Please sign the NDA\&quot;, \&quot;message\&quot;: \&quot;Hi Ann, please sign by Friday.\&quot;, \&quot;expiry_date\&quot;: \&quot;2026-12-31\&quot;}&#39; # 7. Poll until status is 6 (Completed), then get the signed PDF curl \&quot;$API/ap1/documents-status-list/?document_ids&#x3D;$DOC\&quot; -H \&quot;Authorization: Bearer $TOKEN\&quot; curl \&quot;$API/ap1/document/download-link/?id&#x3D;$DOC\&quot; -H \&quot;Authorization: Bearer $TOKEN\&quot; &#x60;&#x60;&#x60; ## Postman Import the whole API into Postman with **Import → Link** and &#x60;&lt;this server&gt;/swaggerap1/postman.json&#x60;. Set &#x60;client_id&#x60; and &#x60;client_secret&#x60; in the collection&#39;s **Variables**, run **Get an access token** (it saves the token for every other request), and set &#x60;document_id&#x60; when a request needs one. ## Webhooks Instead of polling, add an endpoint with &#x60;POST /ap1/webhooks/&#x60; (or in **Account &amp; Settings → API**) and Signedly posts your organisation&#39;s document events to it: &#x60;document.sent&#x60;, &#x60;document.viewed&#x60;, &#x60;document.signed&#x60;, &#x60;document.approved&#x60;, &#x60;document.completed&#x60;, &#x60;document.rejected&#x60; and &#x60;document.expired&#x60; (all of them, or the &#x60;events&#x60; you choose). Each is a JSON &#x60;POST&#x60;: &#x60;&#x60;&#x60;json {\&quot;id\&quot;: \&quot;5b7f…\&quot;, \&quot;type\&quot;: \&quot;document.signed\&quot;, \&quot;created_at\&quot;: \&quot;2026-10-27T09:12:00+00:00\&quot;, \&quot;test\&quot;: false, \&quot;data\&quot;: {\&quot;document\&quot;: {\&quot;id\&quot;: \&quot;6f0c…\&quot;, \&quot;name\&quot;: \&quot;nda.pdf\&quot;, \&quot;status\&quot;: 5}, \&quot;recipient\&quot;: {\&quot;id\&quot;: \&quot;0b6e…\&quot;, \&quot;email\&quot;: \&quot;ann@example.com\&quot;, \&quot;name\&quot;: \&quot;Ann Lee\&quot;, \&quot;role\&quot;: \&quot;signer\&quot;}}} &#x60;&#x60;&#x60; &#x60;recipient&#x60; is null for events no recipient caused (sent, completed, expired); &#x60;test&#x60; is true for documents made with your test keys. Fetch anything else, such as download links, with your access token: events never carry links. **Check every event is from Signedly.** The &#x60;Signedly-Signature&#x60; header is &#x60;t&#x3D;&lt;unix seconds&gt;,v1&#x3D;&lt;signature&gt;&#x60;, where the signature is the hex HMAC-SHA256 of &#x60;&lt;t&gt;.&lt;raw body&gt;&#x60; with the endpoint&#39;s secret. Refuse an event whose signature doesn&#39;t match or whose &#x60;t&#x60; is more than 5 minutes off: &#x60;&#x60;&#x60;python import hashlib, hmac, time def is_from_signedly(secret, header, raw_body): parts &#x3D; dict(item.split(\&quot;&#x3D;\&quot;, 1) for item in header.split(\&quot;,\&quot;)) signed &#x3D; f\&quot;{parts[&#39;t&#39;]}.{raw_body.decode()}\&quot;.encode() expected &#x3D; hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest() fresh &#x3D; abs(time.time() - int(parts[\&quot;t\&quot;])) &lt;&#x3D; 300 return fresh and hmac.compare_digest(parts[\&quot;v1\&quot;], expected) &#x60;&#x60;&#x60; **Answer 2xx within 10 seconds**, then do the work. Anything else is retried after 1 and 5 minutes, then 30 minutes and 2, 5 and 10 hours (7 tries in about 18 hours). &#x60;Signedly-Event-Id&#x60; is the same on every try of an event: use it to ignore repeats. After 20 events in a row fail for good, Signedly switches the endpoint off and emails your organisation&#39;s admin; switch it on again with &#x60;PUT /ap1/webhooks/{id}/&#x60; and &#x60;\&quot;is_active\&quot;: true&#x60;. Each endpoint&#39;s deliveries and their last answers are at &#x60;GET /ap1/webhooks/{id}/deliveries/&#x60;, and any can be sent again. ## Sandbox Build and test against the API without paying for documents: in **Account &amp; Settings → API**, generate your **test keys**, and get a token with them at &#x60;/ap1/token/&#x60; as usual. Everything works the same, except that what you upload or make from a template with a test token is a **test document** (&#x60;is_test&#x60; on its upload): - every page of its PDF and of its audit trail says **TEST – NOT LEGALLY BINDING**; - its emails are real, with &#x60;[TEST]&#x60; at the start of the subject; - it isn&#39;t billed or counted toward your plan; - your organisation can make 50 a calendar month (templates don&#39;t count); the next upload answers 429. ## Fields Positions and sizes are in **PDF points** (1/72 inch), measured from the **top-left corner** of the page as it is displayed (rotation applied). &#x60;page_number&#x60; counts pages from 0. A field must sit wholly on its page (1 point of tolerance); otherwise it is refused with 400. A field&#39;s page and signatory can&#39;t be changed later: delete the field and add it again. ## Status values **Document &#x60;status&#x60;:** 1 Draft · 2 Signees Added · 3 Prepared · 4 Sent · 5 In Progress · 6 Completed · 7 Rejected · 8 Archived · 9 Expired. Signatories, fields and sends are only accepted while a document is 1–3 (not yet sent). **Signatory &#x60;status&#x60;:** 1 Waiting · 2 Invited · 3 Signed · 4 Viewed · 5 Rejected. ## Lists &#x60;GET /ap1/documents/&#x60;, &#x60;/ap1/documents-status-list/&#x60;, &#x60;/ap1/templates/&#x60;, &#x60;/ap1/logs/&#x60; and &#x60;/ap1/logs/hits/&#x60; are paged: pass &#x60;limit&#x60; (default 10) and &#x60;offset&#x60;, and read &#x60;count&#x60;, &#x60;next&#x60;, &#x60;previous&#x60; and &#x60;results&#x60; from the response. ## Errors | Status | Meaning | |---|---| | 400 | The request was refused, also when your plan doesn&#39;t include it (see Plans); the body says why (&#x60;{\&quot;error\&quot;: \&quot;...\&quot;}&#x60;, or the name of each bad field with its messages). Nothing was changed. | | 403 | The access token is missing, unknown or expired; the client ID and secret or the refresh token were refused; the organisation&#39;s plan has no API access (Free, see Plans); or an &#x60;expiry_date&#x60; isn&#39;t in the future (&#x60;\&quot;Invalid Date Entered\&quot;&#x60;). | | 402 | No API contract, or an unpaid API invoice: live documents are refused (test keys keep working). | | 404 | The document, template, signatory or field doesn&#39;t exist or isn&#39;t yours. | | 429 | Too many token requests (wait a minute), or this month&#39;s 50 test documents are used. | | 5xx | Our side failed; retry later. | A send that times out may still have worked: check the document&#39;s status before sending again (a second send of a sent document answers 400). Download, view and audit links are valid for about 7 days; ask for a new one whenever you need it.
18
+
@@ -0,0 +1,453 @@
1
+ # signedly
2
+
3
+ The Signedly REST API lets your system upload documents, add signatories and
4
+ fields, send them for signing and download the signed result. Every path starts
5
+ with `/ap1/`, and every request and response body is JSON unless an endpoint says
6
+ otherwise (the uploads are `multipart/form-data`).
7
+
8
+ ## Authentication
9
+
10
+ 1. In the Signedly web app, open **Account & Settings → API** and generate a
11
+ **client ID** and **client secret** for your organisation.
12
+ 2. `POST /ap1/token/` with them. You get an `access_token` (valid **2 hours**) and
13
+ a `refresh_token` (valid **7 days**). While both are still valid, calling
14
+ `/ap1/token/` again returns the same pair.
15
+ 3. Send the access token on every other call:
16
+ `Authorization: Bearer <access_token>`.
17
+ 4. When the access token expires, `POST /ap1/refreshtoken/` with the refresh token
18
+ for a new access token. When the refresh token has expired too, call
19
+ `/ap1/token/` again.
20
+
21
+ `/ap1/token/` and `/ap1/refreshtoken/` allow 60 calls a minute per IP address;
22
+ more answer 429. A missing, unknown or expired access token answers 403
23
+ (`\"Client not found\"` or `\"Access token expired\"`).
24
+
25
+ The API acts for your **organisation's admin account**: documents you upload
26
+ belong to it and appear in its Signedly web app, and you can reach only that
27
+ account's documents, templates, signatories and fields. Another organisation's
28
+ IDs answer 404, as if they didn't exist.
29
+
30
+ ## Plans
31
+
32
+ What the API allows depends on the Signedly plan of your **organisation's admin
33
+ account** (Account & Settings → Account & Plan). The same rules apply to live and
34
+ test keys.
35
+
36
+ | What | Free | Personal Pro | Business Pro | Teams |
37
+ |---|---|---|---|---|
38
+ | Generate live and test keys (Account & Settings → API) | – | ✓ | ✓ | ✓ |
39
+ | Every endpoint, `/ap1/token/` and `/ap1/refreshtoken/` included | – | ✓ | ✓ | ✓ |
40
+ | `require_email_otp` on `POST /ap1/signatories/` and `POST /ap1/signatories/bulk/` | – | ✓ | ✓ | ✓ |
41
+ | Bulk send: `GET /ap1/bulk-sends/columns/` and `POST /ap1/bulk-sends/` | – | – | – | ✓ |
42
+
43
+ The API is part of the paid plans. On Free (or with no plan) every call answers
44
+ 403 `\"... Your plan doesn't include API access.\"`, with live or test keys, also
45
+ with a token or keys made earlier; they work again once the plan is paid. On a
46
+ paid plan, a feature it doesn't include answers 400 with
47
+ `\"Your plan doesn't include ...\"` and changes nothing, and
48
+ `GET /ap1/bulk-sends/{id}/` still reports bulk sends already made.
49
+
50
+ Live documents also need an API contract with Signedly. Without one, or with an
51
+ unpaid API invoice, `POST /ap1/upload/` (except templates), `/ap1/upload_app/`,
52
+ `/ap1/documents/fromtemplate/` and `/ap1/bulk-sends/` answer 402 with live keys.
53
+ Test keys work without a contract (see Sandbox).
54
+
55
+ ## Sending a document for signing
56
+
57
+ 1. `POST /ap1/upload/` a PDF or DOCX (`type` 2). The document is prepared in the
58
+ background: find it in `GET /ap1/documents/?name=<name>` (its `upload.id` is
59
+ the upload's `id`), and wait until `GET /ap1/documents/{id}/pages/` lists its
60
+ pages.
61
+ 2. `POST /ap1/signatories/` (one) or `POST /ap1/signatories/bulk/` (several) to
62
+ add the people who sign.
63
+ 3. `POST /ap1/documents/fields/` to place the fields each signatory fills in.
64
+ 4. Send it:
65
+ - `POST /ap1/document/send/` emails every signatory a signing link (with
66
+ ordered signing, only the first; each next one is emailed in
67
+ turn), or
68
+ - `POST /ap1/document/send_url/` sends no email and returns the first
69
+ signatory's signing link, for you to show or send yourself.
70
+ 5. Poll `GET /ap1/documents-status-list/` (or `GET /ap1/documents/`) until the
71
+ status is 6 (Completed), then `GET /ap1/document/download-link/` for the
72
+ signed PDF and `GET /ap1/document/download-audit-link/` for its audit trail.
73
+
74
+ **From a template:** upload with `type` 4 and a `template_name` (or make the
75
+ template in the web app), place its fields with `POST /ap1/templates/fields/`,
76
+ then for each signing make a document with `POST /ap1/documents/fromtemplate/`,
77
+ add its signatory, and send it.
78
+
79
+ **One signer, one call:** `POST /ap1/upload_app/` uploads a PDF or DOCX for one
80
+ signer and returns their signing link in `redirect_url`; the signer places their
81
+ own signature. After signing they go to the `redirect_url` you sent, and the
82
+ signed PDF and its audit trail are emailed to `final_email` (otherwise to your
83
+ organisation's admin).
84
+
85
+ ## Quick start with curl
86
+
87
+ Each step uses an ID from the step before. `$API` is this server, e.g.
88
+ `https://l0ads.signedly.com`.
89
+
90
+ ```bash
91
+ # 1. Token
92
+ curl -X POST $API/ap1/token/ -H 'Content-Type: application/json' \\
93
+ -d '{\"client_id\": \"<client id>\", \"client_secret\": \"<client secret>\"}'
94
+ TOKEN=<access_token from the answer>
95
+
96
+ # 2. Upload a PDF (answers with the upload's id)
97
+ curl -X POST $API/ap1/upload/ -H \"Authorization: Bearer $TOKEN\" \\
98
+ -F file=@nda.pdf -F name=nda-ann-lee -F type=2
99
+
100
+ # 3. Find the document, then wait until it has pages
101
+ curl \"$API/ap1/documents/?name=nda-ann-lee\" -H \"Authorization: Bearer $TOKEN\"
102
+ DOC=<results[0].id>
103
+ curl $API/ap1/documents/$DOC/pages/ -H \"Authorization: Bearer $TOKEN\"
104
+ PAGE=<[0].id>
105
+
106
+ # 4. Add the signatory
107
+ curl -X POST $API/ap1/signatories/ -H \"Authorization: Bearer $TOKEN\" \\
108
+ -H 'Content-Type: application/json' \\
109
+ -d '{\"document_id\": \"'$DOC'\", \"name\": \"Ann Lee\", \"email\": \"ann@example.com\"}'
110
+ SIGNER=<id from the answer>
111
+
112
+ # 5. Place her signature: 150 × 40 points, 72 points from the left, 640 from the top
113
+ curl -X POST $API/ap1/documents/fields/ -H \"Authorization: Bearer $TOKEN\" \\
114
+ -H 'Content-Type: application/json' \\
115
+ -d '[{\"document_id\": \"'$DOC'\", \"signatory_id\": \"'$SIGNER'\", \"kind\": 2,
116
+ \"label\": \"Signature\", \"placeholder\": \"Sign here\", \"page\": \"'$PAGE'\",
117
+ \"page_number\": 0, \"x\": 72, \"y\": 640, \"width\": 150, \"height\": 40}]'
118
+
119
+ # 6. Send it (Ann gets the signing email)
120
+ curl -X POST $API/ap1/document/send/ -H \"Authorization: Bearer $TOKEN\" \\
121
+ -H 'Content-Type: application/json' \\
122
+ -d '{\"document_id\": \"'$DOC'\", \"subject\": \"Please sign the NDA\",
123
+ \"message\": \"Hi Ann, please sign by Friday.\", \"expiry_date\": \"2026-12-31\"}'
124
+
125
+ # 7. Poll until status is 6 (Completed), then get the signed PDF
126
+ curl \"$API/ap1/documents-status-list/?document_ids=$DOC\" -H \"Authorization: Bearer $TOKEN\"
127
+ curl \"$API/ap1/document/download-link/?id=$DOC\" -H \"Authorization: Bearer $TOKEN\"
128
+ ```
129
+
130
+ ## Postman
131
+
132
+ Import the whole API into Postman with **Import → Link** and
133
+ `<this server>/swaggerap1/postman.json`. Set `client_id` and `client_secret` in the
134
+ collection's **Variables**, run **Get an access token** (it saves the token for
135
+ every other request), and set `document_id` when a request needs one.
136
+
137
+ ## Webhooks
138
+
139
+ Instead of polling, add an endpoint with `POST /ap1/webhooks/` (or in **Account &
140
+ Settings → API**) and Signedly posts your organisation's document events to it:
141
+ `document.sent`, `document.viewed`, `document.signed`, `document.approved`,
142
+ `document.completed`, `document.rejected` and `document.expired` (all of them,
143
+ or the `events` you choose). Each is a JSON `POST`:
144
+
145
+ ```json
146
+ {\"id\": \"5b7f…\", \"type\": \"document.signed\", \"created_at\": \"2026-10-27T09:12:00+00:00\",
147
+ \"test\": false,
148
+ \"data\": {\"document\": {\"id\": \"6f0c…\", \"name\": \"nda.pdf\", \"status\": 5},
149
+ \"recipient\": {\"id\": \"0b6e…\", \"email\": \"ann@example.com\", \"name\": \"Ann Lee\",
150
+ \"role\": \"signer\"}}}
151
+ ```
152
+
153
+ `recipient` is null for events no recipient caused (sent, completed, expired);
154
+ `test` is true for documents made with your test keys. Fetch anything else, such
155
+ as download links, with your access token: events never carry links.
156
+
157
+ **Check every event is from Signedly.** The `Signedly-Signature` header is
158
+ `t=<unix seconds>,v1=<signature>`, where the signature is the hex HMAC-SHA256 of
159
+ `<t>.<raw body>` with the endpoint's secret. Refuse an event whose signature
160
+ doesn't match or whose `t` is more than 5 minutes off:
161
+
162
+ ```python
163
+ import hashlib, hmac, time
164
+
165
+ def is_from_signedly(secret, header, raw_body):
166
+ parts = dict(item.split(\"=\", 1) for item in header.split(\",\"))
167
+ signed = f\"{parts['t']}.{raw_body.decode()}\".encode()
168
+ expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
169
+ fresh = abs(time.time() - int(parts[\"t\"])) <= 300
170
+ return fresh and hmac.compare_digest(parts[\"v1\"], expected)
171
+ ```
172
+
173
+ **Answer 2xx within 10 seconds**, then do the work. Anything else is retried after
174
+ 1 and 5 minutes, then 30 minutes and 2, 5 and 10 hours (7 tries in about 18
175
+ hours). `Signedly-Event-Id` is the same on every try of an event: use it to
176
+ ignore repeats. After 20 events in a row fail for good, Signedly switches the
177
+ endpoint off and emails your organisation's admin; switch it on again with
178
+ `PUT /ap1/webhooks/{id}/` and `\"is_active\": true`. Each endpoint's deliveries and
179
+ their last answers are at `GET /ap1/webhooks/{id}/deliveries/`, and any can be
180
+ sent again.
181
+
182
+ ## Sandbox
183
+
184
+ Build and test against the API without paying for documents: in **Account &
185
+ Settings → API**, generate your **test keys**, and get a token with them at
186
+ `/ap1/token/` as usual. Everything works the same, except that what you upload or
187
+ make from a template with a test token is a **test document** (`is_test` on its
188
+ upload):
189
+
190
+ - every page of its PDF and of its audit trail says **TEST – NOT LEGALLY BINDING**;
191
+ - its emails are real, with `[TEST]` at the start of the subject;
192
+ - it isn't billed or counted toward your plan;
193
+ - your organisation can make 50 a calendar month (templates don't count); the next
194
+ upload answers 429.
195
+
196
+ ## Fields
197
+
198
+ Positions and sizes are in **PDF points** (1/72 inch), measured from the
199
+ **top-left corner** of the page as it is displayed (rotation applied).
200
+ `page_number` counts pages from 0. A field must sit wholly on its page (1 point
201
+ of tolerance); otherwise it is refused with 400. A field's page and signatory
202
+ can't be changed later: delete the field and add it again.
203
+
204
+ ## Status values
205
+
206
+ **Document `status`:** 1 Draft · 2 Signees Added · 3 Prepared · 4 Sent ·
207
+ 5 In Progress · 6 Completed · 7 Rejected · 8 Archived · 9 Expired. Signatories,
208
+ fields and sends are only accepted while a document is 1–3 (not yet sent).
209
+
210
+ **Signatory `status`:** 1 Waiting · 2 Invited · 3 Signed · 4 Viewed · 5 Rejected.
211
+
212
+ ## Lists
213
+
214
+ `GET /ap1/documents/`, `/ap1/documents-status-list/`, `/ap1/templates/`,
215
+ `/ap1/logs/` and `/ap1/logs/hits/` are paged: pass `limit` (default 10) and
216
+ `offset`, and read `count`, `next`, `previous` and `results` from the response.
217
+
218
+ ## Errors
219
+
220
+ | Status | Meaning |
221
+ |---|---|
222
+ | 400 | The request was refused, also when your plan doesn't include it (see Plans); the body says why (`{\"error\": \"...\"}`, or the name of each bad field with its messages). Nothing was changed. |
223
+ | 403 | The access token is missing, unknown or expired; the client ID and secret or the refresh token were refused; the organisation's plan has no API access (Free, see Plans); or an `expiry_date` isn't in the future (`\"Invalid Date Entered\"`). |
224
+ | 402 | No API contract, or an unpaid API invoice: live documents are refused (test keys keep working). |
225
+ | 404 | The document, template, signatory or field doesn't exist or isn't yours. |
226
+ | 429 | Too many token requests (wait a minute), or this month's 50 test documents are used. |
227
+ | 5xx | Our side failed; retry later. |
228
+
229
+ A send that times out may still have worked: check the document's status before
230
+ sending again (a second send of a sent document answers 400).
231
+
232
+ Download, view and audit links are valid for about 7 days; ask for a new one
233
+ whenever you need it.
234
+
235
+
236
+ This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
237
+
238
+ - API version: v1
239
+ - Package version: 0.1.0
240
+ - Generator version: 7.10.0
241
+ - Build package: org.openapitools.codegen.languages.PythonClientCodegen
242
+ For more information, please visit [https://signedly.com](https://signedly.com)
243
+
244
+ ## Requirements.
245
+
246
+ Python 3.8+
247
+
248
+ ## Installation & Usage
249
+ ### pip install
250
+
251
+ If the python package is hosted on a repository, you can install directly using:
252
+
253
+ ```sh
254
+ pip install git+https://github.com/signedly/signedly-sdks.git
255
+ ```
256
+ (you may need to run `pip` with root permission: `sudo pip install git+https://github.com/signedly/signedly-sdks.git`)
257
+
258
+ Then import the package:
259
+ ```python
260
+ import signedly
261
+ ```
262
+
263
+ ### Setuptools
264
+
265
+ Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
266
+
267
+ ```sh
268
+ python setup.py install --user
269
+ ```
270
+ (or `sudo python setup.py install` to install the package for all users)
271
+
272
+ Then import the package:
273
+ ```python
274
+ import signedly
275
+ ```
276
+
277
+ ### Tests
278
+
279
+ Execute `pytest` to run the tests.
280
+
281
+ ## Getting Started
282
+
283
+ Please follow the [installation procedure](#installation--usage) and then run the following:
284
+
285
+ ```python
286
+
287
+ import signedly
288
+ from signedly.rest import ApiException
289
+ from pprint import pprint
290
+
291
+ # Defining the host is optional and defaults to https://l0ads.signedly.com
292
+ # See configuration.py for a list of all supported configuration parameters.
293
+ configuration = signedly.Configuration(
294
+ host = "https://l0ads.signedly.com"
295
+ )
296
+
297
+ # The client must configure the authentication and authorization parameters
298
+ # in accordance with the API server security policy.
299
+ # Examples for each auth method are provided below, use the example that
300
+ # satisfies your auth use case.
301
+
302
+ # Configure API key authorization: Bearer
303
+ configuration.api_key['Bearer'] = os.environ["API_KEY"]
304
+
305
+ # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed
306
+ # configuration.api_key_prefix['Bearer'] = 'Bearer'
307
+
308
+
309
+ # Enter a context with an instance of the API client
310
+ with signedly.ApiClient(configuration) as api_client:
311
+ # Create an instance of the API class
312
+ api_instance = signedly.APIRequestLogsApi(api_client)
313
+ method = 'method_example' # str | Only this HTTP method. (optional)
314
+ path = 'path_example' # str | Only paths that contain this, e.g. `/ap1/document/`. (optional)
315
+ limit = 56 # int | How many results to return (default 10). (optional)
316
+ offset = 56 # int | How many results to skip. (optional)
317
+
318
+ try:
319
+ # Count your API calls per path
320
+ api_response = api_instance.list_request_counts(method=method, path=path, limit=limit, offset=offset)
321
+ print("The response of APIRequestLogsApi->list_request_counts:\n")
322
+ pprint(api_response)
323
+ except ApiException as e:
324
+ print("Exception when calling APIRequestLogsApi->list_request_counts: %s\n" % e)
325
+
326
+ ```
327
+
328
+ ## Documentation for API Endpoints
329
+
330
+ All URIs are relative to *https://l0ads.signedly.com*
331
+
332
+ Class | Method | HTTP request | Description
333
+ ------------ | ------------- | ------------- | -------------
334
+ *APIRequestLogsApi* | [**list_request_counts**](docs/APIRequestLogsApi.md#list_request_counts) | **GET** /ap1/logs/hits/ | Count your API calls per path
335
+ *APIRequestLogsApi* | [**list_request_logs**](docs/APIRequestLogsApi.md#list_request_logs) | **GET** /ap1/logs/ | List your API calls
336
+ *AuthenticationApi* | [**get_access_token**](docs/AuthenticationApi.md#get_access_token) | **POST** /ap1/token/ | Get an access token
337
+ *AuthenticationApi* | [**refresh_access_token**](docs/AuthenticationApi.md#refresh_access_token) | **POST** /ap1/refreshtoken/ | Refresh the access token
338
+ *BulkSendingApi* | [**create_bulk_send**](docs/BulkSendingApi.md#create_bulk_send) | **POST** /ap1/bulk-sends/ | Send a template to many people
339
+ *BulkSendingApi* | [**get_bulk_send**](docs/BulkSendingApi.md#get_bulk_send) | **GET** /ap1/bulk-sends/{id}/ | Follow a bulk send
340
+ *BulkSendingApi* | [**list_bulk_send_columns**](docs/BulkSendingApi.md#list_bulk_send_columns) | **GET** /ap1/bulk-sends/columns/ | List the columns a template&#39;s bulk send needs
341
+ *DocumentsApi* | [**create_document_from_template**](docs/DocumentsApi.md#create_document_from_template) | **POST** /ap1/documents/fromtemplate/ | Make a document from a template
342
+ *DocumentsApi* | [**delete_document**](docs/DocumentsApi.md#delete_document) | **DELETE** /ap1/documents-status/{id}/ | Delete a template or an unsent document
343
+ *DocumentsApi* | [**get_download_status**](docs/DocumentsApi.md#get_download_status) | **GET** /ap1/documents-status/{id}/ | Check whether the signed PDF is ready
344
+ *DocumentsApi* | [**list_document_pages**](docs/DocumentsApi.md#list_document_pages) | **GET** /ap1/documents/{id}/pages/ | List a document&#39;s pages and their fields
345
+ *DocumentsApi* | [**list_document_statuses**](docs/DocumentsApi.md#list_document_statuses) | **GET** /ap1/documents-status-list/ | List the status of your organisation&#39;s documents
346
+ *DocumentsApi* | [**list_documents**](docs/DocumentsApi.md#list_documents) | **GET** /ap1/documents/ | List the documents this API client created
347
+ *DocumentsApi* | [**upload_document**](docs/DocumentsApi.md#upload_document) | **POST** /ap1/upload/ | Upload a document or template
348
+ *DocumentsApi* | [**upload_document_for_one_signer**](docs/DocumentsApi.md#upload_document_for_one_signer) | **POST** /ap1/upload_app/ | Upload a document for one signer and get their signing link
349
+ *DownloadsApi* | [**get_audit_trail_link**](docs/DownloadsApi.md#get_audit_trail_link) | **GET** /ap1/document/download-audit-link/ | Get a link to the audit trail
350
+ *DownloadsApi* | [**get_download_link**](docs/DownloadsApi.md#get_download_link) | **GET** /ap1/document/download-link/ | Get a link to the signed PDF
351
+ *DownloadsApi* | [**get_view_link**](docs/DownloadsApi.md#get_view_link) | **GET** /ap1/document/view-link/ | Get a link to view the document
352
+ *FieldsApi* | [**create_document_fields**](docs/FieldsApi.md#create_document_fields) | **POST** /ap1/documents/fields/ | Add fields to a document
353
+ *FieldsApi* | [**create_template_fields**](docs/FieldsApi.md#create_template_fields) | **POST** /ap1/templates/fields/ | Add fields to a template
354
+ *FieldsApi* | [**delete_field**](docs/FieldsApi.md#delete_field) | **DELETE** /ap1/documents/fields/{id}/ | Delete a field
355
+ *FieldsApi* | [**list_document_fields**](docs/FieldsApi.md#list_document_fields) | **GET** /ap1/documents/fields/ | List a document&#39;s fields
356
+ *FieldsApi* | [**list_template_fields**](docs/FieldsApi.md#list_template_fields) | **GET** /ap1/templates/fields/ | List a template&#39;s fields
357
+ *FieldsApi* | [**update_document_field**](docs/FieldsApi.md#update_document_field) | **PUT** /ap1/documents/fields/{id}/ | Change a document&#39;s field
358
+ *FieldsApi* | [**update_document_field_by_body**](docs/FieldsApi.md#update_document_field_by_body) | **PUT** /ap1/documents/fields/ | Change a document&#39;s field (ID in the body)
359
+ *FieldsApi* | [**update_template_field**](docs/FieldsApi.md#update_template_field) | **PUT** /ap1/templates/fields/{id}/ | Change a template&#39;s field
360
+ *SendingApi* | [**fill_and_send_document**](docs/SendingApi.md#fill_and_send_document) | **POST** /ap1/document/update_and_send/ | Fill in fields, add a signatory and send, in one call
361
+ *SendingApi* | [**send_document**](docs/SendingApi.md#send_document) | **POST** /ap1/document/send/ | Send a document for signing by email
362
+ *SendingApi* | [**send_document_by_link**](docs/SendingApi.md#send_document_by_link) | **POST** /ap1/document/send_url/ | Send a document and get the signing link
363
+ *SignatoriesApi* | [**create_signatories**](docs/SignatoriesApi.md#create_signatories) | **POST** /ap1/signatories/bulk/ | Add several signatories
364
+ *SignatoriesApi* | [**create_signatory**](docs/SignatoriesApi.md#create_signatory) | **POST** /ap1/signatories/ | Add a signatory
365
+ *SignatoriesApi* | [**delete_signatory**](docs/SignatoriesApi.md#delete_signatory) | **DELETE** /ap1/signatories/{id}/ | Remove a signatory
366
+ *SignatoriesApi* | [**list_signatories**](docs/SignatoriesApi.md#list_signatories) | **GET** /ap1/signatories/ | List a document&#39;s signatories
367
+ *TemplatesApi* | [**create_template_fields**](docs/TemplatesApi.md#create_template_fields) | **POST** /ap1/templates/fields/ | Add fields to a template
368
+ *TemplatesApi* | [**delete_document**](docs/TemplatesApi.md#delete_document) | **DELETE** /ap1/documents-status/{id}/ | Delete a template or an unsent document
369
+ *TemplatesApi* | [**list_template_fields**](docs/TemplatesApi.md#list_template_fields) | **GET** /ap1/templates/fields/ | List a template&#39;s fields
370
+ *TemplatesApi* | [**list_templates**](docs/TemplatesApi.md#list_templates) | **GET** /ap1/templates/ | List your organisation&#39;s templates
371
+ *TemplatesApi* | [**update_template_field**](docs/TemplatesApi.md#update_template_field) | **PUT** /ap1/templates/fields/{id}/ | Change a template&#39;s field
372
+ *WebhooksApi* | [**create_webhook_endpoint**](docs/WebhooksApi.md#create_webhook_endpoint) | **POST** /ap1/webhooks/ | Add a webhook endpoint
373
+ *WebhooksApi* | [**delete_webhook_endpoint**](docs/WebhooksApi.md#delete_webhook_endpoint) | **DELETE** /ap1/webhooks/{id}/ | Delete a webhook endpoint
374
+ *WebhooksApi* | [**get_webhook_endpoint**](docs/WebhooksApi.md#get_webhook_endpoint) | **GET** /ap1/webhooks/{id}/ | Get a webhook endpoint
375
+ *WebhooksApi* | [**list_webhook_deliveries**](docs/WebhooksApi.md#list_webhook_deliveries) | **GET** /ap1/webhooks/{id}/deliveries/ | List an endpoint&#39;s deliveries
376
+ *WebhooksApi* | [**list_webhook_endpoints**](docs/WebhooksApi.md#list_webhook_endpoints) | **GET** /ap1/webhooks/ | List your webhook endpoints
377
+ *WebhooksApi* | [**redeliver_webhook**](docs/WebhooksApi.md#redeliver_webhook) | **POST** /ap1/webhooks/deliveries/{id}/redeliver/ | Send a delivery again
378
+ *WebhooksApi* | [**rotate_webhook_secret**](docs/WebhooksApi.md#rotate_webhook_secret) | **POST** /ap1/webhooks/{id}/rotate-secret/ | Replace a webhook endpoint&#39;s secret
379
+ *WebhooksApi* | [**send_test_webhook**](docs/WebhooksApi.md#send_test_webhook) | **POST** /ap1/webhooks/{id}/test/ | Send a test event
380
+ *WebhooksApi* | [**update_webhook_endpoint**](docs/WebhooksApi.md#update_webhook_endpoint) | **PUT** /ap1/webhooks/{id}/ | Change or switch a webhook endpoint on or off
381
+
382
+
383
+ ## Documentation For Models
384
+
385
+ - [CreateBulkSend202Response](docs/CreateBulkSend202Response.md)
386
+ - [CreateBulkSendRequest](docs/CreateBulkSendRequest.md)
387
+ - [CreateDocumentFieldsRequestInner](docs/CreateDocumentFieldsRequestInner.md)
388
+ - [CreateDocumentFromTemplate200Response](docs/CreateDocumentFromTemplate200Response.md)
389
+ - [CreateDocumentFromTemplateRequest](docs/CreateDocumentFromTemplateRequest.md)
390
+ - [CreateDocumentFromTemplateRequestRecipientsInner](docs/CreateDocumentFromTemplateRequestRecipientsInner.md)
391
+ - [CreateSignatoriesRequest](docs/CreateSignatoriesRequest.md)
392
+ - [CreateSignatoriesRequestSignatoriesInner](docs/CreateSignatoriesRequestSignatoriesInner.md)
393
+ - [CreateSignatoryRequest](docs/CreateSignatoryRequest.md)
394
+ - [CreateTemplateFieldsRequestInner](docs/CreateTemplateFieldsRequestInner.md)
395
+ - [CreateWebhookEndpointRequest](docs/CreateWebhookEndpointRequest.md)
396
+ - [DeleteFieldRequest](docs/DeleteFieldRequest.md)
397
+ - [Document](docs/Document.md)
398
+ - [DocumentPage](docs/DocumentPage.md)
399
+ - [DocumentStatusPage](docs/DocumentStatusPage.md)
400
+ - [DocumentStatusRow](docs/DocumentStatusRow.md)
401
+ - [FillAndSendDocumentRequest](docs/FillAndSendDocumentRequest.md)
402
+ - [FillAndSendDocumentRequestElementsInner](docs/FillAndSendDocumentRequestElementsInner.md)
403
+ - [GetAccessTokenRequest](docs/GetAccessTokenRequest.md)
404
+ - [GetAuditTrailLink200Response](docs/GetAuditTrailLink200Response.md)
405
+ - [GetDownloadStatus200Response](docs/GetDownloadStatus200Response.md)
406
+ - [ListBulkSendColumns200ResponseInner](docs/ListBulkSendColumns200ResponseInner.md)
407
+ - [ModelField](docs/ModelField.md)
408
+ - [Page](docs/Page.md)
409
+ - [RefreshAccessToken200Response](docs/RefreshAccessToken200Response.md)
410
+ - [RefreshAccessTokenRequest](docs/RefreshAccessTokenRequest.md)
411
+ - [RequestCountPage](docs/RequestCountPage.md)
412
+ - [RequestHit](docs/RequestHit.md)
413
+ - [RequestLog](docs/RequestLog.md)
414
+ - [RequestLogPage](docs/RequestLogPage.md)
415
+ - [SendDocument200Response](docs/SendDocument200Response.md)
416
+ - [SendDocumentByLink200Response](docs/SendDocumentByLink200Response.md)
417
+ - [SendDocumentByLinkRequest](docs/SendDocumentByLinkRequest.md)
418
+ - [SendDocumentRequest](docs/SendDocumentRequest.md)
419
+ - [Signatory](docs/Signatory.md)
420
+ - [Template](docs/Template.md)
421
+ - [TemplateField](docs/TemplateField.md)
422
+ - [TemplatePage](docs/TemplatePage.md)
423
+ - [UpdateDocumentFieldByBodyRequest](docs/UpdateDocumentFieldByBodyRequest.md)
424
+ - [UpdateDocumentFieldByBodyRequestItemsInner](docs/UpdateDocumentFieldByBodyRequestItemsInner.md)
425
+ - [UpdateWebhookEndpointRequest](docs/UpdateWebhookEndpointRequest.md)
426
+ - [Upload](docs/Upload.md)
427
+ - [UploadDocumentForOneSigner200Response](docs/UploadDocumentForOneSigner200Response.md)
428
+ - [UploadDocumentForOneSignerRequest](docs/UploadDocumentForOneSignerRequest.md)
429
+ - [UploadDocumentRequest](docs/UploadDocumentRequest.md)
430
+ - [WebhookDelivery](docs/WebhookDelivery.md)
431
+ - [WebhookDeliveryPage](docs/WebhookDeliveryPage.md)
432
+ - [WebhookEndpoint](docs/WebhookEndpoint.md)
433
+ - [WebhookEndpointWithSecret](docs/WebhookEndpointWithSecret.md)
434
+
435
+
436
+ <a id="documentation-for-authorization"></a>
437
+ ## Documentation For Authorization
438
+
439
+
440
+ Authentication schemes defined for the API:
441
+ <a id="Bearer"></a>
442
+ ### Bearer
443
+
444
+ - **Type**: API key
445
+ - **API key parameter name**: Authorization
446
+ - **Location**: HTTP header
447
+
448
+
449
+ ## Author
450
+
451
+ info@signedly.com
452
+
453
+
@@ -0,0 +1,89 @@
1
+ [tool.poetry]
2
+ name = "signedly"
3
+ version = "0.1.0"
4
+ description = "Signedly API"
5
+ authors = ["Signedly <info@signedly.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ repository = "https://github.com/signedly/signedly-sdks"
9
+ keywords = ["OpenAPI", "OpenAPI-Generator", "Signedly API"]
10
+ include = ["signedly/py.typed"]
11
+
12
+ [tool.poetry.dependencies]
13
+ python = "^3.8"
14
+
15
+ urllib3 = ">= 1.25.3 < 3.0.0"
16
+ python-dateutil = ">= 2.8.2"
17
+ pydantic = ">= 2"
18
+ typing-extensions = ">= 4.7.1"
19
+
20
+ [tool.poetry.dev-dependencies]
21
+ pytest = ">= 7.2.1"
22
+ pytest-cov = ">= 2.8.1"
23
+ tox = ">= 3.9.0"
24
+ flake8 = ">= 4.0.0"
25
+ types-python-dateutil = ">= 2.8.19.14"
26
+ mypy = ">= 1.5"
27
+
28
+
29
+ [build-system]
30
+ requires = ["setuptools"]
31
+ build-backend = "setuptools.build_meta"
32
+
33
+ [tool.pylint.'MESSAGES CONTROL']
34
+ extension-pkg-whitelist = "pydantic"
35
+
36
+ [tool.mypy]
37
+ files = [
38
+ "signedly",
39
+ #"test", # auto-generated tests
40
+ "tests", # hand-written tests
41
+ ]
42
+ # TODO: enable "strict" once all these individual checks are passing
43
+ # strict = true
44
+
45
+ # List from: https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options
46
+ warn_unused_configs = true
47
+ warn_redundant_casts = true
48
+ warn_unused_ignores = true
49
+
50
+ ## Getting these passing should be easy
51
+ strict_equality = true
52
+ extra_checks = true
53
+
54
+ ## Strongly recommend enabling this one as soon as you can
55
+ check_untyped_defs = true
56
+
57
+ ## These shouldn't be too much additional work, but may be tricky to
58
+ ## get passing if you use a lot of untyped libraries
59
+ disallow_subclassing_any = true
60
+ disallow_untyped_decorators = true
61
+ disallow_any_generics = true
62
+
63
+ ### These next few are various gradations of forcing use of type annotations
64
+ #disallow_untyped_calls = true
65
+ #disallow_incomplete_defs = true
66
+ #disallow_untyped_defs = true
67
+ #
68
+ ### This one isn't too hard to get passing, but return on investment is lower
69
+ #no_implicit_reexport = true
70
+ #
71
+ ### This one can be tricky to get passing if you use a lot of untyped libraries
72
+ #warn_return_any = true
73
+
74
+ [[tool.mypy.overrides]]
75
+ module = [
76
+ "signedly.configuration",
77
+ ]
78
+ warn_unused_ignores = true
79
+ strict_equality = true
80
+ extra_checks = true
81
+ check_untyped_defs = true
82
+ disallow_subclassing_any = true
83
+ disallow_untyped_decorators = true
84
+ disallow_any_generics = true
85
+ disallow_untyped_calls = true
86
+ disallow_incomplete_defs = true
87
+ disallow_untyped_defs = true
88
+ no_implicit_reexport = true
89
+ warn_return_any = true
@@ -0,0 +1,7 @@
1
+ [flake8]
2
+ max-line-length = 99
3
+
4
+ [egg_info]
5
+ tag_build =
6
+ tag_date = 0
7
+