Automation and API
If you want scripts, scheduled jobs, or agents to operate your own Jant site, this is the entry point. By the end you should know how to issue a token, which endpoints to call, and how to debug failures.
Jant provides two channels:
- HTTP JSON API: general-purpose, works with curl.
- MCP interface (
/api/mcp): for agents that already speak the tool-calling protocol.
For full field definitions and request bodies, see the API Reference.
A project created with create-jant also has AGENTS.md, which points an agent at the running site's /skill.md, at npx jant --help, and at these docs, and examples/agent-content-automation/README.md with ready-to-run requests.
Which path first
- Scripts, scheduled jobs, external integrations: use the HTTP API.
- The caller is itself an MCP client: use MCP.
- An AI assistant working with one site: hand it that site's
/skill.mdURL (for example,https://example.com/skill.md), a site-bound guide to reading, publishing, organizing, and migrating content through HTTP or MCP. To move an old blog in, see Export and import.
Default to HTTP. MCP only beats it when the caller already speaks the tool-calling protocol.
Local CLI
Setting up, deploying, moving, and backing up a site stay on the CLI: setup, migrate, deploy, reset-password, site export, site import, site snapshot, db export, and so on. site export and site import call the site's API with an API token; the rest read and write the database directly. See Command line.
Content automation (publishing posts, uploading media, updating settings) goes through HTTP or MCP.
HTTP API
Issuing a token
- Sign in to the site and open Settings → API Tokens.
- Click New Token and give it a recognizable name — that's how you identify it later when revoking.
- Copy the string that starts with
jnt_. It's shown only once — if you lose it, issue a new one.
To revoke, delete the row on the same page; revocation takes effect immediately. Today every token is site-scoped with full read/write — no scopes, no expiry. Both may show up later; this page will be updated when they do.
For local development, DEV_API_TOKEN from packages/core/.dev.vars works the same way.
Authentication
Send the header:
Authorization: Bearer jnt_...
A few public read endpoints don't need a token by default: GET /api/public/threads, GET /api/public/threads/:slug, GET /api/public/threads/:slug/posts, and GET /api/public/posts/:slug. When PUBLIC_API_ENABLED=false, /api/public/* returns 404 to every caller. Public HTML pages, including /search, remain available.
Common endpoints
| Endpoint | Methods | Purpose |
|---|---|---|
/api/posts |
GET / POST / PUT / DELETE | List, read, create, update, delete posts |
/api/threads |
GET | List Threads, read one, and page through its posts, drafts and private Threads included |
/api/public/threads |
GET | Public read of Threads — the homepage's list by default, with the archive's filters (no token) |
/api/public/posts |
GET | Public read of one published post by slug (no token). Lists of posts are Thread lists: /api/public/threads |
/api/upload |
POST | One-shot multipart upload, single file per call — preferred for scripts |
/api/media |
GET / PUT / DELETE | List, read, update the alt text of, and delete uploaded files; give a video its poster |
/api/uploads |
POST → PUT → POST | Multipart upload session — for large files or unstable networks |
/api/attachments |
GET | Fetch raw attachment content by id |
/api/collections |
GET / POST / PUT / DELETE | Collections |
/api/smart-collections |
GET / POST / PUT / DELETE | Smart collections — collections whose members come from conditions |
/api/settings |
GET / PUT | Site settings |
/api/search |
GET | Full-text search of published posts, private ones included |
/api/mcp |
POST | MCP JSON-RPC (initialize / tools/list, etc.) |
/api/upload and /api/uploads differ by a single s but mean different things — the first is a one-shot single-file multipart upload, the second is a three-step init/part/complete session. Default to /api/upload; reach for /api/uploads only when files are large or the connection is unreliable.
Minimal example: post a note
curl -X POST "$JANT_URL/api/posts" \
-H "Authorization: Bearer $JANT_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"format": "note",
"bodyMarkdown": "Hello from curl."
}'
examples/agent-content-automation/ has a quote post and a settings update to start from. Every field, including collectionIds, publishedAt, slug, pinned, and featured, is in the API reference.
Upload an image
curl -X POST "$JANT_URL/api/upload" \
-H "Authorization: Bearer $JANT_API_TOKEN" \
-F "file=@./path/to/photo.webp;type=image/webp" \
-F "alt=Cover image"
Update settings
curl -X PUT "$JANT_URL/api/settings" \
-H "Authorization: Bearer $JANT_API_TOKEN" \
-H "Content-Type: application/json" \
-d @./examples/agent-content-automation/site-settings.json
Error responses
Every failure under /api returns JSON with a fixed shape:
{
"error": "human readable message",
"code": "ERROR_CODE",
"details": {
"formErrors": [],
"fieldErrors": { "title": ["..."] }
}
}
details is present only on 400 validation failures and names the fields that failed. Common status codes:
| Status | code |
Meaning and handling |
|---|---|---|
| 400 | VALIDATION_ERROR |
Request body failed validation; fix per details |
| 401 | UNAUTHORIZED |
Missing or invalid token; reissue and update env vars |
| 403 | FORBIDDEN |
Token is valid but lacks access to the resource |
| 404 | NOT_FOUND |
Resource doesn't exist |
| 409 | CONFLICT and friends |
State conflict (slug collision, hosted media quota, etc.) |
| 500 | EXTERNAL_SERVICE_ERROR, etc. |
Server error; retry, and if it keeps failing, send the request details for debugging |
Rate limiting
The API has no hard rate limit. The search limit, RATE_LIMIT_SEARCH_PER_MIN in Configuration, applies to signed-out readers on the /search page, not to /api/search. A single Cloudflare Workers instance has limited concurrency, though — for bulk writes, keep calls sequential and add a small gap between writes when needed. If rate limits are added to the API later, they'll return 429 with Retry-After, and this section will be updated.
MCP interface
For agents that already support MCP. The transport is HTTP JSON-RPC:
- Path:
/api/mcp - Authentication: scripts and agents send
Authorization: Bearer jnt_...; same-origin browser extensions can reuse the session cookie. - Protocol header:
MCP-Protocol-Version: 2025-06-18. A request without it is read as that version; any other version answers400. This page is updated when the version changes. - Methods:
initialize,ping,tools/list,tools/call.
The tools cover posts, Threads, media, attachments, collections, settings, and search, and each does what its HTTP endpoint does. Navigation, custom URLs, smart collections, the collections directory, pinning a Thread in a collection, translations, avatar and icon uploads, and export are HTTP-only. Get the exact tool names and parameters from tools/list.
Minimal initialization request:
curl -X POST "$JANT_URL/api/mcp" \
-H "Authorization: Bearer $JANT_API_TOKEN" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
When to use MCP: the caller already has an MCP client; you want Jant exposed as a set of tools rather than handwritten fetch calls.
When not to use MCP: simple shell scripts; one-off bulk content imports; anything that doesn't need tool discovery or the tool-calling protocol.
Recommended starting point: get these three calls working first
If the goal is just "let an agent reliably publish posts, upload images, and change settings," getting these three HTTP calls working is enough:
POST /api/postsPOST /api/uploadPUT /api/settings
Once those are stable, layer on MCP, multi-tool orchestration, or more complex content workflows.
What's next
- API Reference — full fields, request bodies, error formats
- FAQ
examples/agent-content-automation/README.mdin the generated project — runnable end-to-end examples