Skip to Content
SDKsTypeScript API Client

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-client

Quick 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.

Signing Packets

Create an authenticated packet-management client, then send one recipient to Korala to review and authorize up to 50 documents:

const packet = await korala.signingPackets.create({ name: 'Series A closing', externalId: 'closing-2026-0142', recipient: { name: 'Alex Manager', email: '[email protected]' }, items: [ { documentId: subscription.id, signerId: subscriptionSigner.id }, { documentId: sideLetter.id, signerId: sideLetterSigner.id }, ], redirectUrl: 'https://fund.example.com/closing/complete', }); const sent = await korala.signingPackets.send(packet.id, { delivery: 'email', }); console.log(sent.signingUrl, sent.deliveryStatus);

The API key can prepare, send, inspect, remind, void, and retrieve audit data. The recipient must verify their email and complete the packet in Korala. See the Signing Packets guide for state handling, webhooks, audit evidence, and limits.

Signatures

Manage saved signatures for signers. Bulk sign uses saved signatures 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

The client exports types for all responses:

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 }); });

Collections and paginated lists

Use client.collections to create, find, archive, restore, and organize collections. See the collections workflow for external-ID reconciliation, explicit creation destinations, and packet preparation.

Use client.documents.listPage(query) for the pagination envelope { data, total, page, limit, totalPages }. The deprecated documents.list() now returns the first page’s items, correcting its previous mismatch between the declared array and the server’s envelope. It does not fetch every page. templates.list(query) already returns an envelope; templates.listPage(query) is an alias. Both resources accept collection and unassigned filters.

Last updated on