Overview
Introduction
The JotBird API allows you to publish, manage, and remove Markdown using scripts, CI pipelines, or any HTTP client. All you need is a free JotBird account and an API key.
All endpoints accept and return JSON. The base URL for all requests is:
https://www.jotbird.comIf you prefer a CLI, the jotbird command wraps these endpoints with file tracking and slug mapping. Install it from npm:
npm install -g jotbirdAn OpenAPI spec is also available for code generation and tooling.
Security
Authentication
All API requests require a personal API key, passed as a Bearer token in the Authorization header:
Authorization: Bearer jb_your_api_key_hereGenerating a key
Sign up for a free account at jotbird.com, then generate an API key in two ways:
- CLI: Run
jotbird loginto open the browser and generate a key automatically. - Browser: Visit jotbird.com/account/api-key while signed in to generate a key.
API keys start with jb_ and are shown only once at creation. Store your key securely — if lost, generate a new one.
Key limits
Each account can have up to 10 API keys. If you reach the limit, revoke an existing key before generating a new one.
Revoking a key
To revoke an API key, open the API keys panel from your account menu in the web app. Each key shows its prefix, creation date, and last usage. Click Revoke to permanently delete a key. Revoked keys stop working immediately.
Reference
Rate Limits
Publish requests are rate-limited per account on a rolling hourly window. Free accounts also have a cap on the number of active documents published via API. Active documents are documents with a live public URL that have not expired. Expired documents do not count toward the limit.
| Limit | Free Account | Pro Account |
|---|---|---|
| Publishes per hour | 10 | 100 |
| Active documents | 10 | Unlimited |
Response headers
Every publish response includes rate limit information:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests per hour for your account |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp (seconds) when the window resets |
| Retry-After | Seconds until you can retry (only on 429 responses) |
Pro accounts are for individual use only, not enterprise use. If you exceed the rate limit, the API returns a 429 status with a Retry-After header indicating when to retry.
Endpoint
Publish a document
/api/v1/publishPublish a new Markdown document or update an existing one. The server renders your Markdown to HTML and hosts it at a shareable URL. Free accounts get 90-day links. Pro makes links permanent.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| markdown | string | Yes | The Markdown content to publish. |
| title | string | No | Document title. If omitted, extracted from the first H1 in the Markdown. |
| slug | string | No | Slug of an existing document to update. If the slug exists and is owned by you, the document is updated in place. Ignored for new documents. |
curl -X POST https://www.jotbird.com/api/v1/publish \
-H "Authorization: Bearer jb_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Hello World\n\nThis is my document."
}'Response
Returns 201 for new documents, 200 for updates.
{
"slug": "bright-calm-meadow",
"url": "https://share.jotbird.com/bright-calm-meadow",
"title": "Hello World",
"expiresAt": "2026-05-10T12:00:00.000Z",
"ttlDays": 90,
"created": true
}A URL slug is generated automatically for new documents. Re-publishing with the same slug updates the document in place rather than creating a new URL. Pro accounts get permanent documents — expiresAt will be null.
Image uploads are not supported through the API. Markdown image references (e.g. ) will render only if they point to externally-hosted images.
Free accounts are limited to 10 active documents. Updating an existing document does not count toward this limit. See Rate Limits for details.
Endpoint
List documents
/api/v1/documentsRetrieve all published documents for your account. Only documents with an active public URL are returned.
Request
No request body is required.
curl https://www.jotbird.com/api/v1/documents \
-H "Authorization: Bearer jb_your_api_key_here"Response
{
"documents": [
{
"slug": "bright-calm-meadow",
"title": "Hello World",
"url": "https://share.jotbird.com/bright-calm-meadow",
"source": "cli",
"updatedAt": "2026-02-09T14:30:00.000Z",
"expiresAt": "2026-05-10T14:30:00.000Z"
}
]
}Results are ordered by most recently updated. The source field indicates how the document was created: "cli", "web", or "api".
Endpoint
Remove a document
/api/v1/documents?slug=:slugPermanently delete a document. This removes the public URL, the stored content, and all associated image references. This action cannot be undone.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| slug | string | Yes | The slug of the document to remove. |
curl -X DELETE "https://www.jotbird.com/api/v1/documents?slug=bright-calm-meadow" \
-H "Authorization: Bearer jb_your_api_key_here"Response
{
"ok": true
}Permanent action
This permanently deletes the document from your account. There is no way to recover a removed document.
Reference
Errors
All error responses return a JSON object with an error field containing a human-readable message:
{
"error": "Missing markdown field"
}Status codes
| Code | Meaning | Example | Common causes |
|---|---|---|---|
| 400 | Bad Request | "Missing markdown field" | Invalid JSON, missing required fields, invalid slug format |
| 401 | Unauthorized | "Invalid API key" | Missing or expired API key, malformed Bearer token |
| 403 | Forbidden | "Document not owned by user""Document limit reached (10)..." | Document owned by another account, or free-tier document cap reached |
| 429 | Too Many Requests | "Rate limit exceeded. Try again in 1800 seconds." | More than 10 (free) or 100 (pro) publishes per hour |
| 413 | Payload Too Large | "Rendered HTML too large (max 524288 bytes)" | Rendered HTML exceeds 512 KB |
| 503 | Service Unavailable | "Failed to allocate document slug" | Database temporarily unavailable, slug allocation failed |