TypeScript API Client
The official TypeScript API client provides a type-safe interface for the Korala API.
Installation
npm install @korala/api-client
# or
yarn add @korala/api-client
# or
pnpm add @korala/api-clientQuick Start
import { KoralaClient } from '@korala/api-client';
const korala = new KoralaClient({
apiKeyId: process.env.KORALA_API_KEY_ID!,
apiSecret: process.env.KORALA_API_SECRET!,
});
// Create a document
const { documentId, uploadUrl } = await korala.documents.createUploadUrl({
filename: 'contract.pdf',
contentType: 'application/pdf',
});
// Upload the file to S3
await fetch(uploadUrl, {
method: 'PUT',
body: pdfBuffer,
headers: { 'Content-Type': 'application/pdf' },
});
// Confirm the upload
await korala.documents.confirmUpload(documentId);
// Add a signer
const signer = await korala.signers.create(documentId, {
email: '[email protected]',
name: 'John Doe',
});
// Add a signature field
await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'signature',
pageNumber: 1,
xPosition: 100,
yPosition: 500,
width: 200,
height: 50,
});
// Send for signing
await korala.documents.send(documentId);Configuration
interface KoralaClientConfig {
// Required
apiKeyId: string; // API key ID
apiSecret: string; // API secret for HMAC signing
// Optional
baseUrl?: string; // API base URL (default: https://api.korala.ai/api/v1)
timeout?: number; // Request timeout in ms (default: 30000)
}Documents
Create Upload URL
const { documentId, uploadUrl, key } = await korala.documents.createUploadUrl({
filename: 'contract.pdf',
contentType: 'application/pdf',
});
// Upload the file to the presigned URL
await fetch(uploadUrl, {
method: 'PUT',
body: pdfBuffer,
headers: { 'Content-Type': 'application/pdf' },
});
// Confirm upload
await korala.documents.confirmUpload(documentId);Get Document
const document = await korala.documents.get(documentId);
console.log(document.status);
console.log(document.originalFileUrl);
console.log(document.signedFileUrl);List Documents
const documents = await korala.documents.list();Send Document
await korala.documents.send(documentId);Void Document
await korala.documents.void(documentId);Get Audit Trail
const events = await korala.documents.getAuditTrail(documentId);Bulk Sign
Sign multiple documents at once using a saved signature:
const result = await korala.documents.bulkSign({
documentIds: ['doc-1', 'doc-2', 'doc-3'],
signerEmail: '[email protected]',
autoFillDateValue: '2026-02-18', // optional, defaults to today
});
console.log(`Signed: ${result.signed}, Failed: ${result.failed}`);
for (const doc of result.results) {
if (!doc.success) {
console.error(`${doc.documentId}: ${doc.error}`);
}
}IP Attribution
When calling bulk sign on behalf of an end user, pass their IP for audit trail attribution:
const result = await korala.documents.bulkSign(
{
documentIds: ['doc-1', 'doc-2'],
signerEmail: '[email protected]',
},
{ clientIp: '203.0.113.42' },
);See the Bulk Signing guide for the complete workflow.
Signatures
Manage saved signatures for signers. Saved signatures are used by bulk sign to auto-fill Signature and Initials fields.
Create Signature
const signature = await korala.signatures.create({
email: '[email protected]',
name: 'Jane Smith',
signatureImageUrl: 'data:image/png;base64,...',
isDefault: true, // optional, defaults to true
});List Signatures
// List all
const signatures = await korala.signatures.list();
// Filter by email
const ceoSignatures = await korala.signatures.list({ email: '[email protected]' });Get Signature
const signature = await korala.signatures.get(signatureId);Delete Signature
await korala.signatures.delete(signatureId);Signers
Add Signer
const signer = await korala.signers.create(documentId, {
email: '[email protected]',
name: 'John Doe',
signingOrder: 1, // optional
});List Signers
const signers = await korala.signers.list(documentId);Remove Signer
await korala.signers.delete(documentId, signerId);Fields
Add Field
const field = await korala.fields.create(documentId, {
signerId: signer.id,
fieldType: 'signature', // 'signature' | 'initials' | 'date' | 'text' | 'checkbox'
pageNumber: 1,
xPosition: 100,
yPosition: 500,
width: 200,
height: 50,
});List Fields
const fields = await korala.fields.list(documentId);Remove Field
await korala.fields.delete(documentId, fieldId);Webhooks
Create Webhook
const webhook = await korala.webhooks.create({
url: 'https://your-app.com/webhooks/korala',
events: ['document_completed', 'document_signed'],
});
// Save the secret for signature verification!
console.log(webhook.secret);List Webhooks
const webhooks = await korala.webhooks.list();Get Webhook
const webhook = await korala.webhooks.get(webhookId);Update Webhook
await korala.webhooks.update(webhookId, {
events: ['document_completed'],
isActive: true,
});Delete Webhook
await korala.webhooks.delete(webhookId);Get Delivery History
const deliveries = await korala.webhooks.getDeliveries(webhookId);Send Test Event
const delivery = await korala.webhooks.sendTestEvent(webhookId);Error Handling
import { KoralaError, KoralaValidationError } from '@korala/api-client';
try {
await korala.documents.send(documentId);
} catch (error) {
if (error instanceof KoralaValidationError) {
console.error('Validation failed:', error.errors);
} else if (error instanceof KoralaError) {
console.error(`API error ${error.status}: ${error.message}`);
} else {
throw error;
}
}TypeScript Types
All response types are fully typed:
import type {
DocumentDto,
DocumentStatus,
SignerDto,
SignerStatus,
FieldDto,
FieldType,
WebhookDto,
WebhookEventType,
WebhookPayloadDto,
// Event-specific data types
DocumentCreatedEventData,
DocumentSentEventData,
DocumentViewedEventData,
DocumentSignedEventData,
DocumentCompletedEventData,
DocumentFailedEventData,
DocumentVoidedEventData,
DocumentDeclinedEventData,
TestEventData,
} from '@korala/api-client';
function handleDocument(doc: DocumentDto) {
if (doc.status === 'completed') {
console.log(`Completed at: ${doc.completedAt}`);
}
}
function handleWebhook(payload: WebhookPayloadDto) {
switch (payload.event) {
case 'document_signed': {
const data = payload.data as DocumentSignedEventData;
console.log(`Signer ${data.signerId} signed, all done: ${data.allSigned}`);
break;
}
case 'document_completed': {
const data = payload.data as DocumentCompletedEventData;
console.log(`Document completed at ${data.completedAt}`);
break;
}
}
}Webhook Verification
The client includes a helper for verifying webhook signatures:
import { verifyWebhookSignature } from '@korala/api-client';
app.post('/webhooks/korala', express.raw({ type: 'application/json' }), (req, res) => {
const isValid = verifyWebhookSignature({
secret: process.env.WEBHOOK_SECRET!,
signature: req.headers['x-signature'] as string,
timestamp: req.headers['x-timestamp'] as string,
body: req.body.toString(),
});
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
// Process event...
res.json({ received: true });
});Last updated on