easycontract — SDK de Python
SDK oficial del API de firma electrónica de easycontract (SES/AdES bajo eIDAS, con paquete de evidencias defendible en litigio).
pip install easycontract
from easycontract import EasyContract
client = EasyContract(api_key="ec_test_...") # ec_live_... en producción
print(client.whoami())
- Modo test de primera clase: una clave
ec_test_…opera sobre datos aislados (TSA/PAdES simulados). Nadie debería firmar un documento real para probar la integración. - Idempotencia automática: todo POST lleva
Idempotency-Key(uuid4); pásala tú misma para reintentos seguros de tu lado. - Reintentos: 429 (respetando
Retry-After) y 5xx en GETs. - Errores tipados con el
codeestable del API:AuthenticationError,RateLimitError,ForbiddenError(cuota/feature/ regla de membresía),InvalidRequestError,NotFoundError,ConflictError,ServerError.
Receta 1 — Enviar un envelope desde plantilla (el flujo RootedCON)
Una sola llamada: cubre los roles, envía, y recibe los enlaces de firma.
result = client.templates.create_envelope(
template_id,
signers={"ponente": {"full_name": "Ada Lovelace", "email": "ada@example.com"}},
title="Contrato ponencia RootedCON 2027 — Ada Lovelace",
send=True, # congela hashes, plan y retención, y acuña enlaces
deliver_emails=True, # easycontract envía los emails con los enlaces
)
envelope_id = result["envelope"]["id"]
Creación de la plantilla (una vez):
template = client.templates.create(name="Contrato ponente", retention_period_months=72)
doc = client.templates.add_document(template["id"], file="contrato-ponente.pdf")
client.templates.add_role(template["id"], key="ponente", label="Ponente")
client.templates.add_field(
template["id"],
document_id=doc["id"],
role="ponente",
anchor_text="Fdo. el ponente:", # la firma se estampa donde el PDF lo dice
)
Receta 2 — Firma embebida (embedded signing)
Con deliver_emails=False recibes el sign_url de un solo uso por firmante y
lo integras en tu propia aplicación (redirect o iframe):
result = client.templates.create_envelope(
template_id,
signers={...},
send=True,
deliver_emails=False,
)
sign_url = result["signers"][0]["sign_url"]
# → redirige al ponente a sign_url sin salir de tu flujo
El enlace es personal, caduca (14 días por defecto, expires_in_days para
cambiarlo) y queda invalidado al firmar o rechazar.
Receta 3 — Webhooks vs. polling
Webhooks (recomendado): registra un endpoint y verifica CADA entrega.
endpoint = client.webhooks.create(url="https://miapp.com/hooks/easycontract")
WEBHOOK_SECRET = endpoint["secret"] # whsec_… — se muestra UNA sola vez
# En tu receptor (Django/Flask/FastAPI):
from easycontract import webhooks
event = webhooks.verify_signature(
payload=request.body,
header=request.headers["X-EasyContract-Signature"],
secret=WEBHOOK_SECRET,
)
if event["type"] == "envelope.completed":
...
Reconciliación / polling: los webhooks son la proyección de un event log consultable; si pierdes una entrega, reconcilia:
for event in client.events.auto_paging_iter(type="envelope.completed"):
...
Receta 4 — Descargar el paquete de evidencias
El ZIP completo (documentos, certificado, audit trail JSON verificable offline, sellos TSA) — lo que un tenant llevaría a un juzgado:
client.envelopes.download_evidence(envelope_id, to="evidencias.zip")
client.envelopes.download_certificate(envelope_id, to="certificado.pdf")
Receta 5 — Gestión de plantillas
for template in client.templates.list()["data"]:
print(template["name"])
detail = client.templates.get(template_id, expand=["documents", "roles", "fields"])
client.templates.delete(old_template_id)
Envelope manual (sin plantilla)
envelope = client.envelopes.create(
title="NDA",
retention_period_months=60, # retención SIEMPRE explícita
)
client.envelopes.add_document(envelope["id"], file="nda.pdf")
client.envelopes.add_signer(
envelope["id"],
full_name="Grace Hopper",
email="grace@example.com",
auth_methods=["email_link", "sms_otp"],
phone="+34600111222", # OTP: plan Pro+
)
sent = client.envelopes.send(envelope["id"])
Organización, miembros e invitaciones
org = client.organization.get() # plan, límites y features del plan
members = client.members.list()
invite = client.invitations.create(email="colega@example.com", role="member")
# invite["accept_url"] — entrégalo tú o deja que easycontract lo envíe por email
Release files for easycontract 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| easycontract-0.1.0.tar.gz | 17.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| easycontract-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.3 kB
Release files / easycontract-0.1.0.tar.gz
| Download URL | easycontract-0.1.0.tar.gz |
|---|---|
| Size | 17.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c3e7c37c518dfc3699b81e9827d8a527596b3a883d4264258440d5994f49db2d
|
|
BLAKE2b-256 checksum How to use checksums |
4612907ced303a91895457541c1b7ab03b2377a773ac02038b9fc40d536d1119
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Release files / easycontract-0.1.0-py3-none-any.whl
| Download URL | easycontract-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35b89e32f3e317aca9a6d3fdde0677aeb9ba502ce9983905da45b887a6357668
|
|
BLAKE2b-256 checksum How to use checksums |
d9a1d4af60c6263d240370e9ab1c1da985306ca9fd1d7b7edd203820f7a8aa83
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|