Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@ninjadoc-ai/sdk

db.vit895MIT1.0.9TypeScript support: included

TypeScript SDK for document processing with zero-friction framework adapters. Features intelligent coordinate handling, semantic regions, React UI overlays, and automatic route detection for Remix and Next.js. Transform raw bounding boxes into interactive

document-processing, ai, ocr, typescript, react, remix, nextjs, framework-adapters, zero-friction, auto-detection, pdf, extraction, coordinates, bounding-box, regions, highlight, overlay, annotation, computer-vision, data-extraction, document-ai, form-processing, invoice-processing, text-extraction, visualization, ui-components, semantic-regions, document-analysis

readme

@ninjadoc-ai/sdk

Description

Ninjadoc AI is the first Document Q&A Platform that lets you ask questions like "What's the total?" to build extraction schemas, then use our API to get structured data with exact coordinates as proof. No training required.

This SDK provides TypeScript/JavaScript integration for document processing with a zero-boilerplate API handler, intelligent coordinate handling, and React UI overlays.

Features

  • Zero-Boilerplate BFF: Use our createApiHandler to create a secure API proxy in your backend with a single function call. No manual endpoint creation needed.
  • Natural Language Q&A: Ask questions like "What's the total?" or use technical field names.
  • Coordinate Precision: Get exact bounding box coordinates for every extracted field.
  • React Integration: Built-in HighlightOverlay component for interactive document viewing.
  • Developer-Friendly: Clean, type-safe clients for both browser and server.
  • Simple Schema Setup: Build extraction schemas by asking natural language questions, no training required.

Installation

npm install @ninjadoc-ai/sdk

Framework Adapters: Zero-Friction Integration

The SDK now includes framework-specific adapters that reduce integration friction to almost zero. These adapters handle framework-specific patterns, environment variables, and error handling automatically.

Remix Adapter

For Remix applications, use the framework adapter for seamless integration:

// app/routes/api.ninjadoc.$.tsx
import { createRemixApiRoute } from '@ninjadoc-ai/sdk/frameworks/remix';

// Zero-friction setup - API key automatically read from NINJADOC_API_KEY
const { loader, action } = createRemixApiRoute();

export { loader, action };

That's it! The adapter automatically:

  • Reads your API key from environment variables
  • Handles Remix's loader/action pattern
  • Provides framework-appropriate error responses
  • Manages request/response conversion

Zero-Friction Browser Client

The browser client now automatically detects your route setup:

// No configuration needed - works out of the box!
const client = createBrowserClient();

// The client automatically:
// 1. Tries framework adapter routes (/api/ninjadoc/*)
// 2. Falls back to legacy routes (/api/extract, /api/jobs/*/status)
// 3. Remembers the working pattern for future requests

This means developers can just call createBrowserClient() with no parameters and it will work with both new framework adapters and existing legacy setups!

Next.js Adapter

For Next.js App Router applications:

// app/api/ninjadoc/[...path]/route.ts
import { createNextApiRoute } from '@ninjadoc-ai/sdk/frameworks/next';

// Zero-friction setup - API key automatically read from NINJADOC_API_KEY
const handler = createNextApiRoute();

export { handler as GET, handler as POST, handler as PUT, handler as DELETE };

The Next.js adapter automatically:

  • Reads your API key from environment variables
  • Handles NextRequest/NextResponse objects
  • Provides framework-appropriate error responses
  • Manages dynamic route parameters

Advanced Configuration

Both adapters support advanced configuration:

const { loader, action } = createRemixApiRoute({
  apiKey: 'your-explicit-api-key', // or omit to use env var
  apiKeyEnv: 'CUSTOM_ENV_VAR', // default: 'NINJADOC_API_KEY'
  onError: (error, context) => {
    // Custom error handling
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500
    });
  }
});

Quick Start: Zero-Friction Integration

The easiest way to get started is using our framework adapters that handle everything automatically.

