Skip to Content
Documents and templatesEmbedded template preparation

Embedded template preparation

Embed PDF upload and template editing in your application. In review mode, your backend defines the fields; users review the suggested positions, move or resize them, and save. You can also upload through your own screen and embed the editor after upload.

Preparation modes

Review

Your backend defines the fields and their settings. Users review their positions, move or resize them, and save. Set mode: TemplatePreparationMode.Review.

Review mode with API-defined fields, a compact field selector and zoom controls

Full

Users can add or remove fields and edit their properties. Omit mode or set mode: TemplatePreparationMode.Full to use the full editor.

Full mode with the field palette and editable field properties

These screenshots use a sample PDF and illustrative field positions.

SDK versions

Use @korala/api-client 1.32.0 or later for session creation and @korala/react 1.4.0 or later for KoralaTemplateEditor. If you import DTOs separately, use @korala/public-dtos 1.32.0 or later. The REST API and plain iframe integration below do not require the React package.

Create a session on your server

Authenticate with an HMAC API key. Never pass API credentials to the browser. Authorize the person in your own application before creating a session.

import { FieldType, TemplatePreparationMode, type TemplatePreparationFieldDto } from '@korala/api-client'; const fields: TemplatePreparationFieldDto[] = [ { fieldType: FieldType.Text, label: 'Legal name', mergeFieldName: 'recipient_name', required: true }, { fieldType: FieldType.Signature, label: 'Signature', mergeFieldName: 'recipient_signature', required: true }, { fieldType: FieldType.Date, label: 'Date signed', mergeFieldName: 'signed_at', required: true, signingDate: true }, ]; const session = await korala.templates.createPreparationSession({ mode: TemplatePreparationMode.Review, fields, name: 'Agreement', roleName: 'Signer', parentOrigin: 'https://app.example.com', }); // Return session.embedUrl to your authorized browser.

The REST equivalent is POST /api/v1/template-preparation-sessions. The response contains templateId, token, embedUrl, and expiresAt. A new-template session creates an inactive PDF template and one role, inherits the API key’s sandbox mode, and expires after one hour. Access is limited to that template; the token cannot list templates, send documents, or use other API routes. Treat both the token and embed URL as credentials. If a session becomes unavailable, create a fresh session. Abandoned templates remain inactive and can be deleted through your server’s ordinary template API.

parentOrigin must be an exact HTTPS origin with no path or trailing slash. HTTP is allowed only for localhost and 127.0.0.1 during development.

Simplified review mode

Set mode: TemplatePreparationMode.Review on your server to give people an upload-and-review flow. Your backend must supply fields: a non-empty list of field definitions with unique variable keys. The example above configures three fields; Korala does not prescribe their names or count. Set signingDate: true on a date field to fill it automatically when signing. In review mode, Korala asks AI for positions for your allowed field keys only. AI cannot introduce field definitions or change their types. Korala discards unknown keys, duplicate keys and rectangles outside the PDF page. If AI omits a field, the editor supplies a default position for review. Scans without extractable text may need manual positioning. People can select a field, move it, resize it, or move it to another page. They cannot add or remove fields, rename variables, change signer roles, or edit field properties. These restrictions also apply to the browser API.

If detection is unavailable, the editor offers a prepared default layout for review. Saving requires the same backend-defined fields and settings. Reopening a review session preserves the approved layout and skips automatic positioning.

The default Full mode retains the configurable editor described below. Use that mode for integrations that need additional fields or template settings. When reopening, supply matching field types, keys, labels, required flags, and signing-date settings. Review mode accepts coordinate fields without defaults, shared fill, conditions, or AcroForm bindings. Use the full editor for those source templates.

Field definitions

Your backend owns these settings. The browser can change page, position and size.

PropertyContract
fieldTypeRequired: text, signature, initials, date, checkbox, dropdown, or radio. Repeated types are allowed.
labelRequired, 1–100 characters; the editor displays this name.
mergeFieldNameRequired, unique in the session, at most 100 characters. Start with an ASCII letter; use letters, digits and underscores.
requiredRequired boolean. Set true for fields the signer must complete.
signingDateOptional boolean, default false. Set true on a date field to use the date of signing. Other types cannot enable it.
optionsRequired for dropdowns: 1–200 non-empty strings, at most 500 characters each. Other types cannot set it.
groupKeyRequired for radios; optional for checkboxes. Members with the same key form a mutually exclusive choice group. Up to 256 characters.
groupRequiredOptional boolean, default false. Require at least one choice in the group; needs groupKey. Set individual group members to required: false.

