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.
If you scaffolded the site with create-jant, the project also ships with:
AGENTS.md.agents/skills/.claude/skills/examples/agent-content-automation/README.md
So an agent working inside the generated project gets more than an API token — it sees the project conventions and ready-to-run examples directly.
Which path first
- Scripts, scheduled jobs, migrations, external integrations: use the HTTP API.
- The caller is itself an MCP client: use MCP.
Default to HTTP. MCP only beats it when the caller already speaks the tool-calling protocol.
Local CLI
Operations that touch the local environment or the database stay on the CLI: migrate, deploy, reset-password, site snapshot, site export, site import, db export, and so on. These commands read and write the database or site deployment directly — no HTTP, no API token. See Export and import.
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: GET /api/collections, GET /api/collections/:id, GET /api/search, GET /api/public/posts, GET /api/public/posts/:slug, GET /api/public/archive.
Common endpoints
| Endpoint | Methods | Purpose |
|---|---|---|
/api/posts |
GET / POST / PUT / DELETE | List, read, create, update, delete posts |
/api/public/posts |
GET | Public read of published posts (no token) |
/api/public/archive |
GET | Public archive feed — includes latest_hidden, supports year/media/title filters (no token) |
/api/upload |
POST / GET / PATCH / DELETE | One-shot multipart upload, single file per call — preferred for scripts |
/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 (GET needs no token) |
/api/settings |
GET / PUT | Site settings |
/api/search |
GET | Full-text search (public, IP-rate-limited) |
/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",
"body": "Hello from curl."
}'
For more formats (link, quote) and advanced fields (collections, publishedAt, slug, pinned, featured), see examples/agent-content-automation/.
Upload an image
curl -X POST "$JANT_URL/api/upload" \
-H "Authorization: Bearer $JANT_API_TOKEN" \
-F "file=@./path/to/photo.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": "..."
}
details is present only on 400 validation failures and carries the field-level information. 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.) |
| 429 | RATE_LIMIT |
Rate-limited; see below |
| 500 | EXTERNAL_SERVICE_ERROR, etc. |
Server error; retry, and if it keeps failing, send the request details for debugging |
Rate limiting
Today only /api/search enforces a per-IP per-minute limit (controlled by the deployment's appConfig.rateLimit.searchPerMinute; for the default see Configuration). Other endpoints have no hard rate limit, but a single Cloudflare Workers instance has limited concurrency — for bulk writes, keep calls sequential and add a small gap between writes when needed. If more rate limits are introduced 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. This page is updated when the version changes. - Methods:
initialize,ping,tools/list,tools/call.
Tools are grouped by resource: posts, media, attachments, collections, settings, search. Get the exact tool names and parameters from tools/list; they map one-to-one with the HTTP endpoints.
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