Skip to main content

SignYu Python SDK

Official Python SDK for the SignYu Aadhaar eSign API. Upload a PDF, add signers, and send it for legally valid Aadhaar OTP based eSignature under the IT Act 2000, all from your backend.

  • Python 3.9 or newer, built on httpx
  • Fully typed (py.typed, TypedDict responses)
  • Webhook signature verification with constant time comparison

API docs: https://signyu.com/docs. API overview and pricing: https://signyu.com/api (signatures from ₹15 each on credit packs of 10 or more).

Install

pip install signyu

Quickstart

from signyu import SignYu

client = SignYu(api_key="sk_live_...")  # or set SIGNYU_API_KEY

# 1. Upload the PDF (a path, bytes, or a binary file object)
doc = client.documents.create(file="agreement.pdf", name="Service Agreement")

# 2. Add signers (they sign in this order, up to 6 per document)
client.documents.add_signers(doc["documentId"], [
    {"name": "Asha Rao", "phone": "9876543210", "email": "asha@example.com"},
    {"name": "Vikram Nair", "phone": "9812345678", "email": "vikram@example.com"},
])

# 3. Send: deducts one credit per signer and emails each signer a link
sent = client.documents.send(doc["documentId"])
print([s["signUrl"] for s in sent["signers"]])

# 4. Check progress (or use webhooks)
status = client.documents.get(doc["documentId"])
print(status["status"])  # PENDING, SENT or COMPLETED

Responses are plain dicts with the API's camelCase keys, typed as TypedDicts in signyu.types.

Get your API key from the dashboard under Developers (https://signyu.com/app/developers). Keep it on your server.

Configuration

client = SignYu(
    api_key="sk_live_...",          # or the SIGNYU_API_KEY environment variable
    base_url="https://signyu.com",  # optional
    timeout=60.0,                   # optional, seconds
    http_client=None,               # optional, your own httpx.Client
)

The client can be used as a context manager (with SignYu(...) as client:) or closed with client.close().

Methods

client.documents.create(file, name=None, file_name=None)

POST /api/v1/documents. Uploads a PDF (at most 10MB) and creates a document in PENDING state. file can be a path (str or pathlib.Path), bytes, or a binary file object. It is always sent as application/pdf. name defaults to the file name.

Returns {"documentId", "name", "status"}.

client.documents.list(limit=None, offset=None)

GET /api/v1/documents. Your documents, most recent first. limit is 1 to 100 (default 20), offset defaults to 0.

Returns {"documents": [{"documentId", "name", "status", "createdAt", "signers": {"total", "signed"}}], "limit", "offset"}.

client.documents.get(document_id)

GET /api/v1/documents/{documentId}. Status and per-signer progress. Once COMPLETED, downloadUrl is a temporary presigned link to the signed PDF and certificateUrl points at the certificate endpoint. Each signer's signUrl is None until the document is sent.

client.documents.add_signers(document_id, signers)

POST /api/v1/documents/{documentId}/signers. Only while the document is PENDING. Each signer needs name, phone (digits only, at least 10) and email. At most 6 signers per document.

Optional custom stamp placement (PDF points, origin at the bottom-left of the page, box at least 140 x 110, one box per page):

client.documents.add_signers(document_id, [{
    "name": "Asha Rao",
    "phone": "9876543210",
    "email": "asha@example.com",
    "advanced": {
        "signaturePlacement": {
            "positions": [{"page": 2, "x": 31, "y": 257, "width": 253, "height": 110}],
        },
    },
}])

client.documents.send(document_id)

POST /api/v1/documents/{documentId}/send. Deducts one credit per signer, marks the document SENT, emails each signer a signing link and returns the links. Call it once per document.

Returns {"documentId", "status": "SENT", "creditsRemaining", "signers": [{"signerId", "name", "email", "signingOrder", "signUrl"}]}.

client.documents.get_certificate(document_id)

GET /api/v1/documents/{documentId}/certificate. Returns the completion certificate and audit trail PDF as bytes. Only available once the document is COMPLETED, otherwise it raises SignYuError with code invalid_state (409).

with open("certificate.pdf", "wb") as fh:
    fh.write(client.documents.get_certificate(document_id))

Webhooks

SignYu sends signer.signed and document.completed events as a JSON POST. Each request carries an X-SignSetu-Signature: sha256=<hex> header, an HMAC-SHA256 of the raw request body keyed with your endpoint's signing secret (whsec_..., shown in the dashboard). Always verify against the raw body bytes.

import os
from flask import Flask, request, abort
import signyu

app = Flask(__name__)

@app.post("/webhooks/signyu")
def signyu_webhook():
    try:
        event = signyu.webhooks.construct_event(
            request.get_data(),  # raw bytes
            request.headers.get("X-SignSetu-Signature"),
            os.environ["SIGNYU_WEBHOOK_SECRET"],
        )
    except signyu.WebhookSignatureError:
        abort(400)

    if event["event"] == "document.completed":
        ...  # event["certificateUrl"], event["signers"]
    return "", 200

signyu.webhooks.verify_signature(raw_body, header, secret) returns a bool if you prefer to handle it yourself. Deliveries can repeat, so make your handler idempotent.

Errors

Every non-2xx response raises signyu.SignYuError:

from signyu import SignYuError

try:
    client.documents.send(document_id)
except SignYuError as err:
    print(err.status)   # 402
    print(err.code)     # "insufficient_credits"
    print(err.message)  # "You need 2 credits to send this document."
Status code Meaning
400 invalid_content_type, invalid_request, invalid_file, no_signers, signer_limit_reached The request is invalid.
401 unauthorized Missing or invalid API key.
402 insufficient_credits Not enough credits to send.
403 api_access_not_enabled The account has no API access subscription.
404 not_found The document does not exist or is not yours.
409 invalid_state Not allowed in the document's current state.
413 file_too_large The PDF is over 10MB.
429 rate_limited Too many requests, retry with backoff.
500 internal_error Something went wrong on our side.
0 connection_error, timeout The request never got a response.

Retry 429 and 5xx with backoff. Do not blindly retry send, since a successful send that timed out on your side would charge credits again.

License

MIT

Metadata

Release files for signyu 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for signyu 0.1.0
File Size Uploaded
signyu-0.1.0.tar.gz 10.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for signyu 0.1.0
File Interpreter ABI Platform
signyu-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 21.5 kB

Release files / signyu-0.1.0.tar.gz

Download URL signyu-0.1.0.tar.gz
Size 10.7 kB
Tags Source
SHA-256 checksum
How to use checksums
22447fa96e3a2398ce162d514dd4e264f2d25f7e58d53818fd00d86a308781c6
BLAKE2b-256 checksum
How to use checksums
68bd8c3167ed029159916bbff9b7bfc656e8537155a359133a0f4260f3411844
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / signyu-0.1.0-py3-none-any.whl

Download URL signyu-0.1.0-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
65d2db05ac1ed3737afe224c943fb47f5d860a9851300248dba69afa73dcb5eb
BLAKE2b-256 checksum
How to use checksums
c0a9227c49b1a48acfbe9c0f2646203ee74805d98fd8824449e623902bcb8112
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page