1. Add Framework Adapter Route

For Remix:

// app/routes.ts - Add this line:
route("/api/ninjadoc/*", "routes/api.ninjadoc.$.tsx"),

// app/routes/api.ninjadoc.$.tsx
import { createRemixApiRoute } from '@ninjadoc-ai/sdk/frameworks/remix';

const { loader, action } = createRemixApiRoute();
export { loader, action };

For Next.js:

// app/api/ninjadoc/[...path]/route.ts
import { createNextApiRoute } from '@ninjadoc-ai/sdk/frameworks/next';

const handler = createNextApiRoute();
export { handler as GET, handler as POST, handler as PUT, handler as DELETE };

2. Use the Client (Zero Configuration)

// Your React Component
import { createBrowserClient } from '@ninjadoc-ai/sdk';
import { useState } from 'react';

function MyUploader() {
  const [jobId, setJobId] = useState<string | null>(null);
  const [document, setDocument] = useState<any | null>(null);

  const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    // Zero configuration - automatically detects your route setup
    const client = createBrowserClient();

    // 1. Extract document via your app's API handler
    const job = await client.extractDocument(file, 'your-processor-uuid');
    setJobId(job.id);

    // 2. Wait for completion and get the processed document
    const processedDoc = await client.processDocument(job.id);
    setDocument(processedDoc);

    // 3. Access data in multiple ways:

    // Find specific regions for visualization
    const totalRegion = client.findRegion(processedDoc.regions, 'invoice_total');
    console.log('Total:', totalRegion?.value);
    console.log('AI Answer:', totalRegion?.ai_answer);

    // Access raw field data with AI answers and confidence
    processedDoc.regions.forEach(region => {
      console.log(`Field: ${region.label}`);
      console.log(`AI Answer: ${region.ai_answer}`);
      console.log(`Confidence: ${region.confidence}`);
      console.log(`Coordinates:`, region.geometry);
    });
  };

  return <input type="file" onChange={handleFileChange} />;
}

That's it! The framework adapter automatically:

  • Reads your NINJADOC_API_KEY environment variable
  • Handles framework-specific request/response patterns
  • Provides appropriate error handling
  • The browser client auto-detects your route setup

Manual Setup (Legacy)

If you prefer manual control, you can still use the original approach:

React Integration

Use the <HighlightOverlay /> component to visualize the extracted data on top of your document viewer.

import { createBrowserClient } from '@ninjadoc-ai/sdk';
import { HighlightOverlay } from '@ninjadoc-ai/sdk/react';
import { useState, useEffect } from 'react';
import type { ProcessedDocument } from '@ninjadoc-ai/sdk';

function DocumentViewer({ jobId }: { jobId: string }) {
  const [document, setDocument] = useState<ProcessedDocument | null>(null);

  // Zero configuration - automatically detects your route setup
  const client = createBrowserClient();

  useEffect(() => {
    // The processDocument method polls for job completion and returns
    // the final document with regions, page dimensions, and raw field data.
    client.processDocument(jobId).then(setDocument);
  }, [jobId]);

  if (!document) return <div>Loading...</div>;

  return (
    <div style={{ position: 'relative' }}>
      {/* Your PDF viewer here */}
      <HighlightOverlay
        document={document}
        containerSize={{ width: 800, height: 600 }}
        onRegionClick={(region) => {
          console.log(`Clicked ${region.label}:`, region.value);
          console.log(`AI Answer: ${region.ai_answer}`);
        }}
      />

      {/* Access all field data */}
      {document.regions.map((region, index) => (
        <div key={index}>
          <strong>{region.label}:</strong> {region.ai_answer}
          (Confidence: {region.confidence}%)
        </div>
      ))}
    </div>
  );
}

API Reference

Browser Client (@ninjadoc-ai/sdk)

The browser client is designed to talk to your application's backend (the API handler), not directly to the Ninjadoc AI API. It now features automatic route detection for zero-configuration setup.

