Um ponto único de assinatura tipado para cada documento.
A1/PKCS#12, PDF/PAdES, XML-DSig e provedores remotos, tudo nativo de Effect. Troque o assinador, mantenha o programa — navegador ou servidor, erros tipados, segredos Redacted.
- Clicksign
- Assinafy
- ZapSign
- DocuSeal
- Documenso
Ao vivo · no seu navegador
Assine um PDF real, aqui mesmo.
Sem backend, sem upload, sem SaaS. Solte um PDF, clique onde a assinatura vai, carregue seu A1 (e-CPF / e-CNPJ) e assine com WebCrypto. O documento e a chave privada nunca saem da página.
Envie seu PDF
Renderizado localmente com pdf.js.
Clique para posicionar
Solte o retângulo de assinatura PAdES em qualquer lugar de qualquer página.
Assine com seu A1
Seu .pfx e a senha assinam no navegador via WebCrypto.
100% no cliente · WebCrypto · PAdES (AdES-BES)
Autoassinatura
Posicione uma vez. Assine a pilha inteira.
Vários contratos reais são gerados no seu navegador com @react-pdf/renderer, renderizados no mesmo canvas de posicionamento pdf.js que o assinador usa, e então posicionados e assinados automaticamente numa fila — um documento por vez.
Provedores remotos
Um SDK para cada assinador.
Oito provedores de assinatura, um único formato de requisição. Escolha um provedor — a chamada create*SignatureRequest muda, o código da sua aplicação não.
- Adaptadores
- Cada provedor é um create*SignatureRequest sobre um SignatureHttpClient compartilhado — o código específico do provedor fica fora do seu app.
- Erros tipados
- Nada lança exceção. Toda falha é um SignatureKitError no canal do Effect, marcado com o provedor e um código literal.
- Segredos protegidos
- Tokens e chaves de API permanecem em Redacted até a chamada HTTP — nunca logados, nunca vazados.
- Formatos próprios por provedor
- Cada signer remoto expõe os documentos, destinatários, status e limites que seu provedor realmente suporta.
import * as Alchemy from "alchemy"
import { ClicksignSignatureRequest, providers as clicksignProviders } from "@signature-kit/clicksign"
import { signatureHttpClientLive } from "@signature-kit/http"
import { Effect, Layer, Redacted } from "effect"
export default class Contracts extends Alchemy.Stack<Contracts>()(
"Contracts",
{
providers: Layer.merge(
clicksignProviders({
accessToken: Redacted.make(process.env.CLICKSIGN_TOKEN ?? ""),
environment: "sandbox",
locale: "pt-BR",
autoClose: true,
}),
signatureHttpClientLive,
),
state: Alchemy.inMemoryState(),
},
Effect.gen(function* () {
return yield* ClicksignSignatureRequest("membership-agreement", {
title: "Membership agreement",
documents: [{ fileName: "agreement.pdf", mimeType: "application/pdf", contentBase64: pdfBase64 }],
recipients: [{ name: "Bruno Lima", email: "bruno@example.com", role: "signer" }],
})
}),
) {}import * as Alchemy from "alchemy"
import { AssinafySignatureRequest, providers as assinafyProviders } from "@signature-kit/assinafy"
import { signatureHttpClientLive } from "@signature-kit/http"
import { Effect, Layer, Redacted } from "effect"
export default class Contracts extends Alchemy.Stack<Contracts>()(
"Contracts",
{
providers: Layer.merge(
assinafyProviders({
accountId: process.env.ASSINAFY_ACCOUNT_ID ?? "",
apiKey: Redacted.make(process.env.ASSINAFY_API_KEY ?? ""),
environment: "sandbox",
}),
signatureHttpClientLive,
),
state: Alchemy.inMemoryState(),
},
Effect.gen(function* () {
return yield* AssinafySignatureRequest("contract", {
title: "Contract",
documents: [{ fileName: "contract.pdf", mimeType: "application/pdf", contentBase64: pdfBase64 }],
recipients: [{ name: "Carla Nunes", email: "carla@example.com" }],
})
}),
) {}import * as Alchemy from "alchemy"
import { ZapSignSignatureRequest, providers as zapSignProviders } from "@signature-kit/zapsign"
import { signatureHttpClientLive } from "@signature-kit/http"
import { Effect, Layer, Redacted } from "effect"
export default class Contracts extends Alchemy.Stack<Contracts>()(
"Contracts",
{
providers: Layer.merge(
zapSignProviders({
apiToken: Redacted.make(process.env.ZAPSIGN_API_TOKEN ?? ""),
environment: "sandbox",
locale: "pt-br",
}),
signatureHttpClientLive,
),
state: Alchemy.inMemoryState(),
},
Effect.gen(function* () {
return yield* ZapSignSignatureRequest("contract", {
title: "Contract",
documents: [{ fileName: "contract.pdf", mimeType: "application/pdf", contentBase64: pdfBase64 }],
recipients: [{ name: "Davi Rocha", email: "davi@example.com" }],
})
}),
) {}import * as Alchemy from "alchemy"
import { DocuSealSignatureRequest, providers as docuSealProviders } from "@signature-kit/docuseal"
import { signatureHttpClientLive } from "@signature-kit/http"
import { Effect, Layer, Redacted } from "effect"
export default class Contracts extends Alchemy.Stack<Contracts>()(
"Contracts",
{
providers: Layer.merge(
docuSealProviders({
apiKey: Redacted.make(process.env.DOCUSEAL_API_KEY ?? ""),
baseUrl: "https://api.docuseal.com",
submittersOrder: "preserved",
}),
signatureHttpClientLive,
),
state: Alchemy.inMemoryState(),
},
Effect.gen(function* () {
return yield* DocuSealSignatureRequest("service-agreement", {
title: "Service agreement",
documents: [{ fileName: "agreement.pdf", mimeType: "application/pdf", contentBase64: pdfBase64 }],
recipients: [{ name: "Ana Silva", email: "ana@example.com", role: "signer" }],
})
}),
) {}import * as Alchemy from "alchemy"
import { DocumensoSignatureRequest, providers as documensoProviders } from "@signature-kit/documenso"
import { signatureHttpClientLive } from "@signature-kit/http"
import { Effect, Layer, Redacted } from "effect"
export default class Contracts extends Alchemy.Stack<Contracts>()(
"Contracts",
{
providers: Layer.merge(
documensoProviders({
apiKey: Redacted.make(process.env.DOCUMENSO_API_KEY ?? ""),
baseUrl: "https://app.documenso.com/api/v2",
}),
signatureHttpClientLive,
),
state: Alchemy.inMemoryState(),
},
Effect.gen(function* () {
return yield* DocumensoSignatureRequest("service-agreement", {
title: "Service agreement",
documents: [{ fileName: "agreement.pdf", mimeType: "application/pdf", contentBase64: pdfBase64 }],
recipients: [{ name: "Ana Silva", email: "ana@example.com", role: "approver", routingOrder: 1 }],
})
}),
) {}Sete capacidades
Tudo o que você assina, uma só API.
A1 / PKCS#12 no navegador ou no servidor, PDF·PAdES e XML-DSig, oito provedores remotos, um canal de erros tipado e uma camada React para assinatura no navegador — a mesma ergonomia nativa de Effect em todos os backends.
Um só serviço, todos os formatos
import { signatures } from "@signature-kit/signatures"A1 no navegador ou no servidor
a1SignaturesLayer({ pfx, password: Redacted.make(password) })PDF, PAdES, ICP-Brasil
signPdf({ pdf, policy: "pades-icp-brasil" })XML-DSig, por referência
signXml({ xml, referenceId: "nfe-1" })Provedores remotos, um canal tipado
ClicksignSignatureRequest("contract", props)Um canal de erros tipado
Effect.catchTag("SignatureKitError", handle)Assine PDF no navegador
import { signPdfSignatureField } from "@signature-kit/pdf/workflow"Dois passos
Sua primeira assinatura, de ponta a ponta.
Instale o núcleo e o assinador A1, depois construa uma layer e execute um programa que inspeciona o certificado e assina.
bun add @signature-kit/signatures @signature-kit/a1npm install @signature-kit/signatures @signature-kit/a1pnpm add @signature-kit/signatures @signature-kit/a1yarn add @signature-kit/signatures @signature-kit/a1@signature-kit/signatures é o ponto de entrada tipado. Cada assinador e formato é instalado apenas quando você precisa dele: /a1/pdf/xml
import { a1SignaturesLayer } from "@signature-kit/a1/signer"
import { signatures } from "@signature-kit/signatures"
import { Effect, Redacted } from "effect"
const layer = a1SignaturesLayer({
pfx,
password: Redacted.make(process.env.A1_PASSWORD ?? ""),
})
const program = Effect.gen(function* () {
const identity = yield* signatures.inspect()
const artifact = yield* signatures.sign({
content,
algorithm: "rsa-sha256",
})
return { identity, artifact }
}).pipe(Effect.provide(layer))
const { identity, artifact } = await Effect.runPromise(program)runPromiseresolve para aidentityanalisada e oartifactassinado. A partir daqui, troque a layer A1 por um formato —signPdfousignXml— ou entregue o programa a um provedor remoto.
Quando você quiser
Implemente a camada de assinatura uma vez.
Código aberto, licença MIT, nativo de Effect. A1, PDF, XML e provedores remotos sob um único programa tipado — cada falha um valor no qual você pode fazer match.