For example, your backend can configure a dropdown and two required-as-a-group radio choices:

const choiceFields: TemplatePreparationFieldDto[] = [ { fieldType: FieldType.Dropdown, label: 'Region', mergeFieldName: 'region', required: true, options: ['North', 'South'] }, { fieldType: FieldType.Radio, label: 'Email', mergeFieldName: 'contact_email', required: false, groupKey: 'contact_method', groupRequired: true }, { fieldType: FieldType.Radio, label: 'Phone', mergeFieldName: 'contact_phone', required: false, groupKey: 'contact_method', groupRequired: true }, ];

The browser can position these fields, but cannot change dropdown options or group settings. Choose checkbox for an independent yes/no value and radio with groupKey for one choice from a group.

Review sessions require at least one definition. There is no preparation-specific field-count cap; normal API request-size limits still apply. Korala positions large field lists in sequential AI batches. Both the hosted upload and editor-only paths use this contract. A 15-field configuration uses the same editor and completion event as a three-field agreement.

PDFs with AcroForm fields

In review mode, Korala uses embedded AcroForm names and rectangles as hints when suggesting positions for your backend-defined fields. It does not import extra fields, signer roles, choices or variable names from the PDF. Review fields use coordinate placement; Korala does not bind them to the PDF’s native widgets. The uploaded PDF retains its existing form content.

An existing template with AcroForm-bound fields cannot open in review mode. Use Full mode for those templates, or upload the PDF as a new template and configure coordinate fields through your backend. Full mode uses the existing AcroForm field-detection flow, with suggestions for users to review.

Viewer controls

Select a field on the PDF and drag it into place. Drag the diagonal grip inside its bottom-right corner to resize. The footer contains zoom controls and, for multipage PDFs, page navigation. On multipage PDFs, or when there are more than three fields, a selector lets you find a field and open its page. The footer stays one row on desktop and two rows on phones.

Use + or − to zoom, or open the percentage menu for a preset or Fit width. Zoom changes the display, not the saved PDF coordinates. To move a field to another page, select it and navigate to the destination. Open the Field actions menu (•••) beside the field selector, then choose Move to page 2 (for example). The menu names the selected field and its current page. Choose Go to field to return to its location. Moving changes the field’s page; it does not create a copy.

Use your own upload screen

Your backend can use the regular template upload API, then create a review session for that uploaded template. Keep the template ID associated with the authorized user on your backend.

// Backend: authorize the user, then request an upload URL. const upload = await korala.templates.createUploadUrl({ filename: 'agreement.pdf', contentType: 'application/pdf', }); // Return upload.uploadUrl to your upload screen. The browser PUTs the PDF // to that URL with Content-Type: application/pdf, then notifies your backend. // Backend: confirm the upload after checking ownership of upload.templateId. await korala.templates.confirmUpload(upload.templateId, { name: 'Agreement' }); await korala.templates.addSignerRole(upload.templateId, { name: 'Recipient', signingOrder: 1, }); const session = await korala.templates.createPreparationSession({ templateId: upload.templateId, mode: TemplatePreparationMode.Review, fields, parentOrigin: 'https://app.example.com', });

The uploaded template must have one signer role. Leave its fields empty; Korala prepares your configured fields in an editing draft and starts positioning when the embedded editor opens. Users skip the hosted upload screen. Save returns the same uploaded template ID. A template that already has matching fields opens the approved layout instead and skips detection.

Edit an existing PDF template

Create another session from your backend using the original approved template ID:

const session = await korala.templates.createPreparationSession({ templateId: existingTemplateId, mode: TemplatePreparationMode.Review, fields, parentOrigin: 'https://app.example.com', });

The editor opens the existing PDF and fields directly. Editing currently requires one signer role and the same sandbox/live mode as your API key. It creates an inactive draft; the original template stays usable during review. Save publishes the approved PDF and fields atomically and returns the original template ID, keeping its signer role ID. If the original changes during review, save returns 409 and you must create a fresh session. Abandoned editing drafts remain inactive.