createBrowserClient(options)

const client = createBrowserClient({
  baseUrl?: string; // Optional: auto-detects if not provided
  credentials?: RequestCredentials; // default: 'include'
  autoDetectRoutes?: boolean; // default: true - automatically detects route patterns
});

Zero-Configuration Usage:

// Automatically detects route patterns with zero configuration
const client = createBrowserClient();

// Automatically detects:
// - Framework adapter routes (/api/ninjadoc/*)
// - Legacy routes (/api/extract, /api/jobs/*/status)
// - Remembers working pattern for performance

client.extractDocument(file, processorId)

Creates a new extraction job by POSTing to your /api/ninjadoc/extract endpoint.

client.getJobStatus(jobId)

Gets the status of a job by GETting from your /api/ninjadoc/jobs/{jobId}/status endpoint.

client.processDocument(jobId)

A convenience method that polls getJobStatus until the job is complete, then returns the fully processed document, including regions with all field data and page dimensions.

Returns a ProcessedDocument object with:

  • jobId: The job identifier
  • status: Complete job status information
  • regions: All extracted fields with AI answers, confidence scores, coordinates, and references
  • pageDimensions: Page size information for coordinate scaling

client.getRegions(jobStatus)

Transforms a completed job status object into an array of Region objects.

client.findRegion(regions, label)

Finds a specific region by its label from an array of regions.

Server Handler (@ninjadoc-ai/sdk/server)

The server package contains tools for your backend.

createApiHandler(options)

Creates a framework-agnostic request handler that securely proxies calls to the Ninjadoc AI API.

import { createApiHandler } from '@ninjadoc-ai/sdk/server';

const handler = createApiHandler({
  apiKey: string; // Your secret Ninjadoc AI API key
});

// Usage:
// await handler(request, subpath);

createServerClient(options)

If you need more control and want to build your own backend logic without the pre-built handler, you can use the createServerClient directly.

import { createServerClient } from '@ninjadoc-ai/sdk/server';

const serverClient = createServerClient({
  apiKey: string; // Your secret Ninjadoc AI API key
});

// Now you can call methods like serverClient.extractDocument(...)

HighlightOverlay Component

The props for the React component remain the same.

interface HighlightOverlayProps {
  document: ProcessedDocument;
  containerSize: { width: number; height: number };
  onRegionClick?: (region: Region) => void;
  activeRegionId?: string;
}

Framework Adapters API Reference

Remix Adapter

createRemixApiRoute(options?)

Creates a complete Remix API route with loader and action functions.

import { createRemixApiRoute } from '@ninjadoc-ai/sdk/frameworks/remix';

const { loader, action } = createRemixApiRoute({
  apiKey?: string; // Optional: API key (auto-read from env if omitted)
  apiKeyEnv?: string; // Optional: Env var name (default: 'NINJADOC_API_KEY')
  onError?: (error, context) => Response; // Optional: Custom error handler
});

createRemixHandler(options?)

Creates individual loader and action handlers with more control.

import { createRemixHandler } from '@ninjadoc-ai/sdk/frameworks/remix';

const { loader, action } = createRemixHandler(options);

Next.js Adapter

createNextApiRoute(options?)

Creates a Next.js API route handler for all HTTP methods.

import { createNextApiRoute } from '@ninjadoc-ai/sdk/frameworks/next';

const handler = createNextApiRoute({
  apiKey?: string; // Optional: API key (auto-read from env if omitted)
  apiKeyEnv?: string; // Optional: Env var name (default: 'NINJADOC_API_KEY')
  onError?: (error, context) => NextResponse; // Optional: Custom error handler
});

export { handler as GET, handler as POST, handler as PUT, handler as DELETE };

createNextHandler(options?)

Creates a Next.js handler with more control.

import { createNextHandler } from '@ninjadoc-ai/sdk/frameworks/next';

const handler = createNextHandler(options);