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. 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.py
    sig = 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. 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.py
    envelope = 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. 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.py
    from 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. 4.Instale e configure

    Só a biblioteca requests. Guarde as credenciais em variáveis de ambiente do servidor.

    terminal
    pip install requests
    
    export ASSINATURA_API_KEY=sk_sua_chave
    export ASSINATURA_API_SECRET=seu_segredo_de_webhook
  5. 5.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.py
    import 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_url
  6. 6.Assinatura qualificada com Bird ID ou VIDaaS

    Troque o modo pelo provedor e informe o CPF do titular do certificado.

    qualificada.py
    requests.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. 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.py
    info = 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. 8.Valide o webhook (HMAC-SHA256) — Flask

    Leia o corpo bruto, confira a assinatura e só então processe o evento.

    webhook.py
    import 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. 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.py
    r = 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.

prompt.txt
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.