API Reference
brief.md — the one canonical install + endpoint reference. Agents can read the raw markdown at networkr.dev/brief.md. If something here contradicts the brief, the brief wins.networkr install brief — the one rail
For AI agents (Cursor, Claude Code, Continue, Aider, Lovable, Bolt, v0, ChatGPT, any IDE-embedded assistant). 99% of installs are run by you, not a human. Read once, then follow the rail.
The one rule
Run npx networkr install and follow each next_step envelope. Do not invent endpoints. Every endpoint that exists is in this brief — if it's not listed below, it doesn't exist.
Base URL: https://api.networkr.dev — every path below is relative to that. If you self-hosted Networkr (https://github.com/HEIMLANDR/networkr), set NETWORKR_API=http://localhost:3002 (or your URL) and use the same paths.
npm: the 0.2.0 install rail described in this brief is the published @latest — just npx networkr install.
What Networkr is
Fully autonomous content engine that replaces a content team, a social scheduler, an email platform, a press-outreach agency, and an ads manager. One install. Pipes activate as the user grows: SEO blog first (always-on), socials when pre-launch, press drip at launch, paid reach at rank-4-to-1. Same voice, brand, tenant key, backend across everything.
Saves comparable founders 25–65% of build time. That's the value frame. You're not installing a tool, you're installing a team.
Quickstart
npx networkr install # one-shot — audits, picks flavour, activates, mints key, writes .env.local
npx networkr status # read the agent brief any time post-install
If npx isn't available, hit the API rail directly. Same endpoints, same flow.
Auto-flow with npx networkr install
The CLI drives this state machine for you — no manual envelope-by-envelope shuffling required for the offer-* steps. Pass --yes to auto-pick recommended choices, --skip-offers to skip GSC/viralr/outboxr (you can connect them later by hitting GET /api/sites/:id/gsc/oauth-url for GSC, or npx networkr connect for viralr/outboxr/ads OAuth providers). For unattended installs, combine flags:
npx networkr install \
--domain mysite.com --email me@mysite.com \
--flavour technical --author-name "Sam" \
--storage hosted \
--yes \
--skip-offers # baseline only, skip all offer-* envelopes
To pre-pick offers individually (overrides --skip-offers per envelope):
--connect-gsc # auto-pick connect_gsc on offer-gsc, surface OAuth URL
--viralr-mode founder # founder | algo, auto-activate viralr in that mode
--activate-outboxr # auto-activate outboxr
In --json mode the CLI emits one event per line: audit, sample, activated, delivery_configured, offer_gsc_decision, offer_viralr_decision, offer_outboxr_decision, install_done. Stream-parse stdout to drive an agent through the full install without prompts.
Endpoint table — every endpoint that exists
Auth column: none = public, tenant = Authorization: Bearer <api_key>, admin = master key only. Tenant keys are minted at activate-time in the install rail; reuse across sibling sites in the same network.
Install (the rail — drives everything)
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/install | none | Start install. Body { domain, email }. Returns install_token + first next_step envelope. |
| POST | /api/install/:token/step | none | Advance the rail. Body matches the envelope's body_template. Returns next envelope. |
| POST | /api/install/:token/skip | none | Skip the current optional step. Returns next envelope. |
| GET | /api/install/:token/resume | none | Re-fetch the current next_step envelope (token lives 24h). |
| GET | /api/install/:token/fix-plan | none | LLM fix-plan when audit is below threshold. Used inside fix-loop. |
| POST | /api/install/:token/reaudit | none | Re-run the audit after the user applies fixes. Up to 5 per install. |
| GET | /preview/:token | none | Sample article preview page (HTML). Show this URL to the user. |
Sites
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/sites | tenant | Register site directly (rail does this for you in activate). |
| GET | /api/sites | tenant | List sites in the caller's network. |
| GET | /api/sites/:id | tenant | Full site detail — voice, author, network, history, GSC status, last health audit. |
| PUT | /api/sites/:id | tenant | Update fields (cron schedule, build_hook_url, branding, voice_id, author_id, approval_required, etc.). |
| DELETE | /api/sites/:id | tenant | Cascade delete site + content + keywords. |
| GET | /api/sites/:id/agent/brief | tenant | Deterministic 10-item checklist — what's ok / warning / missing, with the exact next API call to fix each. Use this for monitoring. |
Blog
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/sites/:id/blog/generate | tenant | Generate one article now. Body optional { topic?, theme?, angle?, forceAngle? }. |
| POST | /api/sites/:id/blog/start | tenant | Enable cron auto-generation. |
| POST | /api/sites/:id/blog/stop | tenant | Disable cron. |
| GET | /api/sites/:id/blog/history | tenant | Recent pipeline runs for this site. |
| GET | /api/sites/:id/blog/preview | tenant | Dry-run: pick angle without publishing. |
| DELETE | /api/sites/:id/blog/posts/:slug | tenant | Remove a post + cover + registry entry. |
| POST | /api/sites/:id/blog/regenerate/:slug | tenant | Re-generate with new settings. |
| POST | /api/sites/:id/blog/flavour | tenant | Preview generate without publishing. |
GSC (Google Search Console)
Single entry point. No wizard. No /connect route. Hit oauth-url, give the URL to the user.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/sites/:id/gsc/oauth-url | tenant | The starting point. Returns { url } — open it in a browser, OAuth flows, callback persists tokens. Done. |
| GET | /api/sites/:id/gsc/status | tenant | { connected, awaiting_verification, property_url, last_pulled_at, recent_indexed_30d, ... }. |
| POST | /api/sites/:id/gsc/pull | tenant | Inspect a single URL via GSC. Body { url }. |
| GET | /api/gsc/oauth-callback | none | Google's redirect target. Don't call directly. |
Build hook
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/sites/:id/build-hook/test | tenant | Fire the configured hook once to verify wiring. |
| (set via PUT /api/sites/:id) | — | tenant | Set/update build_hook_url field. |
IndexNow
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /{key}.txt | none | Auto-served key verification (Bing/Yandex/Naver/Seznam). Tenant doesn't need to call. |
| GET | /api/indexnow/key | tenant | Get the IndexNow key + setup instructions. |
Public Blog API (no auth — for hosted sites' frontend)
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/blog/:siteId/posts | none | Post list. Query limit, offset, category. |
| GET | /api/blog/:siteId/posts/:slug | none | Single post body. |
| GET | /api/blog/:siteId/covers/:file | none | Cover image (PNG). |
| GET | /api/blog/:siteId/rss.xml | none | RSS feed. |
| GET | /api/blog/:siteId/content-policy | none | Auto-generated transparency policy. |
| GET | /api/blog/:siteId/authors/:slug | none | Author profile JSON. |
Install state machine — cheat sheet (0.2.0)
The install rail is one server-driven loop. Read next_step.id, do what the envelope says, post the result. Below: every step_id, what the envelope expects, what the response gives back.
The 0.2.0 chain is 9 steps: 8 ordered + done. Dropped vs 0.1.x: preview (merged into flavour — sample article returns inline on the same response), offer-ads (Google Ads OAuth not shipped), and tease-minions (waitlist copy moved into done).
| step_id | When it fires | Required body to advance | Returns |
|---|---|---|---|
fix-loop | Audit score below threshold | { choice_id: "get_fix_plan" | "reaudit" | "skip_fix" | "abort" } | New audit OR proceed to flavour |
flavour | Pick voice + author, generate sample (preview merged in) | { step_id: "flavour", flavour, author_name, blog_mode: "production", author_bio?, accent_color?, niche? } | sample_article + preview_url + preview_inline: true — agent shows inline. Re-POST flavour with new value to retry voice. → activate |
activate | Pick storage, create site, mint key, optional approval gate | { step_id: "activate", db_type: "hosted" | "supabase" | ..., db_url?, db_key?, approval_required?: false, approval_window_hours?: 2 } | { site_id, api_key.key } (key shown ONCE — write to .env.local immediately). approval block reports whether the OK-layer was applied (hosted-mode only). |
verify | Confirm install stuck | { step_id: "verify" } | { verified: true, site, sitemap_status, indexnow }. sitemap_status reports whether /sitemap.xml is reachable + an agent_fix_prompt if not. indexnow confirms Networkr auto-pings Bing/Yandex/Naver/Seznam. → configure_blog_delivery |
configure_blog_delivery | Pick how new posts reach the live site | { step_id: "configure_blog_delivery", choice_id: "build_hook" | "embed" | "defer" | "rewrite" | "cms_push" | "gh_actions", build_hook_url? } | → offer-gsc |
offer-gsc | Optional GSC connect | { choice_id: "connect_gsc" | "skip_gsc" }. If connect: agent first GETs /api/sites/:id/gsc/oauth-url, opens the URL for the user, then POSTs the choice. | → offer-viralr |
offer-viralr | Optional socials pipe | { choice_id: "activate_viralr_founder" | "activate_viralr_algo" | "skip_viralr" }. Activation api_call returns connect_url for completing OAuth via npx networkr connect. | → offer-outboxr |
offer-outboxr | Optional email/press pipe | { choice_id: "activate_outboxr" | "skip_outboxr" }. Same connect-url pattern as viralr. | → done |
done | Install complete | — | { done: true, site_id, api_key_prefix, save_to_env, verify_command, digest_opt_out_url, user_copy }. The user_copy carries the Minions waitlist tease + weekly-digest opt-out hint. |
When done: true, save to .env.local:
NETWORKR_API=https://api.networkr.dev
NETWORKR_SITE_ID=<from activate response>
NETWORKR_KEY=<api_key.key from activate response — shown ONCE>
GSC quickstart
GET /api/sites/:id/gsc/oauth-url ← THE start. Returns { url }.
GET /api/sites/:id/gsc/status ← Check connected state.
POST /api/sites/:id/gsc/pull ← Inspect one URL.
That's it. No /connect, no /auth-url, no wizard. Open the returned url in the user's browser, the callback persists tokens, you're done.
There is no npx networkr gsc subcommand — drive it via the API call above.
Build hook quickstart
The build hook is how new articles reach a static frontend. Networkr POSTs to it on every publish. Works with Netlify, Vercel, Cloudflare Pages, GitHub Actions repository_dispatch, Render, Railway, Fly.
npx networkr build-hook set <url> # save it
npx networkr build-hook test # fire once + report
API equivalents: PUT /api/sites/:id { build_hook_url } to set, POST /api/sites/:id/build-hook/test to verify.
Hidden features — Auto / Background
Already running for this tenant. Query if needed; do not try to "configure" them.
- SEO Brain — discovers topic queue weekly, feeds the pipeline. Status:
GET /api/seo/brain/status. Trigger one site:POST /api/seo/brain/trigger { site_id }. - Keyword rank tracker — auto-checks weekly. Read:
GET /api/seo/keywords/:siteId. Add:POST /api/seo/keywords { site_id, keywords[] }. - Orchestrator — daily self-monitoring per network. Latest report:
GET /api/orchestrator/latest. History:GET /api/orchestrator/history. - Content registry — index of every article across the network. Read:
GET /api/registry?site_id=<id>. Search:GET /api/registry/search?tags=...&q=.... Cross-link suggestions:GET /api/registry/links/:siteId?tags=.... - Site health audits — daily uptime/sitemap/robots/meta checks. Read:
GET /api/health/sites/:siteId. Trigger:POST /api/health/sites/:siteId/audit. - Weekly digest email — Mondays 08:00 Stockholm via Mailjet, per network.
- OK-layer (per-article approval) — opt-in via
PUT /api/sites/:id { approval_required: 1, approval_window_hours: 2 }. Hosted-mode only.
Most of the time you don't need any of this — surface it only if the user asks "how do I see X" or the agent brief flags a missing/warning item.
DO NOT
- Don't invent endpoints. If it's not in the table above, it doesn't exist. Don't guess
/api/sites/:id/integrations,/api/sites/:id/gsc/connect,/api/sites/:id/gsc/auth-url— none of those exist. Use what's listed. - Don't manually edit articles in the user's DB. Posts must go through the pipeline. To change a post:
DELETE /api/sites/:id/blog/posts/:slugthenPOST /api/sites/:id/blog/regenerate/:slugorPOST /api/sites/:id/blog/generate. - Don't use
npx networkr connectfor GSC. That command is for outboxr/viralr/ads OAuth providers (Mailjet, LinkedIn, Google Ads, etc.). GSC has its own dedicated flow:GET /api/sites/:id/gsc/oauth-url(no CLI subcommand exists). - Don't push to npm or modify deployed services without user permission. No
npm publish, nogit push --force, nonetlify deploy --prod, no production migrations. The user runs deploys. - Don't fabricate secrets. If you can't find DB creds in
.env.local, prompt the user. Do not invent values to make a request succeed. - Don't loop on
429. Wait 60s and retry once. If still 429, surface the error.
CLI shortcuts (every rail step has one)
npx networkr install # full rail, --json for stream events
npx networkr status # agent brief checklist
npx networkr build-hook set/test/clear # build hook lifecycle
npx networkr connect # OAuth menu for outboxr/viralr/ads providers
npx networkr outboxr accounts/send/... # outboxr ops
# GSC: no dedicated subcommand — call GET /api/sites/:id/gsc/oauth-url directly
CLI flags: --yes skips confirms, --json emits one event per line for stream parsing, --site <id> selects site for multi-site tenants. Falls back to API rail if npx not available.
Hosted mode — render the blog
For hosted sites (no backend), the frontend fetches from:
GET /api/blog/<site_id>/posts?limit=20
GET /api/blog/<site_id>/posts/<slug>
GET /api/blog/<site_id>/covers/<file>
GET /api/blog/<site_id>/rss.xml
GET /api/blog/<site_id>/content-policy
GET /api/blog/<site_id>/authors/<slug>
Reference Next.js implementation: https://github.com/HEIMLANDR/networkr/tree/main/frontend/src/app/blog. Adapt for whatever the user's on (Next / Astro / Hugo / 11ty / SvelteKit / plain HTML).
Error contract
400— missing / invalid body field. Readerror.401— missing or invalidAuthorizationheader.403— admin-only endpoint hit with tenant key, or activation rejected.404— wrong scope, missing site, or invalid token.409— site already registered for that domain.410— install token expired; restart withPOST /api/install.429— rate-limited; wait 60s, retry once.5xx— backend issue; retry once with exponential backoff.
Reactivation — when new features ship
Networkr may email the user later: "Minions v1 just shipped — resume your install." That link reopens the rail at a new step offering the new feature. Same envelopes — the user doesn't learn anything new, they accept or skip.
Final message to the user (when done: true)
- Site
<domain>is registered as<site_id>. - Tenant key saved in
.env.local. It's their auth going forward. - Sample article already published.
- First pipeline article generates within minutes.
- Daily cadence starts tomorrow (default 06:00 Europe/Stockholm).
- Mention any pipes activated + what OOB auth still needs (one connect email covers all).
- Mention the Minions waitlist if they joined — tease Q3.
Further reading
- API reference: https://networkr.dev/docs
- How it works: https://networkr.dev/how-it-works
- Content policy: https://networkr.dev/content-policy
- Standards: https://networkr.dev/standards
Last updated: 2026-06-06. Source: frontend/public/brief.md. Also available as raw markdown at /brief.md.