← All @molecule/* packages · App templates
@molecule/api-esign-hellosignProvider bond · esign · API (Node) · v1.0.1 · Apache-2.0
HelloSign (Dropbox Sign) e-signature provider for molecule.dev.
npm install @molecule/api-esign-hellosignnpm · Source on GitHub · Implements @molecule/api-esign
@molecule/api-esign-hellosign is a provider bond on the API (Node) side: it implements the esign core interface (@molecule/api-esign) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider } from '@molecule/api-esign'
import { provider } from '@molecule/api-esign-hellosign'
setProvider(provider)Works with: @molecule/api-bond, @molecule/api-esign, @molecule/api-secrets
Secrets: HELLOSIGN_API_KEY
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.
HelloSign (Dropbox Sign) e-signature provider for molecule.dev.
Implements the @molecule/api-esign EsignProvider contract against the
HelloSign v3 REST API: create signature requests (raw Buffer upload,
hosted { url }, or { templateId, prefill } template), poll status,
cancel, download the signed PDF, and verify + normalize webhook events
(HMAC-SHA256, keyed by the API key).
import { setProvider } from '@molecule/api-esign'
import { provider } from '@molecule/api-esign-hellosign'
setProvider(provider)
provider
npm install @molecule/api-esign-hellosign @molecule/api-bond @molecule/api-esign @molecule/api-secrets
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 HelloSign signature request.
function cancelSignatureRequest(id: string): Promise<void>
id — HelloSign signature_request_id.createSignatureRequest(input)Creates a new signature request via HelloSign. Routes between three endpoints depending on the document form:
signature_request/send (multipart)signature_request/send (JSON file_url)signature_request/send_with_templatefunction createSignatureRequest(input: CreateSignatureRequestInput): Promise<SignatureRequest>
input — The signature request input.Returns: The newly-created normalized signature request.
getSignatureRequest(id)Retrieves the current state of a HelloSign signature request.
function getSignatureRequest(id: string): Promise<SignatureRequest>
id — HelloSign signature_request_id.Returns: The normalized signature request.
getSignedDocument(id)Downloads the signed PDF for a HelloSign signature request.
function getSignedDocument(id: string): Promise<Buffer<ArrayBufferLike>>
id — HelloSign signature_request_id.Returns: The signed document bytes.
processWebhook(_headers, body)Verifies and parses an inbound HelloSign webhook callback. The HelloSign
webhook payload arrives form-encoded with a single json field whose
value is the JSON body. The body contains event.event_hash, computed
as hmac_sha256(api_key, event_time + event_type).
Implementations that pre-parse the form into { json: '...' } should
pass the resulting object directly. The provider also tolerates a body
already shaped like the inner event payload.
function processWebhook(
_headers: Record<string, string | string[] | undefined>,
body: unknown,
): Promise<EsignWebhookEvent>
_headers — The HTTP request headers (unused; HelloSign places the hash inside the body).body — The parsed request body.Returns: The normalized webhook event.
esignHellosignSecretDefinitionsSecret definitions required by the Dropbox Sign (HelloSign) e-signature bond.
const esignHellosignSecretDefinitions: SecretDefinition[]
providerThe HelloSign provider implementing the EsignProvider interface.
const provider: EsignProvider
Implements @molecule/api-esign interface.
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-esign'
import { provider } from '@molecule/api-esign-hellosign'
export function setupEsignHellosign(): void {
setProvider(provider)
}
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-esign ^1.0.1@molecule/api-secrets ^1.0.1HELLOSIGN_API_KEY (required) — Dropbox Sign (HelloSign) API key
@molecule/api-bond
@molecule/api-esign
@molecule/api-secrets
Webhook provisioning is manual. Configure the callback URL in the
Dropbox Sign dashboard (Settings → API → Account callback) — this bond
does not register it. Events arrive application/x-www-form-urlencoded
with a single json field: mount the route with a urlencoded (or
multipart) body parser — NOT a raw-body or JSON parser — and pass the
parsed { json: '...' } object to processWebhook().
Respond with the literal text Hello API Event Received (HTTP 200)
after processWebhook() succeeds — Dropbox Sign treats any other
response body as a failed delivery, retries, and eventually disables
the callback.
Live sends only — there is no test-mode switch. The bond never sends
test_mode=1, so every request is a real (billable) signature request;
free/trial accounts get a 4xx on send, and signers receive real emails —
use addresses you control in development.
Requires HELLOSIGN_API_KEY (read lazily at call time; never echoed
into error messages). A missing key throws at first use, not at import.
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.