Developers

How to read Necto Consulting as a machine and publish to it: the APIs, errors, limits and versions. Reading is open to anyone; publishing needs a token.

Quickstart

Read a page as markdown, list the endpoints, search the articles, and check an article without writing it:

curl -H "Accept: text/markdown" https://necto-consulting.pages.dev/
curl https://necto-consulting.pages.dev/api/
curl -X POST https://necto-consulting.pages.dev/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_articles","arguments":{"query":"<your question>"}}}'
curl -X POST "https://necto-consulting.pages.dev/api/content/?dry_run=1" -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"slug":"a-test","title":"A test","body":"<p>Text</p>","rubric":"<a category>"}'

Public interfaces

WhatWhere
Markdown of any pageGET any page with Accept: text/markdown
llms.txthttps://necto-consulting.pages.dev/llms.txt
Sitemaphttps://necto-consulting.pages.dev/sitemap.xml
RSS and JSON Feed, full texthttps://necto-consulting.pages.dev/feed.xml
MCP server (read-only tools; MCP 2026-07-28 and 2025-06-18)POST https://necto-consulting.pages.dev/mcp, card: server-card.json
API catalog (RFC 9727)/.well-known/api-catalog
OpenAPI 3.1https://necto-consulting.pages.dev/openapi.json
ARD catalog/.well-known/ai-catalog.json
Agent skills/.well-known/agent-skills/index.json
How agents authenticate/.well-known/auth.md

Content API

JSON over HTTPS. A success answers { "status": "ok", "version": ... }; GET /api/ returns this table as JSON, and openapi.json describes every request and answer.

MethodPathAuthWhat it does
GET/api/noneThis list: every endpoint with its method, path and authentication, and where the docs are.
GET/api/healthnoneLiveness for agents and uptime monitors. No dependency is probed.
GET/api/content/versionnoneThe API version and what the article template renders (the VISIBILIO handshake).
POST/api/content/Bearer tokenCreate an article. With dry_run it is validated and nothing is written; with Idempotency-Key a retry returns the first answer.
GET/api/content/{slug}noneOne published article. A draft answers 404.
PUT/api/content/{slug}Bearer tokenUpdate an article: only the fields the payload carries change. With dry_run it is validated and merged, and nothing is written.
DELETE/api/content/{slug}Bearer tokenRemove an article and its images.
GET/api/content/catalogBearer tokenCategories, tags and every published article (Visibilio Connect), the articles a page at a time: follow next_cursor until it is null (the Link header names the same next page).
GET/api/content/tagsBearer tokenThe tags of the published articles, as the catalog lists them (Visibilio Connect).
POST/api/content/imagesBearer tokenUpload one image (multipart/form-data: file, slug, variant; at most 10 MB) into the site's own storage; the answer names its URL. With dry_run it is checked and nothing is written.
POST/api/content/catalogBearer tokenRebuild the article lists and counts from the stored articles after parallel writes: a dry run answering each change (changes[]) and the catalog it leaves; ?apply=1 writes them.
POST/mcpnoneMCP server, JSON-RPC 2.0 over POST: read-only tools (tools/list names them). MCP 2026-07-28, each request on its own (params._meta and the MCP-Protocol-Version, Mcp-Method and Mcp-Name headers; server/discover lists the versions), and MCP 2025-06-18 (initialize first).

Keys and the sandbox

Tokens are issued by a person, not by an endpoint: write to info@necto-consulting.com with your organisation, what you are building, the expected volume and whether you need to read or to write. There is no self-service registration.

There is no separate test environment. dry_run is the only sandbox: send ?dry_run=1 or "dry_run": true with a create or an update, and the whole payload is validated and the answer says what would be created, or what the article would become, while nothing is written.

A create, an update or a dry run that succeeds may also carry warnings: what the article misses of the body contract that makes a page citable (an answer in its first 60 words, absolute dates instead of "recently", a source for every superlative, sections that read on their own, three questions a client would ask). They are advice: the answer stays 200. A body longer than 100000 characters is stored without the check, and one warning, unchecked, says so.

Errors

Every /api/* error has one shape; errors[] appears when there are several problems. OAuth answers its own RFC 6749 errors and JSON-RPC answers inside its envelope.

{
  "status": "error",
  "code": "validation_failed",
  "message": "The payload failed validation.",
  "hint": "errors[] names each field and what it needs; fix them all and send again.",
  "docs": "https://necto-consulting.pages.dev/developers/#error-validation_failed",
  "errors": [
    {
      "field": "title",
      "message": "required"
    }
  ]
}
CodeStatusMeaningWhat to do
bad_request400The request is malformed.Check the method, the path and the headers against GET /api/.
invalid_json400The body is not valid JSON.Send a JSON object with Content-Type: application/json.
validation_failed400The payload failed validation.errors[] names each field and what it needs; fix them all and send again.
unsupported_version400This API version is not served.Send X-Content-API-Version: 1, or leave the header out.
unauthorized401A valid token is required.Send Authorization: Bearer <token>. Tokens are issued by a person: see /.well-known/auth.md.
forbidden403This request is not allowed.The token or the origin is not allowed to do this.
not_found404Nothing here.GET /api/ lists every endpoint; a draft article answers 404 in public.
method_not_allowed405This path does not accept this method.The Allow header lists the methods it accepts.
conflict409The resource already exists.An article with this slug exists: update it with PUT /api/content/{slug}.
idempotency_in_progress409A request with this Idempotency-Key is still being processed.Wait the Retry-After seconds and send the same request again.
payload_too_large413The body is too large.An article with its images must stay under 12 MB.
idempotency_key_reused422This Idempotency-Key was used with a different body.Use a new key for a new request; a retry sends the same body with the same key.
rate_limited429Too many requests.Wait the Retry-After seconds; the RateLimit headers show the policy.
internal_error500The server failed.Retry the same request later. A write cut short may be half done: a create answers its retry with 409 and lists the stored article then; GET /api/content/{slug} shows what is stored.
bad_gateway502An upstream service failed.Retry later.
unavailable503The service is not available.Retry later.

Limits

Per client address, in a fixed window. Every answer of a limited endpoint carries RateLimit-Policy and RateLimit (draft-ietf-httpapi-ratelimit-headers) and X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix seconds); a refused request answers 429 with Retry-After in seconds.

PolicyApplies toRequestsWindow
contentPOST, PUT and DELETE under /api/content/3060 s
mcpPOST /mcp12060 s

An article with its images must stay under 12 MB.

Retrying a create safely

Send Idempotency-Key: <a unique value> with POST /api/content/ (draft-ietf-httpapi-idempotency-key-header). The same key with the same body returns the first answer for 24 hours, marked Idempotent-Replayed: true; the same key with another body answers 422 idempotency_key_reused; a request still running answers 409 with Retry-After. A 5xx or a 429 is not stored, so its retry runs again, and a dry run is never stored.

Versions and deprecation

This is version 1.1.0 of the Content API; every answer says so in X-Content-API-Version. Send X-Content-API-Version: 1 to lock the major version: a request for another one answers 400 unsupported_version before anything runs. A breaking change gets a new major version. Before an endpoint is removed it carries Deprecation and Sunset headers for at least 90 days, and it is listed here.

No endpoint is deprecated.