Skip to documentation content

TypeScript SDK

A typed, server-side client for Node.js applications.

In this guide
  1. 1Create a reusable client
  2. 2Run or start jobs
  3. 3Handle typed errors
  4. 4Verify webhooks
In this guide
  1. 1Create a reusable client
  2. 2Run or start jobs
  3. 3Handle typed errors
  4. 4Verify webhooks

Package contract

The generated source distribution is @nordicdevhouse/sdk. It is a server-side TypeScript client; browser use is deliberately unsupported because an API key must never cross the server seam.

Create one reusable client

Create the client at application startup and reuse its connection pool. Configuration is immutable after construction. Per-call overrides may shorten a timeout or reduce retries, but cannot silently weaken authentication.

TypeScript
import { NordicDevhouse } from '@nordicdevhouse/sdk';

const ndh = new NordicDevhouse({
  apiKey: process.env.NORDIC_DEVHOUSE_API_KEY!,
  timeoutMs: 30_000,
  maxRetries: 3
});

Run a scrape to completion

Use scrape.run for the default workflow. It creates an idempotent job, follows the job until it reaches a terminal state, and returns a typed result. The SDK preserves the job and request identifiers for logs and tracing.

TypeScript
const result = await ndh.scrape.run({
  url: 'https://example.com/products',
  formats: ['json'],
  idempotencyKey: 'catalog-2026-08-11'
});

console.log(result.jobId, result.records, result.data);

Control an asynchronous job

Use start when the request lifecycle must not wait for extraction. Persist the returned job ID. wait can resume after a process restart and accepts an AbortSignal so shutdown and user cancellation do not leak background work.

TypeScript
const job = await ndh.scrape.start({
  url: 'https://example.com/products',
  formats: ['json']
});

const result = await ndh.jobs.wait(job.id, {
  timeoutMs: 10 * 60_000,
  signal: abortController.signal
});

Public types

TypePurpose
NordicDevhouseOptionsAPI key, base URL, timeouts, retries, and optional fetch adapter
ScrapeInputURL, formats, webhook URL, metadata, and idempotency key
JobStable ID, state, timestamps, progress, and warnings
JobResult<T>Completed job metadata and typed data payload
WebhookEvent<T>Verified event ID, type, timestamp, and typed data
RequestOptionsTimeout, retry budget, cancellation signal, and extra request metadata

Handle typed errors

All failures extend NordicDevhouseError and expose code, message, requestId, status, attempts, and cause when available. Only catch a narrower type when the application can take a specific recovery action.

TypeScript
import {
  NordicDevhouseError,
  RateLimitError,
  ValidationError
} from '@nordicdevhouse/sdk';

try {
  await ndh.scrape.run({ url, formats: ['json'] });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error(error.retryAfterMs, error.requestId);
  } else if (error instanceof ValidationError) {
    console.error(error.issues);
  } else if (error instanceof NordicDevhouseError) {
    console.error(error.code, error.requestId);
  }
}

Verify webhooks from raw bytes

Pass the unparsed request body to verify. The helper validates HMAC-SHA256, enforces a five-minute timestamp tolerance, and returns a typed event only after verification. JSON parsed and serialized again is not equivalent to the signed payload. Persist the verified event ID to prevent duplicate processing; signature verification alone does not store replay state.

TypeScript
const event = ndh.webhooks.verify({
  payload: rawRequestBody,
  signature: request.headers.get('Nordic-Signature'),
  secret: process.env.NORDIC_WEBHOOK_SECRET!
});

if (event.type === 'scrape.completed') {
  await importResult(event.data.jobId);
}

Runtime and lifecycle rules

  1. 1
    Target Node.js 22 or newer and ship ESM with declaration maps
  2. 2
    Accept a fetch-compatible adapter only for testing and supported server runtimes
  3. 3
    Reuse one client instead of constructing a client per request
  4. 4
    Never log Authorization, webhook secrets, or complete request bodies by default
  5. 5
    Expose close() for explicit resource cleanup and make repeated close calls safe
Was this page helpful?