Skip to Content
GuidesDocuments

Documents

Documents are the core resource in Korala. This guide covers creating documents, managing their lifecycle, and retrieving signed copies.

Document Lifecycle

StatusDescription
draftDocument created but not sent for signing
pendingSent to signers, awaiting signatures
completedAll signatures collected, document sealed
voidedCancelled before completion
expiredExpiration date passed before completion

Creating a Document

Document creation is a two-step process:

  1. Get an upload URL - Request a pre-signed URL for uploading your PDF
  2. Confirm the upload - Tell Korala the upload is complete
import { KoralaClient } from '@korala/api-client'; import fs from 'fs'; const korala = new KoralaClient({ apiKeyId: 'your-api-key-id', apiSecret: 'your-api-secret', }); // Step 1: Get upload URL const { documentId, uploadUrl, key } = await korala.documents.createUploadUrl({ filename: 'contract.pdf', contentType: 'application/pdf', }); // Step 2: Upload the file const pdfBuffer = fs.readFileSync('contract.pdf'); await fetch(uploadUrl, { method: 'PUT', body: pdfBuffer, headers: { 'Content-Type': 'application/pdf' }, }); // Step 3: Confirm the upload const document = await korala.documents.confirmUpload(documentId); console.log(`Document created: ${document.id}`); console.log(`Status: ${document.status}`); // 'draft'

Sending for Signatures

Once you’ve added signers and fields, send the document:

// Add signers first const signer = await korala.signers.create(documentId, { email: '[email protected]', name: 'John Doe', }); // Add signature fields await korala.fields.create(documentId, { signerId: signer.id, fieldType: 'signature', pageNumber: 1, xPosition: 100, yPosition: 500, width: 200, height: 50, }); // Send for signing const document = await korala.documents.send(documentId, { electronicDisclosure: { id: 'acme-electronic-signing-terms', version: '2026-09-01', title: 'Electronic signature disclosure', contentHtml: '<p>Contact Acme Legal for a paper copy.</p>', }, }); console.log(`Status: ${document.status}`); // 'pending'

electronicDisclosure is optional. Use it when your organization needs custom paper-copy, withdrawal, fee, or contact terms. Korala sanitizes the HTML and freezes the profile when you send the document. The final signing action links to the stored content; later edits cannot change it. Korala records the profile ID, version, and content hash in the audit trail and Certificate of Completion.

Saving a reusable signature

In both the single-document and packet signing viewers, a signer can draw or type a signature using their signing link. To reuse a saved signature or select Save for future, they must first verify their email through the signer portal. A forwarded signing link does not grant access to saved signatures.

Signatures and initials are saved separately. A signature saved while signing one document is available in packets from the same organization, and vice versa. Changing a saved signature does not change an authorized packet action.

Reminders and Expiration

Korala can nudge idle signers and close out stale documents automatically, so you don’t have to chase people by hand.

Expiration. Pass expiresInDays when sending to set a deadline; if unsigned by then, the document moves to expired (a terminal state, like voided), signer links stop working, and a document.expired webhook fires. Omit it to fall back to your organization’s default expiry (defaultExpirationDays in org settings), or to never expire if neither is set.

// Expire this document if unsigned after 14 days. const document = await korala.documents.send(documentId, { expiresInDays: 14 });

Reminders. Enable reminders once at the organization level; every unsigned signer whose turn it is (sequential order is respected) is then emailed on a cadence, up to a cap.

await korala.organizations.updateSettings({ reminderEnabled: true, reminderIntervalDays: 3, // default 3 maxReminders: 3, // default 3 defaultExpirationDays: 30, });

Reminders and expiry are evaluated by a background scheduler, so they take effect within minutes of becoming due rather than exactly on the second. Documents sent with suppressNotifications (or in sandbox) are never reminded. Each reminder and the expiry are recorded in the audit trail.

Retrieving Documents

Get a Single Document

const document = await korala.documents.get(documentId); console.log(`Name: ${document.name}`); console.log(`Status: ${document.status}`); console.log(`Original PDF: ${document.originalFileUrl}`); if (document.status === 'completed') { console.log(`Signed PDF: ${document.signedFileUrl}`); console.log(`Certificate: ${document.certificateFileUrl}`); console.log(`Completed: ${document.completedAt}`); }

List All Documents

// List all documents const documents = await korala.documents.list(); // Filter by status const pendingDocs = await korala.documents.list({ status: 'pending' }); // Pagination const page2 = await korala.documents.list({ limit: 10, offset: 10 });

Downloading Files

Completed documents have three files:

FileDescription
originalFileUrlThe original uploaded PDF
signedFileUrlPDF with visual signatures and cryptographic seal
certificateFileUrlCertificate of Completion (audit trail)
const document = await korala.documents.get(documentId); if (document.status === 'completed') { // Download signed PDF const signedPdf = await fetch(document.signedFileUrl); fs.writeFileSync('signed-contract.pdf', await signedPdf.buffer()); // Download certificate const certificate = await fetch(document.certificateFileUrl); fs.writeFileSync('certificate.pdf', await certificate.buffer()); }

Voiding a Document

Cancel a document before it’s completed:

const document = await korala.documents.void(documentId); console.log(`Status: ${document.status}`); // 'voided'

Voiding a document is permanent. Korala notifies signers that you cancelled the document.

Response Format

{ "id": "doc_abc123", "name": "contract.pdf", "status": "completed", "originalFileUrl": "https://storage.example.com/original.pdf", "signedFileUrl": "https://storage.example.com/signed.pdf", "certificateFileUrl": "https://storage.example.com/certificate.pdf", "expiresAt": null, "completedAt": "2024-01-15T10:30:00Z", "createdAt": "2024-01-14T09:00:00Z", "updatedAt": "2024-01-15T10:30:00Z" }

Organize with collections

Documents can belong to several optional collections. Supply collectionIds when requesting an upload URL, or organize existing documents in bulk. Filter document lists by collectionId, unassigned, search, and status.

See Collections for scope, archive behavior, request limits, and API and SDK examples.

Last updated on