signingLast updated on
Last updated on
Signers, signature capture, witnesses, and attestations
The signing flow in OpenForm separates the concepts of who can sign (Signers) from who they sign for (Parties). This enables scenarios where one person signs for multiple parties, or an authorized representative signs on behalf of an organization.
Signing Flow Overview
// 1. Fill form with party data
const draft = form.fill({
fields: { /* ... */ },
parties: {
landlord: { id: 'landlord-0', legalName: 'ABC Property LLC' },
tenant: { id: 'tenant-0', fullName: 'Jane Smith' }
}
})
// 2. Register signers with their adopted signatures
const withSigners = draft
.addSigner('jane', {
person: { fullName: 'Jane Smith' },
adopted: {
signature: { image: 'data:image/png;base64,...', method: 'drawn' },
initials: { method: 'typed' }
}
})
.addSigner('bob', {
person: { fullName: 'Bob Manager' },
adopted: {
signature: { image: 'data:image/png;base64,...', method: 'drawn' }
}
})
// 3. Link signers to parties (who signs for whom)
const ready = withSigners
.addSignatory('tenant', 'tenant-0', { signerId: 'jane' })
.addSignatory('landlord', 'landlord-0', { signerId: 'bob', capacity: 'Managing Member' })
// 4. Prepare for signing (freezes data)
const signable = ready.prepareForSigning()
// 5. Capture signatures at template locations
const signed = signable
.captureSignature('tenant', 'tenant-0', 'jane', 'tenant-final-sig')
.captureSignature('landlord', 'landlord-0', 'bob', 'landlord-final-sig')
// 6. Add witnesses and attestations
const witnessed = signed
.addWitness({ id: 'witness-0', party: { fullName: 'Sam Witness' } })
.addAttestation({
witnessId: 'witness-0',
signature: { image: 'data:...', method: 'drawn', timestamp: new Date().toISOString() },
attestsTo: [
{ roleId: 'tenant', partyId: 'tenant-0', signerId: 'jane' }
]
})
// 7. Finalize
const executed = witnessed.finalize()Signer
A Signer represents a person who can sign documents, along with their adopted signature and initials.
interface Signer {
person: Person // Who is signing (always a Person)
adopted?: {
signature?: AdoptedSignature // Adopted signature image
initials?: AdoptedSignature // Adopted initials image
}
}AdoptedSignature
An AdoptedSignature is a reusable signature or initials image that a signer has approved.
interface AdoptedSignature {
image?: string // Base64-encoded image or data URI
method: 'drawn' | 'typed' | 'uploaded' | 'certificate'
}PartySignatory
A PartySignatory links a signer to a party, specifying who signs for whom.
interface PartySignatory {
signerId: string // Reference to a Signer
capacity?: string // Role or title (CEO, Managing Member, etc.)
}Example: One Signer, Multiple Parties
// Jane signs for herself as tenant AND as authorized representative for guarantor
const draft = form.fill({
parties: {
tenant: { id: 'tenant-0', fullName: 'Jane Smith' },
guarantor: { id: 'guarantor-0', legalName: 'Smith Family Trust' }
}
})
.addSigner('jane', { person: { fullName: 'Jane Smith' }, adopted: { /* ... */ } })
.addSignatory('tenant', 'tenant-0', { signerId: 'jane' })
.addSignatory('guarantor', 'guarantor-0', { signerId: 'jane', capacity: 'Trustee' })SignatureCapture
A SignatureCapture records when and where a signature was placed in the document.
interface SignatureCapture {
role: string // Party role ID (e.g., "landlord", "tenant")
partyId: string // The party ID
signerId: string // The signer ID
locationId: string // Template location identifier
type: 'signature' | 'initials'
timestamp: string // ISO 8601 date-time
image?: string // Override image (if different from adopted)
method?: 'drawn' | 'typed' | 'uploaded' | 'certificate'
}Capturing Signatures
const signable = draft.prepareForSigning()
// Capture using adopted signature
const signed = signable.captureSignature('tenant', 'tenant-0', 'jane', 'page-1-sig')
// Capture with override image (one-time signature)
const signed = signable.captureSignature('tenant', 'tenant-0', 'jane', 'page-1-sig', {
image: 'data:image/png;base64,...',
method: 'drawn'
})
// Capture initials
const initialed = signed.captureInitials('tenant', 'tenant-0', 'jane', 'page-1-init')WitnessParty
A WitnessParty represents a witness who can attest to signatures.
interface WitnessParty {
id: string // Unique identifier
party: Person // Witness identity (always a Person)
notary?: boolean // Whether this witness is a notary public
}Adding Witnesses
const signable = draft.prepareForSigning()
// Add a regular witness
const withWitness = signable.addWitness({
id: 'witness-0',
party: { fullName: 'Sam Witness' }
})
// Add a notary
const withNotary = withWitness.addWitness({
id: 'notary-0',
party: { fullName: 'Nancy Notary' },
notary: true
})Attestation
An Attestation records a witness's attestation to one or more party signatures.
interface Attestation {
witnessId?: string // Reference to declared witness
witness?: WitnessParty // Inline witness definition
signature: Signature // The witness's signature
attestsTo: AttestationTarget[] // Signatures being witnessed
}
interface AttestationTarget {
roleId: string // Role of the party being witnessed
partyId: string // Party ID
signerId: string // Signer ID
locationId?: string // Specific capture location (optional)
}Attestation Properties
AttestationTarget Properties
Adding Attestations
// Using a pre-declared witness
const attested = signable.addAttestation({
witnessId: 'witness-0',
signature: {
image: 'data:image/png;base64,...',
method: 'drawn',
timestamp: new Date().toISOString()
},
attestsTo: [
{ roleId: 'tenant', partyId: 'tenant-0', signerId: 'jane' },
{ roleId: 'landlord', partyId: 'landlord-0', signerId: 'bob' }
]
})
// Using inline witness definition
const attested = signable.addAttestation({
witness: { id: 'witness-1', party: { fullName: 'New Witness' } },
signature: { /* ... */ },
attestsTo: [{ roleId: 'tenant', partyId: 'tenant-0', signerId: 'jane' }]
})Signature Status
Check signature progress using status methods on SignableForm:
// Get status for a specific role
const status = signable.getSignatureStatus('tenant')
// { required: true, captured: 1, total: 2, complete: false, witnesses: { required: 1, captured: 0 } }
// Get overall status
const overall = signable.getOverallSignatureStatus()
// { complete: false, roles: { tenant: {...}, landlord: {...} } }Related
- party - Party role definitions
- form - Form lifecycle and methods
- Signature primitive - Signature data type