Como Integrar Assinatura Digital em PHP / Laravel
Se você desenvolve em PHP ou Laravel e precisa coletar assinaturas com validade jurídica direto da sua aplicação, este guia mostra o caminho completo: instalar o SDK oficial via Composer, autenticar via OAuth2, criar uma sessão de assinatura, adicionar signatários, enviar o documento, verificar webhooks com HMAC e, por fim, baixar o PDF assinado. Tudo com snippets idiomáticos de PHP e Laravel, prontos para colar no seu projeto.
A SignDocs Brasil expõe uma API REST agnóstica de linguagem e mantém SDKs oficiais para TypeScript/Node, Python, Go, Java, PHP e C#/.NET. Como o SDK PHP é um pacote Composer puro (PSR-4, sem dependência de framework), ele se encaixa igualmente bem em Laravel, Symfony, Slim, WordPress ou PHP procedural.
Antes de começar, vale entender o panorama geral em o que é a API de assinatura digital da SignDocs e, se você quiser comparar com outras stacks, veja os guias paralelos de integração em Node.js e integração em Java. Para um panorama agnóstico de linguagem, comece por o que é uma API de assinatura digital.
Pré-requisitos
Para acompanhar este tutorial você precisa de:
- PHP 8.1+ (o SDK aproveita tipos nomeados, enums e propriedades readonly).
- Composer instalado para gerenciar dependências.
- Uma conta SignDocs e um par de credenciais de API (
client_ideclient_secret). Veja como obter sua API key. - Acesso ao ambiente de homologação (sandbox) para testar sem custo.
- Opcionalmente, um framework como Laravel 10/11 — usaremos Laravel nos exemplos de rota e controller.
api-hml.signdocs.com.br (forma com hífen, não api.hml). As entidades de homologação têm TTL de 7 dias — transações e evidências de teste somem depois disso, o que é ótimo para manter o sandbox limpo.
Passo 1 — Instalar o SDK PHP via Composer
A instalação é uma única linha de Composer (o pacote exige PHP 8.1+ e usa Guzzle por baixo):
Em um projeto Laravel, mantenha as credenciais no arquivo .env e exponha-as via um arquivo de configuração. Isso evita hardcode de segredos e facilita alternar entre homologação e produção:
Passo 2 — Autenticar via OAuth2 (client-credentials)
A SignDocs usa OAuth2 no fluxo client-credentials: você troca client_id + client_secret por um bearer token JWT de curta duração (15 minutos), assinado com ECDSA (ES256). O SDK PHP cuida dessa troca e renova o token automaticamente antes de expirar, então normalmente você só instancia o cliente uma vez. Para entender o mecanismo a fundo, veja o guia de autenticação OAuth2 da API.
Em Laravel, o padrão idiomático é registrar o cliente como singleton em um Service Provider, para que todo o app reutilize a mesma instância (e o mesmo token em cache):
Em PHP puro (sem framework), a inicialização é igualmente direta. O SDK obtém o token na primeira chamada e o reutiliza enquanto válido:
client_secret no frontend, em repositórios públicos ou em logs. Mantenha-o em variáveis de ambiente no servidor. Para clientes enterprise regulados (BACEN/Open Finance), há ainda suporte a mTLS (mutual TLS), que adiciona autenticação mútua por certificado de cliente sobre o OAuth2.
Passo 3 — Criar a sessão de assinatura
A SignDocs oferece duas superfícies de API que você pode usar a partir do PHP:
| Superfície | Quando usar | Característica |
|---|---|---|
| Assinatura Expressa (Signing Sessions) | Fluxo de signatário único e rápido — um único POST /v1/signing-sessions retorna um checkout hospedado ou widget embutido |
Menos chamadas; ideal para "assinar agora" |
| Transaction API (envelopes) | Múltiplos signatários no mesmo documento, ordem de assinatura, ciclo de vida completo | Controle granular sobre o fluxo transacional |
Para o quickstart, usaremos a Assinatura Expressa, que entrega valor com uma única chamada. O exemplo abaixo cria uma sessão para um contrato e define o perfil de política DIGITAL_CERTIFICATE (certificado ICP-Brasil A1 — para titulares de token A3, o aplicativo SignDocs oferece o assinador desktop):
policy.profile é DIGITAL_CERTIFICATE. Não use DIGITAL_SIGN_A1 ali — esse valor é um tipo de etapa (step.type) que aparece na resposta, e a API rejeita com 400 se for enviado como profile. Para escolher entre clickwrap, OTP, biometria e certificado, consulte a seção de métodos em o que é uma API de assinatura digital.
Resposta típica da criação
Passo 4 — Múltiplos signatários e envelopes (Transaction API)
Quando o mesmo documento precisa de mais de um signatário, ou de uma ordem de assinatura definida, use envelopes. O SDK PHP expõe métodos para criar o envelope e adicionar uma sessão por signatário — cada uma com sua própria URL de assinatura. Saiba mais sobre o desenho do fluxo em fluxo transacional da API de assinatura.
Para detalhes sobre a sequência de assinatura quando há vários signatários, veja ordem de assinatura com múltiplos signatários.
Passo 5 — Verificar webhooks com HMAC em Laravel
Em vez de ficar consultando o status da transação em loop (polling), o ideal é receber webhooks: a API faz um HTTP POST no seu endpoint sempre que um evento ocorre (SIGNING_SESSION.COMPLETED, TRANSACTION.COMPLETED, STEP.FAILED, etc.). Cada webhook traz uma assinatura HMAC-SHA256 no header, e você deve verificá-la antes de processar. O guia completo está em webhooks e eventos da API de assinatura.
Registrar a rota
Em Laravel, exclua a rota de webhook da verificação CSRF (ela não vem de um formulário do seu app) e aponte para um controller dedicado:
O controller que verifica a assinatura
O ponto crítico é ler o corpo bruto da requisição com $request->getContent() (não o array já parseado), recalcular o HMAC e comparar com hash_equals(), que é uma comparação timing-safe — imune a timing attacks:
Prefere não implementar o HMAC na mão? O SDK traz o helper pronto: SignDocsBrasil\Api\WebhookVerifier::verify($payload, $signature, $timestamp, $secret) faz a mesma validação (incluindo a tolerância de replay) em uma chamada.
id do evento para idempotência, despache o trabalho pesado para uma fila (queue) e responda 200 em segundos. Se você processar tudo de forma síncrona e estourar o timeout, a API tratará como falha e reenviará o evento — gerando duplicatas.
O Job que reage ao evento
Passo 6 — Baixar o PDF assinado
Quando a transação é concluída, você recebe o evento TRANSACTION.COMPLETED. Nesse momento, use o SDK para obter as URLs temporárias de download do PDF final (já com as assinaturas embutidas) e do pacote de evidências, e salve os arquivos no Storage do Laravel ou no S3:
O pacote de evidências .p7m contém o container PKCS#7/CMS com a cadeia de certificação, o hash SHA-256 do documento, os carimbos de hora do servidor e a trilha de auditoria que sustentam a validade jurídica. Para entender o que ele inclui, veja o pacote de evidências P7M como prova jurídica. Qualquer pessoa pode conferir a autenticidade do documento no verificador público.
Boas práticas para PHP/Laravel em produção
- Segredos no ambiente, nunca no código: use
.env+config(); em produção, prefira um cofre de segredos (AWS Secrets Manager, Vault) em vez de arquivos. - Filas para webhooks: conecte o queue do Laravel a Redis, SQS ou banco. Processe eventos em workers, mantendo a rota de webhook leve.
- Idempotência sempre: persista o
idde cada evento em uma tabela com índice único. A entrega de webhooks é at-least-once, então duplicatas vão acontecer. - Timeout e retries no cliente HTTP: o SDK já trata renovação de token; configure timeouts sensatos para chamadas de criação de sessão.
- Homologação antes de produção: rode o fluxo completo em
api-hml.signdocs.com.bre só então troque a base URL e as credenciais. - Observabilidade: logue o
iddo evento e otransactionIdem cada etapa para facilitar a reconciliação.
Padrões de assinatura suportados
As assinaturas geradas seguem PAdES (para PDF), CAdES (para qualquer tipo de arquivo) e usam containers PKCS#7/CMS, no nível baseline (PAdES-B / CAdES-B): assinatura + cadeia de certificados ICP-Brasil + carimbo de hora do servidor + trilha de auditoria com o hash SHA-256 do documento. Os níveis com carimbo de tempo de uma ACT e LTV não são gerados atualmente pela API. Para o aprofundamento técnico desses padrões, veja PKCS#7, CMS, PAdES e CAdES no glossário.
Resumo do fluxo end-to-end
- Composer:
composer require signdocs-brasil/signdocs-brasil-phpe configure as credenciais no.env. - OAuth2: instancie o cliente; o SDK obtém e renova o bearer token automaticamente.
- Criar sessão:
signingSessions->create()(expressa) ouenvelopes->create()(multi-signatário). - Adicionar signatários:
envelopes->addSession()comsignerIndex— cada sessão tem sua URL de assinatura. - Webhook: rota POST em Laravel + verificação HMAC (
WebhookVerifier::verify()ouhash_equals()) + idempotência peloiddo evento. - Download: ao receber
TRANSACTION.COMPLETED, baixe o PDF assinado e o.p7mde evidências pelas URLs temporárias.
Se quiser começar ainda mais rápido, há um caminho enxuto em primeiros passos com a API em 5 minutos. E se a sua stack for outra, os guias de Node.js e Java seguem exatamente a mesma lógica.
Perguntas Frequentes
Existe um SDK oficial de assinatura digital para PHP?
Sim. A SignDocs mantém um SDK PHP oficial distribuído via Composer, ao lado dos SDKs para TypeScript/Node, Python, Go, Java e C#/.NET. O SDK PHP encapsula a autenticação OAuth2, a renovação automática de token, as chamadas REST tipadas e os helpers de verificação de webhook, de modo que você não precisa montar requisições cURL manualmente. Como a API REST é agnóstica de linguagem, você também pode usar Guzzle ou cURL puro caso prefira não adicionar uma dependência ao seu projeto.
O SDK PHP funciona com Laravel e Symfony?
Sim. O SDK é um pacote Composer PSR-4 sem acoplamento a nenhum framework, então funciona em Laravel, Symfony, Slim, WordPress ou PHP puro. Em Laravel, o padrão recomendado é registrar o cliente como singleton em um Service Provider, ler as credenciais do arquivo .env via config(), e tratar os webhooks com uma rota POST mais um controller dedicado que verifica a assinatura HMAC antes de processar o evento.
Como autenticar na API de assinatura a partir de PHP?
A autenticação usa OAuth2 no fluxo client-credentials: você envia seu client_id e client_secret ao endpoint de token e recebe um bearer token JWT (assinado com ECDSA ES256) que expira em 15 minutos. O SDK PHP faz essa troca automaticamente e renova o token antes de expirar, então você só precisa configurar as credenciais uma vez. Para integrações enterprise reguladas (BACEN/Open Finance) há ainda suporte a mTLS. Nunca exponha o client_secret no frontend; mantenha-o em variáveis de ambiente no servidor.
Como verificar a assinatura HMAC de um webhook em Laravel?
Os webhooks da SignDocs chegam como HTTP POST com um header contendo uma assinatura HMAC-SHA256 calculada sobre o corpo bruto da requisição. Em Laravel, leia o corpo bruto com $request->getContent(), recalcule o HMAC com hash_hmac('sha256', $payload, $secret) e compare com a assinatura recebida usando hash_equals(), que é uma comparação timing-safe. Só processe o evento se as assinaturas coincidirem; caso contrário, retorne 401. Implemente também idempotência usando o id do evento para tolerar reentregas — ou use o helper WebhookVerifier::verify() do SDK, que já valida assinatura e timestamp.
A API PHP suporta assinatura com certificado ICP-Brasil (A1 e A3)?
Sim. A política de assinatura aceita o perfil DIGITAL_CERTIFICATE, que aplica o certificado ICP-Brasil A1 (o formato usado em integrações via API; titulares de token A3 usam o assinador desktop do aplicativo SignDocs), além de perfis com clickwrap, OTP por SMS/e-mail e biometria facial. Você define o perfil ao criar a sessão de assinatura via SDK PHP. As assinaturas resultantes seguem os padrões PAdES e CAdES no nível baseline (assinatura + cadeia de certificados ICP-Brasil + carimbo de hora do servidor + trilha de auditoria), gerando um pacote de evidências .p7m que vincula o hash SHA-256 do documento, com validade jurídica conforme a MP 2.200-2/2001.
Como testar a integração PHP antes de ir para produção?
Use o ambiente de homologação apontando a base URL do SDK para api-hml.signdocs.com.br (forma com hífen, não api.hml). Você cria credenciais de homologação separadas e roda todo o fluxo (token, criação de sessão, assinatura e webhook) sem custo nem efeitos em produção. Lembre-se de que as entidades de homologação têm TTL de 7 dias, então transações e evidências de teste são removidas após esse período. Quando o fluxo estiver validado, basta trocar a base URL e as credenciais para produção.
Como baixar o PDF final assinado a partir do PHP?
Quando a transação é concluída, você recebe o evento TRANSACTION.COMPLETED via webhook. A partir daí, chame o método de download de documento do SDK PHP passando o transactionId; a resposta traz uma URL temporária (signedUrl) do PDF assinado, que você baixa e salva no Storage do Laravel ou no S3. Para uso jurídico, baixe também o pacote de evidências .p7m, que contém o container PKCS#7/CMS com a cadeia de certificação, o hash SHA-256 do documento, os carimbos de hora do servidor e a trilha de auditoria.
Integre assinatura digital ao seu app PHP/Laravel hoje
SDK PHP oficial via Composer, OAuth2 automático, webhooks com HMAC-SHA256 e certificado ICP-Brasil. LGPD-first, com validade jurídica pela MP 2.200-2/2001. O acesso à API é um plano sob medida, com sandbox de homologação gratuito — comece por ele e suba para produção trocando uma única variável.
Fale com o time comercial Conheça a plataforma grátis