JSON API (v1)
Recommended for apps and scripts: predictable JSON, rich filters, and explicit blog selection via blog_id on the query string when you are not using the selected blog.
https://scribbles.page/api/v1
Discover blogs and metadata
https://scribbles.page/api/v1/info
Returns API metadata and the blogs available to your account.
Example Request
curl "https://scribbles.page/api/v1/info" \
-H "Authorization: Bearer YOUR_API_KEY"
List posts
https://scribbles.page/api/v1/posts
List, filter, and paginate posts. List responses omit heavy body fields unless you opt in with include_content.
Example Request
curl "https://scribbles.page/api/v1/posts?limit=10&sort=-published_at" \
-H "Authorization: Bearer YOUR_API_KEY"
curl "https://scribbles.page/api/v1/posts?include_content=true&limit=5" \
-H "Authorization: Bearer YOUR_API_KEY"
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| blog_id | integer | No | Target a specific blog by id. |
| status | string | No | published (default), draft, archived, or all. |
| type | string | No | posts or pages. |
| category | string | No | Filter to one category (name). |
| category_id | integer | No | Filter to one category (id). |
| exclude_category | string | No | Exclude one category (name). |
| exclude_category_id | integer | No | Exclude one category (id). |
| uncategorized | boolean | No | true for posts with no category. |
| search | string | No | Search title and content. |
| from_date | date | No | Start of date range filter. |
| to_date | date | No | End of date range filter. |
| page | integer | No | Page number for pagination. |
| limit | integer | No | Page size (max 100). |
| sort | string | No | Sort field; prefix with - for descending (title, created_at, updated_at, published_at). |
| include_content | boolean | No | When true, list items include HTML/text bodies. |
Create and update posts
https://scribbles.page/api/v1/posts
Create a post with a JSON body wrapped under post. Use PUT or PATCH on /posts/:id to update.
Example Request
curl -X POST "https://scribbles.page/api/v1/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"post":{"title":"Hello","content":"This is **markdown**.","content_type":"markdown","status":"published"}}'
https://scribbles.page/api/v1/posts/:id
Example (update)
curl -X PATCH "https://scribbles.page/api/v1/posts/123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"post":{"title":"Updated title"}}'
https://scribbles.page/api/v1/posts/:id
Example (delete)
curl -X DELETE "https://scribbles.page/api/v1/posts/123" \
-H "Authorization: Bearer YOUR_API_KEY"
Publish and unpublish
https://scribbles.page/api/v1/posts/:id/publish
https://scribbles.page/api/v1/posts/:id/unpublish
Example Request
curl -X PATCH "https://scribbles.page/api/v1/posts/123/publish" \
-H "Authorization: Bearer YOUR_API_KEY"
curl -X PATCH "https://scribbles.page/api/v1/posts/123/unpublish" \
-H "Authorization: Bearer YOUR_API_KEY"
Attachments and rich HTML
https://scribbles.page/api/v1/attachments
The usual flow is two requests: upload the image, then create (or update) a post that embeds the returned snippet and sets alt text. Upload with multipart form data.
1. Upload the image
curl -X POST "https://scribbles.page/api/v1/attachments" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "blog_id=YOUR_BLOG_ID" \
-F "attachment[file][email protected]" \
-F "attachment[caption]=Optional caption"
Copy html (the ActionText snippet) and filename from the response:
Upload response
{
"attachment": {
"html": "<action-text-attachment sgid=\"SGID_FROM_UPLOAD\" content-type=\"image/jpeg\" filename=\"photo.jpg\" caption=\"Optional caption\"></action-text-attachment>",
"filename": "photo.jpg",
"media_type": "image"
}
}
Embed the html value in content and key alt_text by the filename. Send the body as HTML — do not use content_type=markdown for attachment HTML.
2. Create the post with alt text
curl -X POST "https://scribbles.page/api/v1/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"blog_id": "YOUR_BLOG_ID",
"post": {
"title": "My post with an image",
"content": "<p>Intro.</p>ACTION_TEXT_ATTACHMENT_HTML<p>Outro.</p>",
"status": "published",
"alt_text": { "photo.jpg": "A sunlit desk with a notebook" }
}
}'
See Alt text for describing images.
Alt text
Set per-image alt text the same way the editor does by sending post[alt_text] when you create or update a post, keyed by the attachment filename returned by the upload endpoint. It is stored on the post and comes back as alt on each attachment in post responses.
Object form (filename → alt)
{"post":{"alt_text":{"photo.jpg":"A sunlit desk with a notebook","diagram.png":"Architecture overview"}}}
Array form
{"post":{"alt_text":[{"filename":"photo.jpg","alt":"A sunlit desk with a notebook"}]}}
Response shape (sketch)
Single post payloads wrap attributes under post, including nested content (html, text), blog, category, meta, and optional attachments. Lists return posts plus pagination (page, limit, total, pages).
Single post response
{
"post": {
"id": 123,
"title": "My post with an image",
"slug": "my-post-with-an-image",
"status": "published",
"type": "post",
"published_at": "2026-06-18T08:30:00Z",
"created_at": "2026-06-18T08:30:00Z",
"updated_at": "2026-06-18T08:30:00Z",
"url": "https://your-blog.example/post/my-post-with-an-image",
"blog": { "id": 9, "title": "My blog", "slug": "my-blog" },
"category": { "id": 4, "name": "Notes", "slug": "notes" },
"meta": {
"hidden": false,
"hide_in_rss": false,
"no_index_no_follow": false,
"show_contact_form": false,
"komments_disabled": false,
"archived": false,
"skip_archive": false,
"is_shared": false,
"share_id": null
},
"content": { "html": "<p>Intro.</p>…", "text": "Intro. …" },
"attachments": [
{
"id": 55,
"blob_id": 88,
"filename": "photo.jpg",
"content_type": "image/jpeg",
"byte_size": 46956,
"media_type": "image",
"url": "https://…/photo.jpg",
"thumbnail": "https://…/photo.jpg",
"alt": "A sunlit desk with a notebook"
}
]
}
}
Errors
- 401 — Missing or invalid API key.
- 403 — Authenticated but not allowed for the resource or action.
- 404 — Unknown blog or post.
- 400 — Bad query combination (for example category filters that exclude each other) or missing upload fields.
- 422 — Validation errors; JSON body often includes
errors/message.