Skip to main content
Intake scripts run server-side JavaScript on every document uploaded through an intake endpoint. They execute after metadata is merged but before the document is stored, giving you a chance to inspect the content, enrich metadata, reject invalid uploads, and control which tasks are created.

How It Works

When a document is uploaded to an intake:
  1. Metadata is merged (intake config + document metadata + upload params)
  2. Your script runs with access to filename, content, and metadata
  3. Based on the script return value, the upload is accepted or rejected
  4. If accepted, the document is stored and tasks are created per the script’s instructions
Scripts run in a sandboxed Goja JavaScript runtime with a 5-second timeout. They cannot make network requests, access the filesystem, or call platform APIs — they operate purely on the data provided to them.

Available Variables

VariableTypeDescription
filenamestringOriginal uploaded filename
fileSizenumberFile size in bytes
mimeTypestringDetected MIME type of the file
metadataobjectMutable metadata object. Merged from: intake config < document metadata < upload params
document.textstringExtracted text content (first 5 pages for PDFs)
document.pageCountnumberNumber of pages (if detectable)
document.metadataobjectRead-only document-level metadata from the file
log(level, msg)functionWrite to server logs. Levels: debug, info, warn, error
labelsstringComma-separated label names from the upload request
statusIdstringDocument status ID from the upload request
externalDatastringRaw external data JSON string from the upload request. After intake processing, this data is injected into the KDDB document under key "default" and accessible via doc.get_external_data().
documentVersionstringDocument version from the upload request

Return Value

The script must return an object. All fields are optional:
({
  metadata: metadata,          // Modified metadata object
  reject: false,               // Reject the upload (HTTP 400)
  rejectReason: "",            // Reason shown to caller
  taskTemplates: []            // Tasks to create (see below)
})
If the script returns nothing (no return statement), the upload proceeds with the original metadata and falls back to the static task template.

Task Templates

The taskTemplates array gives scripts full control over which tasks are created for each document.

Behavior

Script returnsResult
taskTemplates: [{slug: "..."}]Creates tasks from those templates
taskTemplates: []Creates no tasks (overrides static template)
No taskTemplates fieldFalls back to static task template

Template Reference Fields

FieldTypeRequiredDefault
slugstringYes
prioritynumberNoTemplate default
teamSlugstringNoTemplate default
assigneeEmailstringNoUnassigned
titlestringNoFilename or AI naming
descriptionstringNoEmpty
metadataobjectNo{}

Example: Route by Document Type

var templates = [];

if (document.text.indexOf("INVOICE") >= 0) {
  templates.push({
    slug: "invoice-review",
    priority: 2,
    teamSlug: "finance-team",
    title: "Invoice: " + filename
  });
} else if (document.text.indexOf("CONTRACT") >= 0) {
  templates.push({
    slug: "legal-review",
    teamSlug: "legal-team"
  });
}

({
  metadata: metadata,
  taskTemplates: templates
})

Example: Multiple Tasks from One Document

// Every document gets a processing task
var templates = [
  { slug: "document-processing" }
];

// High-priority documents also get a review task
if (metadata.priority === "urgent") {
  templates.push({
    slug: "urgent-review",
    priority: 1,
    title: "URGENT: " + filename
  });
}

({
  metadata: metadata,
  taskTemplates: templates
})

Example: Conditional Skip

// Only create tasks for PDFs over 1MB
if (mimeType === "application/pdf" && fileSize > 1024 * 1024) {
  ({
    metadata: metadata,
    taskTemplates: [{ slug: "large-pdf-review" }]
  });
} else {
  // No task needed — just store the document
  ({
    metadata: metadata,
    taskTemplates: []
  });
}

Validation and Rejection

Return reject: true to refuse the upload before it is stored:
// Reject files over 100MB
if (fileSize > 100 * 1024 * 1024) {
  ({
    metadata: metadata,
    reject: true,
    rejectReason: "File exceeds 100MB limit"
  });
}

// Reject non-PDF files
if (!filename.endsWith(".pdf")) {
  ({
    metadata: metadata,
    reject: true,
    rejectReason: "Only PDF files are accepted"
  });
}

({
  metadata: metadata,
  reject: false
})
The caller receives an HTTP 400 with the rejection reason:
{
  "error": "SCRIPT_REJECTED",
  "rejectReason": "File exceeds 100MB limit",
  "filename": "huge-file.bin"
}

Metadata Enrichment

The metadata object is mutable. Any changes are persisted on the document family:
metadata.source = "intake";
metadata.receivedAt = new Date().toISOString();
metadata.classification = document.text.indexOf("CONFIDENTIAL") >= 0
  ? "confidential"
  : "general";

({
  metadata: metadata,
  reject: false
})

API Response

When tasks are created, the upload response includes task IDs:
{
  "id": "doc-family-id",
  "path": "invoice.pdf",
  "taskId": "task-id-1",
  "taskIds": ["task-id-1", "task-id-2"]
}
FieldDescription
taskIdID of the first task created (backward compatible)
taskIdsArray of all task IDs created
taskId is included for backward compatibility when exactly one task is created. Always use taskIds for new integrations.

Shared Modules

Load reusable JavaScript modules using the Module Refs picker in the Script tab. Selected modules execute before your script, making their functions available in global scope:
// Assuming "my-org/doc-classifier" module provides classifyDocument()
var docType = classifyDocument(document.text);

var templates = [];
if (docType.templates) {
  docType.templates.forEach(function(t) {
    templates.push({ slug: t });
  });
}

({
  metadata: metadata,
  taskTemplates: templates
})

Limitations

  • 5-second timeout — scripts that exceed this are terminated and the upload fails
  • No network access — scripts cannot make HTTP requests or call external APIs
  • No filesystem access — scripts operate only on the provided variables
  • Text extraction — only the first 5 pages of PDFs are extracted; other file types may not have text available
  • Goja runtime — supports ES5.1 JavaScript with some ES6+ features available