← All @molecule/* packages · App templates
@molecule/api-esignCore interface · esign · API (Node) · v1.0.1 · Apache-2.0
E-signature core interface for molecule.dev
npm install @molecule/api-esign@molecule/api-esign is the esign core interface on the API (Node) side: the API your app calls, with no vendor inside.
Choose the implementation by bonding one of its 1 provider: @molecule/api-esign-hellosign.
import { setProvider, createSignatureRequest, processWebhook } from '@molecule/api-esign'
import { provider } from '@molecule/api-esign-hellosign'
// Wire the provider at startup
setProvider(provider)
// Create a request from an uploaded document; persist request.id on your record
const request = await createSignatureRequest({
title: 'Lease Agreement',
signers: [{ name: 'Alice Tenant', email: 'alice@example.com', role: 'Tenant' }],
document: pdfBuffer,
})
// In the HTTP handler bound to the provider's webhook URL:
const event = await processWebhook(req.headers, req.body)
if (event.type === 'signature_request_all_signed') {
await markContractSigned(event.signatureRequestId)
}Providers (1): @molecule/api-esign-hellosign
Works with: @molecule/api-bond, @molecule/api-i18n
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
E-signature core interface for molecule.dev.
Defines the {@link EsignProvider} interface for the signature-request
lifecycle: create a request (from a raw Buffer, a hosted { url }, or a
vendor { templateId, prefill } document), poll its status, cancel it,
download the signed PDF, and normalize inbound webhook events. Bond
packages (HelloSign / Dropbox Sign, DocuSign, OpenSign, Adobe Sign, etc.)
implement this interface; application code uses the convenience functions
(createSignatureRequest, getSignatureRequest, cancelSignatureRequest,
getSignedDocument, processWebhook) which delegate to the bonded
provider.
import { setProvider, createSignatureRequest, processWebhook } from '@molecule/api-esign'
import { provider } from '@molecule/api-esign-hellosign'
// Wire the provider at startup
setProvider(provider)
// Create a request from an uploaded document; persist request.id on your record
const request = await createSignatureRequest({
title: 'Lease Agreement',
signers: [{ name: 'Alice Tenant', email: 'alice@example.com', role: 'Tenant' }],
document: pdfBuffer,
})
// In the HTTP handler bound to the provider's webhook URL:
const event = await processWebhook(req.headers, req.body)
if (event.type === 'signature_request_all_signed') {
await markContractSigned(event.signatureRequestId)
}
core
npm install @molecule/api-esign @molecule/api-bond @molecule/api-i18n
CreateSignatureRequestInputInput to {@link EsignProvider.createSignatureRequest}.
interface CreateSignatureRequestInput {
/** Human-readable title for the request, shown to signers. */
title: string
/** Ordered list of signers. */
signers: Signer[]
/** The document to be signed. */
document: EsignDocument
/** Optional list of CC email addresses that receive a copy on completion. */
ccs?: string[]
/** Optional message included in the signing invitation. */
message?: string
}
EsignProviderAbstract e-signature provider interface. All vendor bonds (HelloSign / Dropbox Sign, DocuSign, OpenSign, Adobe Sign, etc.) must implement this interface so application code stays vendor-agnostic.
interface EsignProvider {
/**
* Creates a new signature request. The document may be supplied as a raw
* Buffer, a hosted URL, or a vendor template reference with prefill.
*
* @param input - Title, signers, document, and optional CC/message fields.
* @returns The newly-created signature request, normalized.
*/
createSignatureRequest(input: CreateSignatureRequestInput): Promise<SignatureRequest>
/**
* Retrieves the current status of an existing signature request.
*
* @param id - Provider-issued signature request id.
* @returns The current state of the signature request, normalized.
*/
getSignatureRequest(id: string): Promise<SignatureRequest>
/**
* Cancels a pending signature request. No-op for already-completed requests
* (providers either return success or 4xx; this method normalizes to void).
*
* @param id - Provider-issued signature request id.
*/
cancelSignatureRequest(id: string): Promise<void>
/**
* Downloads the signed document (typically PDF) as a Buffer. Available
* once the request status is `signed`.
*
* @param id - Provider-issued signature request id.
* @returns The signed document bytes.
*/
getSignedDocument(id: string): Promise<Buffer>
/**
* Verifies and parses an inbound webhook callback from the provider.
* Implementations MUST verify the request authenticity (e.g. via HMAC)
* and throw on signature mismatch.
*
* @param headers - The HTTP request headers as a plain object.
* @param body - The parsed JSON body of the webhook request.
* @returns A normalized event describing what happened.
*/
processWebhook(
headers: Record<string, string | string[] | undefined>,
body: unknown,
): Promise<EsignWebhookEvent>
}
EsignWebhookEventNormalized webhook event produced by {@link EsignProvider.processWebhook}.
interface EsignWebhookEvent {
/** Type of the underlying event. */
type: EsignWebhookEventType
/** Signature request id this event refers to. */
signatureRequestId: string
/** Email of the signer involved, when applicable (e.g. signed / declined). */
signerEmail?: string
/** The original provider payload, for diagnostic / audit purposes. */
raw: unknown
}
SignatureRequestNormalized signature request returned by all EsignProvider methods.
interface SignatureRequest {
/** Provider-issued signature request id. */
id: string
/** Aggregate status for the whole request. */
status: SignatureRequestStatus
/** Per-signer breakdown including individual status and timestamp. */
signers: SignerWithStatus[]
/** ISO-8601 timestamp at which the request reached `signed` status. */
signedAt?: string
}
SignerA signer participating in a signature request.
interface Signer {
/** Display name shown to the signer in invitations. */
name: string
/** Email address used to deliver the signing invitation. */
email: string
/** Optional role label (e.g. `'Tenant'`, `'Landlord'`). Some providers use this for template binding. */
role?: string
}
SignerWithStatusA signer plus their current status within a signature request.
interface SignerWithStatus extends Signer {
/** Current status for this signer. */
status: SignerStatus
/** ISO-8601 timestamp at which the signer signed, when applicable. */
signedAt?: string
}
EsignDocumentThe document body for a new signature request. Three forms are supported:
Buffer (uploaded via multipart upload by the provider).{ url, filename? }.{ templateId, prefill? },
where prefill populates merge fields defined on the template.type EsignDocument =
| Buffer
| { url: string; filename?: string }
| { templateId: string; prefill?: Record<string, string | number | boolean> }
EsignWebhookEventTypeWebhook event types normalized across providers.
type EsignWebhookEventType =
| 'signature_request_signed'
| 'signature_request_all_signed'
| 'signature_request_declined'
| 'signature_request_cancelled'
| 'signature_request_expired'
| 'unknown'
SignatureRequestStatusAggregate status for a signature request as a whole.
awaiting_signatures — at least one signer has not yet signedsigned — every signer has signeddeclined — at least one signer declinedcancelled — request was cancelled by the requesterexpired — request window elapsed before completiontype SignatureRequestStatus =
'awaiting_signatures' | 'signed' | 'declined' | 'cancelled' | 'expired'
SignerStatusPer-signer status within a signature request.
pending — invitation sent, awaiting actionsigned — signer has completed and signeddeclined — signer explicitly declinedexpired — signature window elapsed before actiontype SignerStatus = 'pending' | 'signed' | 'declined' | 'expired'
cancelSignatureRequest(id)Cancels a pending signature request.
function cancelSignatureRequest(id: string): Promise<void>
id — Provider-issued signature request id.createSignatureRequest(input)Creates a new signature request via the bonded provider.
function createSignatureRequest(input: CreateSignatureRequestInput): Promise<SignatureRequest>
input — Title, signers, document, and optional CC / message fields.Returns: The newly-created signature request, normalized.
getProvider()Retrieves the bonded e-signature provider, throwing if none is configured.
function getProvider(): EsignProvider
Returns: The bonded e-signature provider.
getSignatureRequest(id)Retrieves the current state of a signature request.
function getSignatureRequest(id: string): Promise<SignatureRequest>
id — Provider-issued signature request id.Returns: The current state of the signature request, normalized.
getSignedDocument(id)Downloads the signed document for a completed signature request.
function getSignedDocument(id: string): Promise<Buffer<ArrayBufferLike>>
id — Provider-issued signature request id.Returns: The signed document bytes.
hasProvider()Checks whether an e-signature provider is currently bonded.
function hasProvider(): boolean
Returns: true if an e-signature provider is bonded.
processWebhook(headers, body)Verifies and parses an inbound webhook callback from the provider.
function processWebhook(
headers: Record<string, string | string[] | undefined>,
body: unknown,
): Promise<EsignWebhookEvent>
headers — The HTTP request headers.body — The parsed JSON request body.Returns: A normalized webhook event.
setProvider(provider)Registers an e-signature provider as the active singleton. Called by bond packages during application startup.
function setProvider(provider: EsignProvider): void
provider — The e-signature provider implementation to bond.| Provider | Package |
|---|---|
| HelloSign | @molecule/api-esign-hellosign |
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-bond
@molecule/api-i18n
Signing is asynchronous, on the vendor's site. Never mark a document
signed when the request is created. Persist the provider-issued
SignatureRequest.id on your record and update status from
processWebhook events (or getSignatureRequest() polling).
processWebhook verifies authenticity and THROWS on a bad signature.
The webhook endpoint is public — let that rejection become a 4xx and never
touch the event body first. Treat type: 'unknown' as ignorable (2xx),
not an error.
getSignedDocument() is only available once status is 'signed' —
gate the download on status AND authorize it (only parties to the
document may fetch it).
Signer email addresses receive real vendor invitations — in development
use addresses you control.
Provider API keys (e.g. the HelloSign bond's HELLOSIGN_API_KEY) are
server-side secrets resolved through the secrets registry — never
hardcoded or client-visible.
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
createSignatureRequest, the app
persists the returned SignatureRequest.id on its record, and the document
shows as awaiting_signatures — NOT marked signed at creation.read_activity tool (filter type 'email'); the signing link is in its
payload. Never mock the flow or expect a real inbox.signature_request_all_signed
event to the webhook endpoint (or poll getSignatureRequest) and confirm the
document flips awaiting_signatures → signed and the signer flips
pending → signed. Observe the transition, never guess it.getSignedDocument
returns the document once status is signed, and the UI download is gated on
that status (unavailable/denied while the request is still awaiting signatures).processWebhook rejects a forged callback — a bad signature THROWS and
becomes a 4xx with no state change; a type: 'unknown' event is ignored (2xx).SignatureRequest.id by guessing it.