formable-sdk
Official Python SDK for the Formable API (v1). Covers templates, signature requests, redlining, and billing.
- Sync (
Formable) and async (AsyncFormable) clients - Fully typed requests and responses (
py.typed) - Python 3.9+
Installation
pip install formable-sdk
Usage
import os
from formable import Formable
formable = Formable(api_key=os.environ["FORMABLE_API_KEY"])
Templates
with open("nda.docx", "rb") as f:
result = formable.templates.create(
file=f.read(),
filename="nda.docx",
signer_roles=[
{"name": "Client", "order": 0},
{"name": "Witness", "order": 1},
],
)
template_id = result["templateId"]
# Mint a fresh edit URL later (expires after 1 day)
edit = formable.templates.create_edit_url(template_id)
print(edit["editUrl"], edit["expiresAt"])
Signature requests
# Formable emails each signer a signing link
request = formable.signature_requests.create(
template_id=template_id,
signers=[
{"email": "jane@example.com", "name": "Jane Doe", "role": "Client"},
{"email": "bob@example.com", "name": "Bob Smith", "role": "Witness"},
],
)
# Embedded flow: mint signing URLs to embed in an iframe yourself
embedded = formable.signature_requests.create_embedded(
template_id=template_id,
signers=[{"email": "jane@example.com", "name": "Jane Doe", "role": "Client"}],
test_mode=True,
)
signer = embedded["signers"][0]
signing = formable.signature_requests.create_signing_url(
signer["recipientSignatureId"]
)
# Track progress
from datetime import datetime, timezone
current = formable.signature_requests.get(embedded["signatureRequestId"])
all_requests = formable.signature_requests.list(
updated_since=datetime(2026, 1, 1, tzinfo=timezone.utc)
)
events = formable.signature_requests.get_events(embedded["signatureRequestId"])
# Download the signed document once completed
envelope = formable.signature_requests.get_signed_envelope(
embedded["signatureRequestId"]
)
print(envelope["signedEnvelopePresignedUrl"])
Redline requests
created = formable.redline_requests.create(
template_id=template_id,
members=[
{"email": "us@example.com", "display_name": "John Doe", "role": "DisclosingParty"},
{"email": "them@example.com", "display_name": "Jane Smith", "role": "ReceivingParty"},
],
metadata={"subject": "Mutual NDA"},
)
redline_request_id = created["redlineRequestId"]
# Mint a redline URL for a member (embed in an iframe)
url = formable.redline_requests.create_url(redline_request_id, "them@example.com")
# Manage members and track progress
formable.redline_requests.update_members(
redline_request_id,
[{"email": "counsel@example.com", "display_name": "Counsel", "role": "ReceivingCounsel"}],
)
redline = formable.redline_requests.get(redline_request_id)
events = formable.redline_requests.get_events(redline_request_id)
Billing and health
billing = formable.billing()
print(billing["numberOfRedliningSessions"])
health = formable.health()
Async client
Every method is also available on AsyncFormable with the same signatures.
import asyncio
from formable import AsyncFormable
async def main():
async with AsyncFormable(api_key=os.environ["FORMABLE_API_KEY"]) as formable:
health = await formable.health()
asyncio.run(main())
Error handling
All non-2xx responses raise a FormableError with the server's error message, HTTP status, and parsed response body.
from formable import FormableError
try:
formable.signature_requests.get("missing-id")
except FormableError as error:
print(error.status, error)
Configuration
| Option | Description | Default |
|---|---|---|
api_key |
Your Formable API key (sent as a bearer token). Required. | - |
base_url |
Override the API base URL. | https://api.formabledocs.com/v1 |
client |
Custom httpx.Client (or httpx.AsyncClient for async). |
Built-in client with 60s timeout |
Development
python3 -m venv .venv
.venv/bin/pip install -e . pytest mypy build
.venv/bin/python -m pytest tests
.venv/bin/python -m mypy src/formable
Publishing
.venv/bin/python -m build
.venv/bin/python -m pip install twine
.venv/bin/python -m twine upload dist/*
Metadata
Release files for formable-sdk 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| formable_sdk-0.1.1.tar.gz | 9.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| formable_sdk-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.6 kB
Release files / formable_sdk-0.1.1.tar.gz
| Download URL | formable_sdk-0.1.1.tar.gz |
|---|---|
| Size | 9.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
05be6e94714a2fc7f8a85870d1a6151d905258b78115d56eb434acfb161b5d92
|
|
BLAKE2b-256 checksum How to use checksums |
0f800cdcef22103a90ea52eecdc52c8db0dd880207784b82aaebe7835522dbee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / formable_sdk-0.1.1-py3-none-any.whl
| Download URL | formable_sdk-0.1.1-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5a7f6790771129ab67f44cd7ec7ebd6ae683d3fac3620a513fbc8cf8a78d3b68
|
|
BLAKE2b-256 checksum How to use checksums |
1b4021f4dc77f8b34243332f012600ab4f0397bc26f6e57b3abe6a34c502f5de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|