Skill: byungkyu/signnow (version 1.0.3)

--- name: signnow description: | SignNow API integration with managed OAuth. E-signature platform for sending, signing, and managing documents. Use this skill when users want to upload documents, send signature invites, create templates, or manage e-signature workflows. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key. metadata: author: maton version: "1.0" clawdbot: emoji: 🧠 requires: env: - MATON_API_KEY --- # SignNow Access the SignNow API with managed OAuth authentication. Upload documents, send signature invites, manage templates, and automate e-signature workflows. ## Quick Start ```bash # Get current user info python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/signnow/user') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` ## Base URL ``` https://api.maton.ai/signnow/{resource} ``` Maton proxies requests to `api.signnow.com` and automatically injects your OAuth token. ## Authentication All requests require the Maton API key in the Authorization header: ``` Authorization: Bearer $MATON_API_KEY ``` **Environment Variable:** Set your API key as `MATON_API_KEY`: ```bash export MATON_API_KEY="YOUR_API_KEY" ``` ### Getting Your API Key 1. Sign in or create an account at [maton.ai](https://maton.ai) 2. Go to [maton.ai/settings](https://maton.ai/settings) 3. Copy your API key ## Connection Management Manage your SignNow OAuth connections at `https://api.maton.ai`. ### List Connections ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/connections?app=signnow&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` ### Create Connection ```bash python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'signnow'}).encode() req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` ### Get Connection ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` **Response:** ```json { "connection": { "connection_id": "{connection_id}", "status": "ACTIVE", "creation_time": "2026-02-08T20:47:23.019763Z", "last_updated_time": "2026-02-08T20:50:32.210896Z", "url": "https://connect.maton.ai/?session_token=...", "app": "signnow", "metadata": {} } } ``` Open the returned `url` in a browser to complete OAuth authorization. ### Delete Connection ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` ### Specifying Connection If you have multiple SignNow connections, specify which one to use with the `Maton-Connection` header: ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/signnow/user') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '{connection_id}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` If you have multiple connections, always include this header to ensure requests go to the intended account. ## Security & Permissions - Access is scoped to documents, templates, signing invites, and folders within the connected SignNow account. - **All write operations require explicit user approval.** Before executing any create, update, or delete call, confirm the target resource and intended effect with the user. ## API Reference ### User Operations #### Get Current User ```bash GET /signnow/user ``` **Response:** ```json { "id": [REDACTED_SECRET], "first_name": "Chris", "last_name": "Kim", "active": "1", "verified": true, "emails": ["[REDACTED_SECRET]"], "primary_email": "[REDACTED_SECRET]", "document_count": 0, "subscriptions": [...], "teams": [...], "organization": {...} } ``` #### Get User Documents ```bash GET /signnow/user/documents ``` **Response:** ```json [ { "id": [REDACTED_SECRET], "document_name": "Contract", "page_count": "3", "created": "1770598603", "updated": "1770598603", "original_filename": "contract.pdf", "owner": "[REDACTED_SECRET]", "template": false, "roles": [], "field_invites": [], "signatures": [] } ] ``` ### Document Operations #### Upload Document Documents must be uploaded as multipart form data with a PDF file: ```bash python <<'EOF' import urllib.request, os, json def encode_multipart_formdata(files): boundary = [REDACTED_SECRET] lines = [] for (key, filename, content) in files: lines.append(f'--{boundary}'.encode()) lines.append(f'Content-Disposition: form-data; name="{key}"; filename="{filename}"'.encode()) lines.append(b'Content-Type: application/pdf') lines.append(b'') lines.append(content) lines.append(f'--{boundary}--'.encode()) lines.append(b'') body = b'\r\n'.join(lines) content_type = f'multipart/form-data; boundary={boundary}' return content_type, body with open('document.pdf', 'rb') as f: file_content = f.read() content_type, body = encode_multipart_formdata([('file', 'document.pdf', file_content)]) req = urllib.request.Request('https://api.maton.ai/signnow/document', data=body, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', content_type) print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` **Response:** ```json { "id": [REDACTED_SECRET] } ``` #### Get Document ```bash GET /signnow/document/{document_id} ``` **Response:** ```json { "id": [REDACTED_SECRET], "document_name": "Contract", "page_count": "3", "created": "1770598603", "updated": "1770598603", "original_filename": "contract.pdf", "owner": "[REDACTED_SECRET]", "template": false, "roles": [], "viewer_roles": [], "attachments": [], "fields": [], "signatures": [], "texts": [], "checks": [] } ``` #### Update Document ```bash PUT /signnow/document/{document_id} Content-Type: application/json { "document_name": "Updated Contract Name" } ``` **Response:** ```json { "id": [REDACTED_SECRET], "signatures": [], "texts": [], "checks": [] } ``` #### Download Document ```bash GET /signnow/document/{document_id}/download?type=collapsed ``` Returns the PDF file as binary data. Query parameters: - `type` - Download type: `collapsed` (flattened PDF), `zip` (all pages as images) #### Get Document History ```bash GET /signnow/document/{document_id}/historyfull ``` **Response:** ```json [ { "unique_id": [REDACTED_SECRET], "user_id": [REDACTED_SECRET], "document_id": [REDACTED_SECRET], "email": "[REDACTED_SECRET]", "created": 1770598603, "event": "created_document" } ] ``` #### Move Document to Folder ```bash POST /signnow/document/{document_id}/move Content-Type: application/json { "folder_id": [REDACTED_SECRET] } ``` **Response:** ```json { "result": "success" } ``` #### Merge Documents Combines multiple documents into a single PDF: ```bash POST /signnow/document/merge Content-Type: application/json { "name": "Merged Document", "document_ids": ["doc_id_1", "doc_id_2"] } ``` Returns the merged PDF as binary data. #### Delete Document ```bash DELETE /signnow/document/{document_id} ``` **Response:** ```json { "status": "success" } ``` ### Template Operations #### Create Template from Document ```bash POST /signnow/template Content-Type: application/json { "document_id": [REDACTED_SECRET], "document_name": "Contract Template" } ``` **Response:** ```json { "id": [REDACTED_SECRET] } ``` #### Create Document from Template ```bash POST /signnow/template/{template_id}/copy Content-Type: application/json { "document_name": "New Contract from Template" } ``` **Response:** ```json { "id": [REDACTED_SECRET], "name": "New Contract from Template" } ``` ### Signature Invite Operations #### Send Freeform Invite Send a document for signature: ```bash POST /signnow/document/{document_id}/invite Content-Type: application/json { "to": "[REDACTED_SECRET]", "from": "[REDACTED_SECRET]" } ``` **Response:** ```json { "result": "success", "id": [REDACTED_SECRET], "callback_url": "none" } ``` **Note:** Custom subject and message require a paid subscription plan. #### Create Signing Link Create an embeddable signing link (requires document fields): ```bash POST /signnow/link Content-Type: application/json { "document_id": [REDACTED_SECRET] } ``` **Note:** Document must have signature fields added before creating a signing link. ### Folder Operations #### Get All Folders ```bash GET /signnow/folder ``` **Response:** ```json { "id": [REDACTED_SECRET], "name": "Root", "system_folder": true, "folders": [ { "id": [REDACTED_SECRET], "name": "Documents", "document_count": "5", "template_count": "2" }, { "id": [REDACTED_SECRET], "name": "Templates", "document_count": "0", "template_count": "3" }, { "id": [REDACTED_SECRET], "name": "Trash Bin", "document_count": "0" } ], "total_documents": 0, "documents": [] } ``` #### Get Folder by ID ```bash GET /signnow/folder/{folder_id} ``` **Response:** ```json { "id": [REDACTED_SECRET], "name": "Documents", "user_id": [REDACTED_SECRET], "parent_id": [REDACTED_SECRET], "system_folder": true, "folders": [], "total_documents": 5, "documents": [...] } ``` ### Webhook (Event Subscription) Operations #### List Event Subscriptions ```bash GET /signnow/event_subscription ``` **Response:** ```json { "subscriptions": [ { "id": [REDACTED_SECRET], "event": "document.complete", "created": "1770598678", "callback_url": "https://example.com/webhook" } ] } ``` #### Create Event Subscription ```bash POST /signnow/event_subscription Content-Type: application/json { "event": "document.complete", "callback_url": "https://example.com/webhook" } ``` **Response:** ```json { "id": [REDACTED_SECRET], "created": 1770598678 } ``` **Available Events:** - `document.create` - Document created - `document.update` - Document updated - `document.delete` - Document deleted - `document.complete` - Document signed by all parties - `invite.create` - Invite sent - `invite.update` - Invite updated #### Delete Event Subscription ```bash DELETE /signnow/event_subscription/{subscription_id} ``` **Response:** ```json { "id": [REDACTED_SECRET], "status": "deleted" } ``` ## Code Examples ### JavaScript ```javascript const response = await fetch( 'https://api.maton.ai/signnow/user', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const data = await response.json(); ``` ### Python ```python import os import requests response = requests.get( 'https://api.maton.ai/signnow/user', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json() ``` ### Python (Upload Document) ```python import os import requests with open('document.pdf', 'rb') as f: response = requests.post( 'https://api.maton.ai/signnow/document', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}, files={'file': ('document.pdf', f, 'application/pdf')} ) doc = response.json() print(f"Uploaded document: {doc['id']}") ``` ### Python (Send Invite) ```python import os import requests doc_id = [REDACTED_SECRET] response = requests.post( f'https://api.maton.ai/signnow/document/{doc_id}/invite', headers={ 'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}', 'Content-Type': 'application/json' }, json={ 'to': '[REDACTED_SECRET]', 'from': '[REDACTED_SECRET]' } ) result = response.json() print(f"Invite sent: {result['id']}") ``` ## Notes - Documents must be in PDF format for upload - Supported file types: PDF, DOC, DOCX, ODT, RTF, PNG, JPG - System folders (Documents, Templates, Archive, Trash Bin) cannot be renamed or deleted - Creating signing links requires documents to have signature fields - Custom invite subject/message requires a paid subscription - Rate limit in development mode: 500 requests/hour per application - IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments ## Error Handling | Status | Meaning | |--------|---------| | 400 | Missing SignNow connection or bad request | | 401 | Invalid or missing Maton API key | | 403 | Insufficient permissions or subscription required | | 404 | Resource not found | | 405 | Method not allowed | | 429 | Rate limited | | 4xx/5xx | Passthrough error from SignNow API | SignNow errors include detailed messages: ```json { "errors": [ { "code": 65578, "message": "Invalid file type." } ] } ``` ### Troubleshooting: API Key Issues 1. Check that the `MATON_API_KEY` environment variable is set: ```bash echo $MATON_API_KEY ``` 2. Verify the API key is valid by listing connections: ```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://api.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ``` ### Troubleshooting: Invalid App Name 1. Ensure your URL path starts with `signnow`. For example: - Correct: `https://api.maton.ai/signnow/user` - Incorrect: `https://api.maton.ai/user` ## Resources - [SignNow API Reference](https://docs.signnow.com/docs/signnow/reference) - [SignNow Developer Portal](https://www.signnow.com/developers) - [SignNow Postman Collection](https://github.com/signnow/postman-collection) - [SignNow SDKs](https://github.com/signnow) - [Maton Community](https://discord.com/invite/dBfFAcefs2) - [Maton Support](mailto:[REDACTED_SECRET])


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)