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.
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.
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.
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
| Type | Purpose |
|---|---|
| NordicDevhouseOptions | API key, base URL, timeouts, retries, and optional fetch adapter |
| ScrapeInput | URL, formats, webhook URL, metadata, and idempotency key |
| Job | Stable 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 |
| RequestOptions | Timeout, 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.
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.
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
- 1Target Node.js 22 or newer and ship ESM with declaration maps
- 2Accept a fetch-compatible adapter only for testing and supported server runtimes
- 3Reuse one client instead of constructing a client per request
- 4Never log Authorization, webhook secrets, or complete request bodies by default
- 5Expose close() for explicit resource cleanup and make repeated close calls safe