One dependency wires a Next.js site to the engine.
Pull finished articles, serve robots.txt, sitemap.xml, rss.xml and llms.txt, source the engine-managed <head>, host the IndexNow key, and receive publish webhooks, mostly one line per feature.
Scaffold by selecting features.
It writes only new files (client, the routes you pick, and middleware), adds env keys, and prints the two snippets it won't overwrite.
npm i @itmaster/sdk npx @itmaster/sdk init # interactive (y/n per feature)# or non-interactive:npx @itmaster/sdk init \ --site <PUBLISH_SITE> --engine https://itmaster.uk \ --features robots,sitemap,rss,llms,indexnow,webhook --yesEnv, then one shared client.
Register the site engine-side, which issues a pull key, set the environment variables, then create the shared client. No pull key just means every call returns null and the site still renders.
ITMASTER_API_URL=https://itmaster.uk
PUBLISH_SITE=<your TargetSite id>
PUBLISH_PULL_KEY=<per-site key>import { createClient } from "@itmaster/sdk";
export const itmaster = createClient({
baseUrl: process.env.ITMASTER_API_URL!,
site: process.env.PUBLISH_SITE!,
pullKey: process.env.PUBLISH_PULL_KEY ?? "",
// Seconds to cache engine reads. Set this. Without it the client sends
// `no-store`, which opts every calling route out of static rendering —
// an ISR page that reads the feed then fails at runtime instead of
// serving. Takedowns still propagate instantly via the push webhook.
cache: 300,
});Six wires, each a re-export.
What each piece is, and where it lands in your app.
robots.txt / sitemap.xml / rss.xml / llms.txt
create*Route(itmaster)IndexNow key
createIndexNowKeyRoute(PUBLISH_SITE)engine-managed <head>
applyMeta + headTagsFromConfigarticle metadata + JSON-LD
articleMetadata / articleJsonLdpublish to live in seconds
createWebhookRoutewrite-back (CMS sites)
createProviderRoutes
Every route is a single re-export.
Derived feeds are a single re-export:
import { createRobotsRoute } from "@itmaster/sdk/next";
import { itmaster } from "@/lib/itmaster";
export const GET = createRobotsRoute(itmaster);IndexNow derives the exact key the engine submits, no secret, no round trip:
// app/api/indexnow-key/route.ts
import { createIndexNowKeyRoute } from "@itmaster/sdk/next";
export const GET = createIndexNowKeyRoute(process.env.PUBLISH_SITE ?? "your-site");
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export function middleware(req: NextRequest) {
if (/^\/[a-f0-9]{32}\.txt$/.test(req.nextUrl.pathname))
return NextResponse.rewrite(new URL("/api/indexnow-key", req.url));
return NextResponse.next();
}
export const config = { matcher: ["/((?!_next/|favicon.ico).*)"] };Engine-managed head, verification, OG and favicon via the Metadata API, the only path that reaches <head> in the App Router:
import { applyMeta } from "@itmaster/sdk/next";
import { itmaster } from "@/lib/itmaster";
import { pageMetadata } from "@/lib/page-seo";
const base = { /* your defaults */ };
export async function generateMetadata(): Promise<Metadata> {
const config = await itmaster.config().catch(() => null);
return pageMetadata("/docs", config ? applyMeta(base, config) : base);
}One call verifies, submits, and indexes.
Once the head and IndexNow routes are live, one engine call verifies the site in Search Console, submits the sitemap, and turns on IndexNow change notifications.
Full reference, provider mode and the mirror feed are in the README# Create a key: dashboard → API & AI accesscurl -X POST "https://itmaster.uk/api/mcp" \ -H "Authorization: Bearer itm_live_..." \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"get_account_status","arguments":{}}}'Questions people ask
Do I have to use the SDK?
No. The SDK is the shortest path on a Next.js site, but the engine is a plain HTTP service: you can pull finished articles from a read-only REST feed with a per-site key, or receive them on an HMAC-signed webhook, in any language. WordPress sites use the plugin and write no code at all.
What does the SDK actually do for me?
It wires six things that are tedious to get right individually: the article feed and one-article fetch, robots.txt, sitemap and RSS routes, an llms.txt route, the engine-managed head (verification tags and analytics), the IndexNow key route, and the signed webhook receiver. Each is a thin re-export, so you can adopt one and ignore the rest.
How do takedowns reach my site?
A taken-down article becomes a tombstone in the feed with status “unpublished”. A pull consumer sees it on its next poll and removes the page; a push consumer is notified immediately. That is why a mirror should read the status field rather than assuming everything in the feed is live.
How often should I poll the feed?
Cache engine reads for a few minutes rather than fetching per request. Pass a cache window to the client, never “no-store”, because an uncached read opts your whole route out of static rendering. Takedowns and new articles still arrive instantly if you wire the push webhook, which calls your revalidation.
Is the pull key safe to ship to the browser?
No. It is a server-side credential scoped to one site, and it should stay in an environment variable read only on the server. The SDK client is server-only for that reason.