iato-sdk
v1.3.0
Published
Official TypeScript SDK for the IATO API — website crawling, content governance, and AI-powered information architecture.
Maintainers
Readme
iato-sdk
Official TypeScript SDK for the IATO API — website crawling, content governance, and AI-powered information architecture.
- Zero dependencies — uses native
fetch(Node 18+) - Fully typed — every endpoint, param, and response has TypeScript types
- Retries & timeouts — exponential backoff on 5xx and 429, configurable limits
- Tree-shakeable — ESM + CJS dual output
Install
npm install iato-sdkQuick Start
import { IATO } from 'iato-sdk';
const iato = new IATO({ apiKey: process.env.IATO_API_KEY! });
// Start a crawl
const job = await iato.crawls.start({
url: 'https://example.com',
workspace_id: 'ws_abc123',
max_pages: 500,
});
// Wait for completion (polls every 5s)
const completed = await iato.crawls.waitForCompletion(job.id);
// Analyze results
const stats = await iato.crawls.stats(completed.id);
const issues = await iato.crawls.seoIssues(completed.id);
const broken = await iato.crawls.brokenLinks(completed.id);
console.log(`Crawled ${stats.total_pages} pages, found ${issues.issues.length} SEO issues`);Configuration
const iato = new IATO({
apiKey: 'your-api-key', // Required
baseUrl: 'https://iato.ai', // Default
timeout: 30000, // 30s default
maxRetries: 2, // Retries on 5xx/429
retryDelay: 1000, // Base delay (exponential backoff)
});Resources
Workspaces
const { workspaces } = await iato.workspaces.list();
const ws = await iato.workspaces.create({ name: 'My Project' });
await iato.workspaces.update(ws.id, { name: 'Renamed' });
const { members } = await iato.workspaces.members(ws.id);
await iato.workspaces.invite(ws.id, { email: '[email protected]', role: 'editor' });
await iato.workspaces.delete(ws.id);Crawls
// Start with full options
const job = await iato.crawls.start({
url: 'https://example.com',
workspace_id: 'ws_123',
max_pages: 5000,
max_depth: 10,
js_rendering: true,
js_wait_time: 3000,
include_screenshots: true,
respect_robots: true,
custom_headers: { 'Accept-Language': 'en-US' },
excluded_paths: ['/admin/*', '/wp-json/*'],
});
// Monitor
const status = await iato.crawls.get(job.id);
console.log(`${status.pages_crawled}/${status.pages_total} pages`);
// Wait and get results
const done = await iato.crawls.waitForCompletion(job.id, 3000, 300_000);
// Pages with filtering
const { pages } = await iato.crawls.pages(done.id, { limit: 100, status_code: 200 });
// Full analysis suite
const stats = await iato.crawls.stats(done.id);
const broken = await iato.crawls.brokenLinks(done.id);
const redirects = await iato.crawls.redirects(done.id);
const duplicates = await iato.crawls.duplicates(done.id);
const seo = await iato.crawls.seoIssues(done.id);
const perf = await iato.crawls.performance(done.id);
const resources = await iato.crawls.resources(done.id);
const structured = await iato.crawls.structuredData(done.id);
// Compare two crawls
const diff = await iato.crawls.compare('job_old', 'job_new');
console.log(`+${diff.summary.added} -${diff.summary.removed} ~${diff.summary.changed}`);
// Export
const csv = await iato.crawls.exportCsv(done.id);
const xml = await iato.crawls.exportSitemap(done.id);Sitemaps & AI Assistant
// Create from crawl
const sitemap = await iato.sitemaps.create({ job_id: job.id, name: 'Current IA' });
// Manage nodes
const { nodes } = await iato.sitemaps.nodes(sitemap.id);
const node = await iato.sitemaps.createNode(sitemap.id, {
title: 'New Section',
type: 'section',
parent_id: nodes[0].id,
});
await iato.sitemaps.updateNode(sitemap.id, node.id, { title: 'Renamed Section' });
// AI Chat — restructure via natural language
const chat = await iato.sitemaps.chat(sitemap.id, {
message: 'Move all blog posts under a /blog/2025/ section',
});
console.log(chat.response);
// If AI generated a plan, review and execute
if (chat.plan) {
const plan = await iato.sitemaps.plan(sitemap.id, chat.plan.id);
console.log(`Plan: ${plan.description}, ${plan.operations.length} operations`);
await iato.sitemaps.executePlan(sitemap.id, plan.id);
// Or: await iato.sitemaps.rejectPlan(sitemap.id, plan.id);
// Undo if needed: await iato.sitemaps.undoPlan(sitemap.id, plan.id);
}
// Quick AI actions
const analysis = await iato.sitemaps.analyze(sitemap.id);
const suggestions = await iato.sitemaps.suggestStructure(sitemap.id);Content Inventory
const { items, total } = await iato.inventory.list(job.id, { limit: 50 });
const invStats = await iato.inventory.stats(job.id);
console.log(`${invStats.total_pages} pages, avg ${invStats.avg_word_count} words`);Navigation
const navStats = await iato.navigation.stats(job.id);
const { menus } = await iato.navigation.detect(job.id);
const validation = await iato.navigation.validate(job.id);Taxonomy Builder
The 5-phase AI taxonomy workflow:
// Phase 1: Extract terms from content
const extracted = await iato.taxonomy.extractTerms(job.id);
await iato.taxonomy.importExtracted(job.id, { terms: extracted.terms });
// Phase 2: AI suggests hierarchy
const { hierarchy } = await iato.taxonomy.suggestHierarchy(job.id);
// Adjust if needed
await iato.taxonomy.setParent(job.id, { term_id: 't1', parent_id: 't2' });
// Phase 3: Auto-classify pages
const { classifications } = await iato.taxonomy.autoClassify(job.id);
// Phase 4: Review
const pending = await iato.taxonomy.pendingClassifications(job.id);
await iato.taxonomy.bulkReview(job.id, {
reviews: pending.classifications.map(c => ({
page_url: c.page_url,
term_id: c.term_id,
action: c.confidence > 0.8 ? 'approve' : 'reject',
})),
});
// Phase 5: Export
const json = await iato.taxonomy.exportJson(job.id);
const csv = await iato.taxonomy.exportCsv(job.id);
const skos = await iato.taxonomy.exportSkos(job.id);Schedules
const schedule = await iato.schedules.create({
name: 'Weekly audit',
url: 'https://example.com',
frequency: 'weekly',
schedule_time: '06:00',
workspace_id: 'ws_123',
});
// Trigger manually
const { job_id } = await iato.schedules.run(schedule.id);Webhooks
const hook = await iato.webhooks.create({
url: 'https://hooks.slack.com/services/xxx',
events: ['crawl.completed', 'crawl.failed', 'changes.detected'],
secret: 'whsec_my_secret',
});
await iato.webhooks.test(hook.id);
// In your webhook handler:
const isValid = await iato.webhooks.verifySignature(
rawBody,
req.headers['x-iato-signature'],
'whsec_my_secret'
);Reports
const report = await iato.reports.generate({ job_id: job.id, type: 'full' });
const pdf = await iato.reports.download(report.id);Authentication & User
const { user } = await iato.auth.me();
const quota = await iato.users.quota();
// Manage API keys
const newKey = await iato.auth.createApiKey({ name: 'CI Pipeline' });
console.log(`Key: ${newKey.key}`); // Only shown onceOrganization
const { users } = await iato.org.members();
await iato.org.invite({ email: '[email protected]', role: 'member' });
const { invitations } = await iato.org.invitations();Health
const status = await iato.health.check();
const detailed = await iato.health.detailed();
const manifest = await iato.health.manifest();AEO (Answer Engine Optimization)
// Healthcheck against an AEO tab (overview | access | files | content | grounding | visibility)
const tab = await iato.aeo.healthz('access', { workspace_id: 17 });
// → { ok: true, feature_flag: true | false }
// Returns 403 when the tab is disabled for the workspace.
// Tab 1 Overview — per-face per-layer sub-scores (Google AI Search readiness
// + Other AI Engines readiness). crawlId is the UUID `crawl_jobs.job_id`.
const scores = await iato.aeo.subScores('a5fb7698-2c4d-4e6f-8a9b-1c2d3e4f5a6b');
// → { success, data: { crawl_id, workspace_id, google: { total, by_layer, measurable_layers }, other: {...} } }
// Tab 1 Overview — top-5 prioritized recommendations for the crawl.
// Each rec carries `applies_to` engine-face attribution.
const recs = await iato.aeo.priorities('a5fb7698-2c4d-4e6f-8a9b-1c2d3e4f5a6b');
// → { success, data: { crawl_id, workspace_id, recommendations: AEORecommendation[] } }
// Tab 1 Overview — score trend over a backward time window. `params.days`
// defaults 30, max 365 (out-of-range returns 400 `invalid_window`).
const trend = await iato.aeo.trend('a5fb7698-2c4d-4e6f-8a9b-1c2d3e4f5a6b', { days: 30 });
// → { success, data: { crawl_id, workspace_id, window_days, google: AEOTrendPoint[], other: AEOTrendPoint[] } }
// Dual `crawl_id`: top-level `data.crawl_id` is the URL crawl; each point's
// `crawl_id` is the score-producing crawl (typically a different value).Tab 1 Overview ships (M2): subScores, priorities, and trend return live data for crawls in workspaces with the aeo.overview feature flag enabled. Through M2 the IssueType producers are stubbed, so the three methods reflect the absence of analysis (sub-scores at 100, recommendations empty, trend flat at 100); real variation lands as M3+ producers populate seo_issues. Further tabs (access, files, content, grounding, visibility) ship in M3+; their healthchecks gate against per-workspace tab flags today.
Error Handling
All errors extend IATOError with typed subclasses:
import { IATO, AuthenticationError, NotFoundError, RateLimitError, ValidationError } from 'iato-sdk';
try {
await iato.crawls.get('nonexistent');
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Job not found');
} else if (error instanceof AuthenticationError) {
console.log('Bad API key');
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof ValidationError) {
console.log('Invalid params:', error.details);
}
}The SDK automatically retries on 5xx errors and 429s with exponential backoff. Configure via maxRetries and retryDelay.
Advanced
Request Options
Every method accepts an optional RequestOptions parameter:
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
const stats = await iato.crawls.stats(jobId, {
timeout: 10000,
signal: controller.signal,
headers: { 'X-Request-Id': 'req_123' },
});Custom HTTP Client
For testing or advanced use, compose resources with a custom HttpClient:
import { HttpClient, Crawls } from 'iato-sdk';
const http = new HttpClient({ apiKey: 'test', baseUrl: 'http://localhost:8000' });
const crawls = new Crawls(http);Binary Downloads
Export methods that return files give you an ArrayBuffer:
import { writeFile } from 'fs/promises';
const csv = await iato.crawls.exportCsv(jobId);
await writeFile('export.csv', Buffer.from(csv));
const skos = await iato.taxonomy.exportSkos(jobId);
await writeFile('taxonomy.rdf', Buffer.from(skos));Requirements
- Node.js 18+ (uses native
fetch) - An IATO API key (get one free)
License
MIT
