Procurando scripts prontos para copiar e colar? Veja as Receitas de Envelopes.
Envelopes estendem as Signing Sessions para fluxos com multiplos signatarios sobre um unico documento. Crie um envelope, adicione sessoes (uma por signatario) e acompanhe a conclusao via webhook ou polling. Ao final, gere um carimbo combinado com todas as assinaturas.
Formatos suportados: Envelopes aceitam documentos em diversos formatos além de PDF (DOCX, XLSX, imagens, etc.). Para documentos não-PDF, o campo
filename(oudocument_filename) é obrigatório. Documentos PDF utilizam PAdES; demais formatos utilizam CAdES (.p7s).
| Aspecto | Signing Sessions | Envelopes |
|---|---|---|
| Signatarios | 1 | N (2+) |
| Documento | Por sessao | Compartilhado |
| Modo | - | PARALLEL / SEQUENTIAL |
| URL de checkout | 1 URL | 1 URL por signatario |
| Carimbo | Individual | Combinado com todas assinaturas |
Cria o envelope com modo PARALLEL, 2 signatarios e documento em base64. Retorna envelopeId, status e documentHash. O documento pode ser PDF ou outro formato suportado.
import { SignDocsBrasilClient } from '@signdocs-brasil/api';
const envelope = await client.envelopes.create({
signingMode: 'PARALLEL',
totalSigners: 2,
document: { content: documentBase64, filename: 'contrato.pdf' },
returnUrl: 'https://app.example.com/done',
locale: 'pt-BR',
expiresInMinutes: 1440,
});
console.log(envelope.envelopeId, envelope.status);
from signdocs_brasil import SignDocsBrasilClient, ClientConfig
from signdocs_brasil.models import CreateEnvelopeRequest
envelope = client.envelopes.create(CreateEnvelopeRequest(
signing_mode='PARALLEL',
total_signers=2,
document_content=document_base64,
document_filename='contrato.pdf',
return_url='https://app.example.com/done',
locale='pt-BR',
expires_in_minutes=1440,
))
print(envelope.envelope_id, envelope.status)
envelope, err := client.Envelopes.Create(ctx, &signdocs.CreateEnvelopeRequest{
SigningMode: signdocs.SigningModeParallel,
TotalSigners: 2,
DocumentContent: documentBase64,
DocumentFilename: "contrato.pdf",
ReturnURL: "https://app.example.com/done",
Locale: "pt-BR",
ExpiresInMinutes: 1440,
})
if err != nil { log.Fatal(err) }
fmt.Println(envelope.EnvelopeID, envelope.Status)
CreateEnvelopeRequest request = new CreateEnvelopeRequest();
request.signingMode = "PARALLEL";
request.totalSigners = 2;
request.document = new CreateEnvelopeRequest.Document(documentBase64, "contrato.pdf");
request.returnUrl = "https://app.example.com/done";
request.locale = "pt-BR";
request.expiresInMinutes = 1440;
Envelope envelope = client.envelopes().create(request);
System.out.println(envelope.envelopeId + " " + envelope.status);
use SignDocsBrasil\Api\Models\CreateEnvelopeRequest;
$envelope = $client->envelopes->create(new CreateEnvelopeRequest(
signingMode: 'PARALLEL',
totalSigners: 2,
documentContent: $documentBase64,
documentFilename: 'contrato.pdf',
returnUrl: 'https://app.example.com/done',
locale: 'pt-BR',
expiresInMinutes: 1440,
));
echo $envelope->envelopeId . ' ' . $envelope->status;
using SignDocsBrasil.Api;
using SignDocsBrasil.Api.Models;
var envelope = await client.Envelopes.CreateAsync(new CreateEnvelopeRequest
{
SigningMode = "PARALLEL",
TotalSigners = 2,
Document = new InlineDocument { Content = documentBase64, Filename = "contrato.pdf" },
ReturnUrl = "https://app.example.com/done",
Locale = "pt-BR",
ExpiresInMinutes = 1440,
});
Console.WriteLine($"Envelope ID: {envelope.EnvelopeId} Status: {envelope.Status}");
Adicione uma sessao por signatario. Cada chamada retorna sessionId, url e clientSecret para aquele signatario.
const session1 = await client.envelopes.addSession(envelope.envelopeId, {
signer: { name: 'Joao Silva', email: 'joao@example.com', userExternalId: 'user-001' },
policy: { profile: 'CLICK_ONLY' },
purpose: 'DOCUMENT_SIGNATURE',
signerIndex: 1,
});
const session2 = await client.envelopes.addSession(envelope.envelopeId, {
signer: { name: 'Maria Souza', email: 'maria@example.com', userExternalId: 'user-002' },
policy: { profile: 'CLICK_ONLY' },
purpose: 'DOCUMENT_SIGNATURE',
signerIndex: 2,
});
console.log(session1.url, session2.url);
from signdocs_brasil.models import AddEnvelopeSessionRequest
session1 = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
signer_name='Joao Silva',
signer_email='joao@example.com',
signer_user_external_id='user-001',
policy_profile='CLICK_ONLY',
purpose='DOCUMENT_SIGNATURE',
signer_index=1,
))
session2 = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
signer_name='Maria Souza',
signer_email='maria@example.com',
signer_user_external_id='user-002',
policy_profile='CLICK_ONLY',
purpose='DOCUMENT_SIGNATURE',
signer_index=2,
))
print(session1.url, session2.url)
session1, err := client.Envelopes.AddSession(ctx, envelope.EnvelopeID, &signdocs.AddEnvelopeSessionRequest{
SignerName: "Joao Silva",
SignerEmail: "joao@example.com",
SignerUserExternalID: "user-001",
PolicyProfile: signdocs.PolicyProfileClickOnly,
Purpose: signdocs.PurposeDocumentSignature,
SignerIndex: 1,
})
if err != nil { log.Fatal(err) }
session2, err := client.Envelopes.AddSession(ctx, envelope.EnvelopeID, &signdocs.AddEnvelopeSessionRequest{
SignerName: "Maria Souza",
SignerEmail: "maria@example.com",
SignerUserExternalID: "user-002",
PolicyProfile: signdocs.PolicyProfileClickOnly,
Purpose: signdocs.PurposeDocumentSignature,
SignerIndex: 2,
})
if err != nil { log.Fatal(err) }
fmt.Println(session1.URL, session2.URL)
AddEnvelopeSessionRequest req1 = new AddEnvelopeSessionRequest();
req1.signer = new AddEnvelopeSessionRequest.Signer("Joao Silva", "joao@example.com", "user-001");
req1.policy = new Policy("CLICK_ONLY");
req1.purpose = "DOCUMENT_SIGNATURE";
req1.signerIndex = 1;
EnvelopeSession session1 = client.envelopes().addSession(envelope.envelopeId, req1);
AddEnvelopeSessionRequest req2 = new AddEnvelopeSessionRequest();
req2.signer = new AddEnvelopeSessionRequest.Signer("Maria Souza", "maria@example.com", "user-002");
req2.policy = new Policy("CLICK_ONLY");
req2.purpose = "DOCUMENT_SIGNATURE";
req2.signerIndex = 2;
EnvelopeSession session2 = client.envelopes().addSession(envelope.envelopeId, req2);
System.out.println(session1.url + " " + session2.url);
use SignDocsBrasil\Api\Models\AddEnvelopeSessionRequest;
$session1 = $client->envelopes->addSession($envelope->envelopeId, new AddEnvelopeSessionRequest(
signerName: 'Joao Silva',
signerEmail: 'joao@example.com',
signerUserExternalId: 'user-001',
policyProfile: 'CLICK_ONLY',
purpose: 'DOCUMENT_SIGNATURE',
signerIndex: 1,
));
$session2 = $client->envelopes->addSession($envelope->envelopeId, new AddEnvelopeSessionRequest(
signerName: 'Maria Souza',
signerEmail: 'maria@example.com',
signerUserExternalId: 'user-002',
policyProfile: 'CLICK_ONLY',
purpose: 'DOCUMENT_SIGNATURE',
signerIndex: 2,
));
echo $session1->url . ' ' . $session2->url;
var session1 = await client.Envelopes.AddSessionAsync(envelope.EnvelopeId, new AddEnvelopeSessionRequest
{
Policy = new Policy { Profile = "CLICK_ONLY" },
Signer = new Signer { Name = "Joao Silva", Email = "joao@example.com", UserExternalId = "user-001" },
Purpose = "DOCUMENT_SIGNATURE",
SignerIndex = 1,
Locale = "pt-BR",
});
var session2 = await client.Envelopes.AddSessionAsync(envelope.EnvelopeId, new AddEnvelopeSessionRequest
{
Policy = new Policy { Profile = "CLICK_ONLY" },
Signer = new Signer { Name = "Maria Souza", Email = "maria@example.com", UserExternalId = "user-002" },
Purpose = "DOCUMENT_SIGNATURE",
SignerIndex = 2,
Locale = "pt-BR",
});
Console.WriteLine($"Session 1 Client Secret: {session1.ClientSecret}");
Console.WriteLine($"Session 2 Client Secret: {session2.ClientSecret}");
Cada signatario recebe sua propria URL de checkout. Use redirecionamento ou o JS SDK embutido.
<!-- Signatario 1 -->
<a href="{{ session1.url }}">Joao — Assinar documento</a>
<!-- Signatario 2 -->
<a href="{{ session2.url }}">Maria — Assinar documento</a>
<!-- Checkout embutido (exemplo para signatario 1) -->
<div id="signdocs-checkout"></div>
<script src="https://cdn.signdocs.com.br/v1/signdocs-brasil.js"></script>
<script>
const sd = SignDocsBrasil.init({ locale: 'pt-BR' });
sd.checkout({
clientSecret: '{{ session1.clientSecret }}',
onComplete: function (event) { window.location.href = '/done'; },
onError: function (event) { console.error(event.code); },
onClose: function () { console.log('Cancelado'); },
});
</script>
Receba SIGNING_SESSION.COMPLETED para cada signatario individual, e ENVELOPE.COMPLETED quando todos terminarem.
{
"event": "SIGNING_SESSION.COMPLETED",
"payload": {
"sessionId": "ss_abc123", "transactionId": "tx_def456",
"envelopeId": "env_xyz789",
"signerIndex": 1, "signerName": "Joao Silva",
"status": "COMPLETED", "evidenceId": "ev_ghi789",
"completedAt": "2026-03-27T10:15:00Z"
}
}
{
"event": "ENVELOPE.COMPLETED",
"payload": {
"envelopeId": "env_xyz789",
"status": "COMPLETED",
"totalSigners": 2, "completedSessions": 2,
"completedAt": "2026-03-27T10:20:00Z"
}
}
Consulte GET /v1/envelopes/{id} para verificar o status e as sessoes.
const detail = await client.envelopes.get(envelope.envelopeId);
console.log(detail.status, detail.completedSessions + '/' + detail.totalSigners);
for (const s of detail.sessions) {
console.log(s.signerName, s.status, s.evidenceId);
}
detail = client.envelopes.get(envelope.envelope_id)
print(detail.status, f"{detail.completed_sessions}/{detail.total_signers}")
for s in detail.sessions:
print(s.signer_name, s.status, s.evidence_id)
detail, err := client.Envelopes.Get(ctx, envelope.EnvelopeID)
if err != nil { log.Fatal(err) }
fmt.Printf("%s %d/%d\n", detail.Status, detail.CompletedSessions, detail.TotalSigners)
for _, s := range detail.Sessions {
fmt.Println(s.SignerName, s.Status, s.EvidenceID)
}
EnvelopeDetail detail = client.envelopes().get(envelope.envelopeId);
System.out.println(detail.status + " " + detail.completedSessions + "/" + detail.totalSigners);
for (EnvelopeSessionSummary s : detail.sessions) {
System.out.println(s.signerName + " " + s.status + " " + s.evidenceId);
}
$detail = $client->envelopes->get($envelope->envelopeId);
echo $detail->status . ' ' . $detail->completedSessions . '/' . $detail->totalSigners . "\n";
foreach ($detail->sessions as $s) {
echo $s->signerName . ' ' . $s->status . ' ' . $s->evidenceId . "\n";
}
var detail = await client.Envelopes.GetAsync(envelope.EnvelopeId);
Console.WriteLine($"Status: {detail.Status} {detail.CompletedSessions}/{detail.TotalSigners}");
foreach (var s in detail.Sessions)
Console.WriteLine($" {s.SignerName}: {s.Status} (evidence: {s.EvidenceId})");
Apos todas as sessoes concluidas, gere o documento com carimbo combinado contendo todas as assinaturas.
const stamp = await client.envelopes.combinedStamp(envelope.envelopeId);
console.log(stamp.downloadUrl, stamp.signerCount);
stamp = client.envelopes.combined_stamp(envelope.envelope_id)
print(stamp.download_url, stamp.signer_count)
stamp, err := client.Envelopes.CombinedStamp(ctx, envelope.EnvelopeID)
if err != nil { log.Fatal(err) }
fmt.Println(stamp.DownloadURL, stamp.SignerCount)
CombinedStampResponse stamp = client.envelopes().combinedStamp(envelope.envelopeId);
System.out.println(stamp.downloadUrl + " " + stamp.signerCount);
$stamp = $client->envelopes->combinedStamp($envelope->envelopeId);
echo $stamp->downloadUrl . ' ' . $stamp->signerCount;
var stamp = await client.Envelopes.CombinedStampAsync(envelope.EnvelopeId);
Console.WriteLine($"Download URL: {stamp.DownloadUrl}");
Console.WriteLine($"Signer Count: {stamp.SignerCount}");
Quando signingMode e SEQUENTIAL, as sessoes sao processadas na ordem definida por signerIndex. Cada signatario so pode assinar apos o anterior concluir. A URL de checkout do proximo signatario so se torna ativa apos a conclusao da sessao anterior.
envelope = client.envelopes.create(CreateEnvelopeRequest(
signing_mode='SEQUENTIAL',
total_signers=2,
document_content=document_base64,
document_filename='contrato.pdf',
))
# signerIndex=1 assina primeiro
session1 = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
signer_name='Joao Silva', signer_email='joao@example.com',
policy_profile='CLICK_ONLY', signer_index=1,
))
# signerIndex=2 so pode assinar apos session1 concluir
session2 = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
signer_name='Maria Souza', signer_email='maria@example.com',
policy_profile='CLICK_ONLY', signer_index=2,
))
envelopes.create ──> envelopeId + status + documentHash
|
v
envelopes.add_session (signatario 1) ──> sessionId + url
envelopes.add_session (signatario 2) ──> sessionId + url
|
v
Redirecionar cada signatario para sua URL
|
v
Signatarios completam seus fluxos
|
┌────┴────┐
v v
Webhook Polling (envelopes.get)
| |
└────┬────┘
v
ENVELOPE.COMPLETED
|
v
envelopes.combined_stamp ──> downloadUrl