Integração com Python em poucos minutos
Exemplos prontos para copiar com requests e Flask: criar assinatura, consultar status, baixar o PDF e validar webhooks.
Sem bibliotecas extras: só HTTP. Execute sempre no servidor — a chave de API nunca vai para o navegador.
1.Carimbo e nome do anexo
Na qualificada, escolha first, last ou all; page prevalece sobre pageIndex (0-based). delivery.filename na criação simples ou qualificada define o nome do anexo sem ativar envios. No reenvio, substitui só aquela chamada. Acentos preservados, extensão PDF. Cobrança por pessoa/canal, com estorno em falha; indisponível para contas Prescri.
entrega.pysig = client.create_qualified_signature( provider="birdid", document_name="Relatório", signer_cpf=signer_cpf, pdf_base64=pdf_b64, stamp_options={"page": "all", "position": "bottom-right"}, delivery={"filename": "Relatório Médico.pdf"}, ) # Depois de consultar status signed: client.deliver_signature(sig["signature_id"], ["email"], filename="Relatório Final.pdf")2.Envelopes: contrato e anexos no mesmo link
Até 10 PDFs, mesmos signatários e confirmação única. Cada documento concluído consome uma unidade. Baixe o ZIP ou um PDF individual após a conclusão.
envelope.pyenvelope = client.create_simple_signature( document_name="Contrato e anexos", documents=[{"document_name": "Contrato", "pdf_base64": contrato_b64}, {"document_name": "Anexo", "pdf_base64": anexo_b64}], signers=[{"full_name": "Maria Exemplo", "email": "maria@example.com"}], send_email_invitation=True, ) zip_bytes = client.download_pdf(envelope["signature_id"], format="zip")3.SDK leve (opcional, sem dependências)
Prefere um cliente pronto? Copie a pasta sdk/python do repositório: usa só a biblioteca padrão e inclui validação de webhook.
uso.pyfrom assinatura_online import AssinaturaClient, verify_webhook client = AssinaturaClient(api_key=os.environ["ASSINATURA_API_KEY"], api_secret=os.environ["ASSINATURA_API_SECRET"]) sig = client.create_simple_signature( document_name="Contrato", pdf_base64=pdf_b64, signers=[{"full_name": "Maria Exemplo", "email": "maria@example.com"}], send_email_invitation=True, ) status = client.get_signature(sig["signature_id"]) pdf_bytes = client.download_pdf(sig["signature_id"])4.Instale e configure
Só a biblioteca requests. Guarde as credenciais em variáveis de ambiente do servidor.
terminalpip install requests export ASSINATURA_API_KEY=sk_sua_chave export ASSINATURA_API_SECRET=seu_segredo_de_webhook5.Crie uma assinatura simples
O signatário recebe o convite por e-mail e confirma com um código. A resposta traz o sign_url.
criar_assinatura.pyimport base64, os, requests BASE = "https://assinatura.online/api/public/v1" HEADERS = {"X-API-Key": os.environ["ASSINATURA_API_KEY"], "X-API-Secret": os.environ["ASSINATURA_API_SECRET"]} def criar_assinatura(caminho_pdf: str) -> dict: with open(caminho_pdf, "rb") as f: pdf_b64 = base64.b64encode(f.read()).decode() r = requests.post(f"{BASE}/signatures/create", headers=HEADERS, timeout=30, json={ "mode": "simple", "document_name": "Contrato de prestação de serviços", "pdf_base64": pdf_b64, "signer": {"full_name": "Maria Exemplo", "email": "maria@example.com"}, "send_email_invitation": True, "external_id": "pedido-123", }) data = r.json() if not r.ok: raise RuntimeError(f"{data.get('code')}: {data.get('error')}") return data # signature_id, status, sign_url6.Assinatura qualificada com Bird ID ou VIDaaS
Troque o modo pelo provedor e informe o CPF do titular do certificado.
qualificada.pyrequests.post(f"{BASE}/signatures/create", headers=HEADERS, timeout=30, json={ "provider": "vidaas", # ou "birdid" / "a1" "document_name": "Laudo técnico", "pdf_base64": pdf_b64, "signer": {"cpf": "52998224725", "full_name": "Ana Exemplo"}, })7.Consulte o status e baixe o PDF
Use para conferir o resultado no servidor. O PDF fica disponível após a conclusão.
status.pyinfo = requests.get(f"{BASE}/signatures/get", headers=HEADERS, params={"signature_id": sid}, timeout=30).json() print(info["status"]) pdf = requests.get(f"{BASE}/signatures/pdf", headers=HEADERS, params={"signature_id": sid}, timeout=60) open("assinado.pdf", "wb").write(pdf.content)8.Valide o webhook (HMAC-SHA256) — Flask
Leia o corpo bruto, confira a assinatura e só então processe o evento.
webhook.pyimport hashlib, hmac, json, os, re, time from flask import Flask, abort, request app = Flask(__name__) TOLERANCIA_S = 300 # mesma tolerância do verify_webhook do SDK V1 = re.compile(r"(?:^|,)\s*v1=([0-9a-fA-F]{64})(?:,|$)") def webhook_valido(ts: str, header: str, raw: bytes) -> bool: if not re.fullmatch(r"[0-9]{1,12}", ts): # Unix em segundos (só ASCII) return False if abs(int(time.time()) - int(ts)) > TOLERANCIA_S: # passado ou futuro return False m = V1.search(header) if not m: # 64 hex antes de comparar return False esperado = hmac.new(os.environ["ASSINATURA_API_SECRET"].encode(), ts.encode() + b"." + raw, hashlib.sha256).hexdigest() return hmac.compare_digest(m.group(1).lower(), esperado) @app.post("/webhooks/assinatura") def webhook(): raw = request.get_data() # corpo BRUTO, sem reserializar if not webhook_valido(request.headers.get("X-Assinatura-Timestamp", ""), request.headers.get("X-Assinatura-Signature", ""), raw): abort(401) evento = json.loads(raw) # Este exemplo trata apenas signature.completed; outros eventos são só reconhecidos. if evento.get("event") != "signature.completed": return "ok" # 1) Confirme no servidor ANTES de qualquer efeito. Sem confirmação → 503 (nova tentativa). try: status = consultar_status(evento["signature_id"]) # GET /signatures/get except Exception: status = None if status != "signed": return "status não confirmado", 503 # 2) Atualize o pedido E registre a deduplicação na MESMA transação (integração sua). # Para completed, signature_id + event identifica o evento. Não serve para todos: # participant_signed ocorre várias vezes — inclua signer e signed_at na chave. try: marcar_assinado_e_deduplicar( chave=f"{evento['signature_id']}:{evento['event']}", external_id=evento.get("external_id"), ) # ex.: BEGIN; INSERT dedup (chave única) ON CONFLICT DO NOTHING; UPDATE pedido; COMMIT except Exception: return "falha temporária", 503 # nada confirmado; a retentativa reprocessa return "ok" # 2xx só depois do COMMIT (ou se a chave já existia)9.A1 direto com retentativa segura
O certificado é conferido antes de qualquer gravação e usado só em memória; a resposta já vem com status signed e o PDF. Após um timeout, repita com a mesma Idempotency-Key. Para não reenviar o arquivo a cada chamada, veja a sessão A1 opcional (até 7 dias) em assinatura.online/documentacao#a1-direto.
a1_direto.pyr = requests.post(f"{BASE}/signatures/create", timeout=60, headers={**HEADERS, "Idempotency-Key": "contrato-2431-v1"}, json={"provider": "a1", "document_name": "Contrato de prestação de serviço", "pdf_base64": pdf_b64, "signer": {"cpf": "52998224725"}, "a1_pfx_base64": pfx_b64, "a1_password": os.environ["A1_PASSWORD"]}) data = r.json() # erro após criar traz data["signature_id"]
Prompt para Cursor, Claude ou Lovable
Cole na sua ferramenta de IA para gerar a integração no seu projeto.
Integre a API da assinatura.online neste projeto Python, apenas no servidor.
Base: https://assinatura.online/api/public/v1, headers X-API-Key: <ASSINATURA_API_KEY> e X-API-Secret: <ASSINATURA_API_SECRET>. Na assinatura qualificada (birdid, vidaas ou a1), use o header Idempotency-Key em retentativas de POST /signatures/create; ele não se aplica ao mode "simple".
1) Função que faz POST /signatures/create com mode "simple", document_name, pdf_base64, signer { full_name, email }, send_email_invitation: True e external_id; retorne signature_id e sign_url.
2) GET /signatures/get?signature_id= para status e GET /signatures/pdf?signature_id= para o PDF.
3) Endpoint de webhook que valida HMAC-SHA256 de "<X-Assinatura-Timestamp>.<corpo bruto>" com ASSINATURA_API_SECRET contra o valor v1= do header X-Assinatura-Signature, usando hmac.compare_digest.
Nunca exponha a chave no navegador. Consulte https://assinatura.online/documentacao.