Embed the editor

embedUrl comes from session.embedUrl in the server-side createPreparationSession() response. Return that value to the authorized user through your own backend endpoint. For example, your /api/template-preparation handler can return it after authorizing the request:

// Your backend; use the fields defined above and keep HMAC credentials here. const session = await korala.templates.createPreparationSession({ mode: TemplatePreparationMode.Review, fields, name: 'Agreement', roleName: 'Recipient', parentOrigin: 'https://app.example.com', }); return Response.json({ embedUrl: session.embedUrl });

Your frontend requests that URL from your backend, then renders the editor. /api/template-preparation below belongs to your application.

import { KoralaTemplateEditor } from '@korala/react'; const response = await fetch('/api/template-preparation', { method: 'POST' }); if (!response.ok) throw new Error('Could not open template preparation'); const { embedUrl } = await response.json(); <KoralaTemplateEditor embedUrl={embedUrl} height={800} onComplete={(templateId) => saveTemplateReference(templateId)} />

Close or replace your modal in onComplete, or show your own success screen. The hosted editor shows a saved-template confirmation while it remains mounted. onLoaded is optional. onComplete runs after the server validates the approved fields and activates the template. Duplicate completion events are ignored by the component. Keep your own template mapping on your server and verify the template through your authenticated API before accepting a browser callback as authoritative.

Preparation accepts PDFs up to 20 MB (or the lower plan limit). Rotated pages must be exported with page rotation flattened before upload; the editor refuses them before field placement so signing coordinates remain consistent.

Review mode starts positioning after upload or after opening a newly uploaded, empty template. You can choose Review fields now if detection is unavailable; Korala uses default positions for your configured fields.

In full mode, accept or reject AI suggestions, then adjust accepted fields in the visual editor. If detection fails, retry it or place fields manually.

In full mode, completion requires three fields on the session’s signer role:

  • Required text with mergeFieldName: "legal_name" (legal name).
  • Required signature.
  • Required date with signingDate: true (date of signing).

These fields must have no default value, shared fill, or conditional requirement. Every field must fit within its PDF page. Newly placed text fields start as Legal name; change their merge name in field properties when using them for another purpose. Newly placed dates start as dates of signing; turn that off in properties for ordinary dates. For detected fields, mark the legal-name text field as Legal name in properties and turn on Date of signing for the appropriate date. Fields can be removed, but save remains blocked until the required three are present.

Edits are persisted as an inactive draft. Save activates the template and closes the session to further edits. Retrying completion returns the same ID until expiry. The approved PDF is a separate copy, so the original upload URL cannot overwrite it after approval. Create a fresh session for a new PDF.

Hosted iframe without React

Set an iframe’s src to embedUrl. The credential is in its URL fragment, which is not sent in HTTP requests or referrers. The editor posts only to the session’s configured parentOrigin:

{ source: 'korala-template-preparation', event: 'completed', // or 'loaded' templateId: '...', }

Check both event.origin against the hosted editor’s origin and event.source against your iframe’s contentWindow. Events never include the session token. The existing EMBED_ALLOWED_ORIGINS deployment policy also applies to preparation pages.

Scoped browser API

The hosted page uses Authorization: Bearer <session.token> with /api/v1/template-preparation. This token works only on these routes:

MethodRoutePurpose
GET/Template details and session state
GET/upload-urlPresigned PDF upload URL before confirmation
POST/confirmValidate PDF and freeze its uploaded contents
POST/fieldsAdd a field using the normal template field DTO
PATCH/fields/:fieldIdUpdate a field belonging to this template
DELETE/fields/:fieldIdRemove a field from this template
POST/detectionStart or retry AI suggestions
GET/detectionDetection status and suggested fields
PATCH/proposed/:fieldId/acceptAccept a suggestion for the session role; body accepts required
PATCH/proposed/:fieldId/rejectReject a suggestion
POST/proposed/accept-allAccept suggestions above minConfidence
POST/review-positionsPrepare the fixed review layout; optional useDefaultPositions bypasses detection
POST/completeValidate, activate, and return templateId

Signer-role assignments are always pinned to the session role. A concurrent mutation receives 409; wait for pending edits before saving. An expired or unknown token receives 401. Existing document generation and embedded signing APIs continue to use the returned approved template ID.

Last updated on