Bulk Signing
Bulk signing allows integration partners to sign hundreds of documents at once. This is ideal when one signer (e.g., a CEO) needs to sign many documents of the same type.
Overview
The bulk signing flow has three steps:
- Save a signature — Capture and store the signer’s signature image
- Create documents — Create documents from a template with signers and fields
- Bulk sign — Sign all documents at once using the saved signature
Step 1: Save a Signature
Before bulk signing, you need a saved signature for the signer. You can capture signatures using the <KoralaSignaturePad> React component or any other method that produces a base64 PNG data URL.
Format requirement: Signature images must be base64 PNG data URLs (
data:image/png;base64,...). JPEG, SVG, and regular HTTP URLs are not supported. The maximum size is 500KB.
Using the React Signature Pad
import { KoralaSignaturePad } from '@korala/react';
function SignatureCapture() {
return (
<KoralaSignaturePad
onSignatureCreated={({ imageDataUrl }) => {
// Send to your backend to save via Korala API
fetch('/api/save-signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
signatureImageUrl: imageDataUrl,
email: '[email protected]',
name: 'Jane Smith',
}),
});
}}
/>
);
}Saving via the API
TypeScript
import { KoralaClient } from '@korala/api-client';
const korala = new KoralaClient({
apiKeyId: process.env.KORALA_API_KEY_ID!,
apiSecret: process.env.KORALA_API_SECRET!,
});
const signature = await korala.signatures.create({
email: '[email protected]',
name: 'Jane Smith',
signatureImageUrl: 'data:image/png;base64,...',
isDefault: true,
});
console.log(`Saved signature: ${signature.id}`);Managing Saved Signatures
// List signatures for a specific email
const signatures = await korala.signatures.list({ email: '[email protected]' });
// Get a specific signature
const signature = await korala.signatures.get(signatureId);
// Delete a signature
await korala.signatures.delete(signatureId);Step 2: Create Documents
Create your documents using templates. See the Documents guide for details on creating and sending documents.
// Create 200 NDAs from a template
const documentIds: string[] = [];
for (const recipient of recipients) {
const doc = await korala.templates.createDocument(templateId, {
signerRoles: {
'Company Representative': {
email: '[email protected]',
name: 'Jane Smith',
},
'Recipient': {
email: recipient.email,
name: recipient.name,
},
},
});
documentIds.push(doc.id);
// Send for signing
await korala.documents.send(doc.id);
}Step 3: Bulk Sign
Sign all documents at once using the saved signature:
TypeScript
const result = await korala.documents.bulkSign({
documentIds,
signerEmail: '[email protected]',
autoFillDateValue: '2026-02-18', // optional, defaults to today
});
console.log(`Signed: ${result.signed}`);
console.log(`Failed: ${result.failed}`);
// Check individual results
for (const doc of result.results) {
if (doc.success) {
console.log(`${doc.documentId}: signed (allSigned: ${doc.allSigned})`);
} else {
console.log(`${doc.documentId}: failed - ${doc.error}`);
}
}How Auto-Fill Works
When bulk signing, the system automatically fills fields based on type:
| Field Type | Auto-Fill Behavior |
|---|---|
| Signature | Uses the signer’s default saved signature |
| Initials | Uses the signer’s default saved signature |
| Date | Uses autoFillDateValue (defaults to today) |
| Text | Must be pre-filled (e.g., via template variables) |
| Checkbox | Must be pre-filled (e.g., via template variables) |
Important: If no saved signature exists for the signer, any required Signature or Initials fields will fail with an error. You must save a signature via
POST /signatures(Step 1) before calling bulk sign.
Per-Document Overrides
You can override specific field values for individual documents:
const result = await korala.documents.bulkSign({
documentIds: ['doc-1', 'doc-2', 'doc-3'],
signerEmail: '[email protected]',
documents: [
{
documentId: 'doc-3',
fields: [
// Override a text field value
{ fieldId: 'field-xyz', value: 'Special terms apply' },
// Override a signature field with a different signature image
{
fieldId: 'field-sig',
value: 'Signed',
signatureImageUrl: 'data:image/png;base64,...',
},
],
},
],
});Per-document overrides take precedence over auto-fill.
Note: All signature images must be base64 PNG data URLs (
data:image/png;base64,...). Other formats (JPEG, SVG, regular URLs) are not supported and will be rejected by the API.
Handling Partial Success
Bulk sign always returns HTTP 200 with per-document results. Some documents may fail while others succeed:
const result = await korala.documents.bulkSign({
documentIds,
signerEmail: '[email protected]',
});
if (result.failed > 0) {
const failures = result.results.filter((r) => !r.success);
console.error('Failed documents:', failures);
// Retry failed documents
const retryIds = failures
.filter((f) => f.error !== 'Signer has already signed')
.map((f) => f.documentId);
if (retryIds.length > 0) {
await korala.documents.bulkSign({
documentIds: retryIds,
signerEmail: '[email protected]',
});
}
}Identifying Signers
You can identify the target signer by email or external ID:
// By email
await korala.documents.bulkSign({
documentIds,
signerEmail: '[email protected]',
});
// By external ID
await korala.documents.bulkSign({
documentIds,
signerExternalId: 'user_123',
});Exactly one of signerEmail or signerExternalId must be provided.
IP Attribution
When your server calls the bulk sign API on behalf of end users, the audit trail records your server’s IP address. To preserve the real end-user IP for compliance, pass it via the X-Client-IP header. This value is stored separately as claimedIpAddress in the audit trail alongside the verified network IP.
TypeScript
const result = await korala.documents.bulkSign(
{
documentIds,
signerEmail: '[email protected]',
},
{ clientIp: endUserIpAddress },
);Note: The
X-Client-IPvalue must be a valid IP address (IPv4 or IPv6). Invalid values are silently ignored. The header is validated but not verified — it represents the partner’s assertion of the end-user’s IP.
Limits
- Maximum 500 documents per bulk sign request
- Documents must be in Pending status
- The target signer must not have already signed or declined
Response Format
{
"signed": 198,
"failed": 2,
"results": [
{
"documentId": "doc-1",
"success": true,
"allSigned": true
},
{
"documentId": "doc-2",
"success": true,
"allSigned": false
},
{
"documentId": "doc-x",
"success": false,
"error": "Document not found"
}
]
}When allSigned is true, the document has been queued for completion (cryptographic signing and timestamping). Listen for the document_completed webhook to know when the signed PDF is ready.