Overview
Start here
The public API currently exposes the minimum surface needed for integrations to discover projects and log writing progress. This page documents the public project and session endpoints available today. For AI assistants, see the MCP guide.
https://quilvo.app/api/v1application/jsonBearer tokenprojects:* / sessions:*Authentication
Bearer tokens
Users create public API keys from Settings / API Keys. Each key can be limited to the project and session abilities needed by the integration.
Authorization: Bearer YOUR_API_KEY
Accept: application/json
Content-Type: application/jsonAbilities
| Ability | Description |
|---|---|
projects:read | Read projectsList projects and read project details. |
projects:write | Write projectsCreate projects and update project metadata. |
sessions:read | Read sessionsList writing sessions and read today's session summary. |
sessions:write | Write sessionsCreate single or bulk writing sessions. |
characters:read | Read charactersList and read planning characters. |
characters:write | Write charactersCreate and update planning characters. |
codex:read | Read codexList and read worldbuilding codex entries. |
codex:write | Write codexCreate and update worldbuilding codex entries. |
timeline:read | Read timelineList and read story timeline events. |
timeline:write | Write timelineCreate and update story timeline events. |
Requests
Request conventions
- Send JSON request bodies for write endpoints.
- Dates use
YYYY-MM-DD. - Resource IDs are UUID strings.
- List endpoints use cursor pagination and accept
per_page.
Responses
Response formats
Paginated lists
{
"data": [],
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
},
"meta": {
"path": "https://quilvo.app/api/v1/projects",
"per_page": 25,
"next_cursor": "...",
"prev_cursor": null
}
}Error responses
{
"error": {
"code": "validation_error",
"message": "The given data was invalid.",
"details": {
"word_count": ["The word count field is required."]
}
}
}Projects
Project endpoints
Use project endpoints to list existing projects, create projects for a linked tool, or update project metadata. For ordinary word count changes, use session endpoints instead.
/projectsList projects for the authenticated user.
Required ability: projects:read
Query parameters
status | active by default. Use archived or all when needed. |
type | Filter by project type, such as novel or short_story. |
series_id | Filter projects by series UUID. |
search | Case-insensitive title search. |
per_page | Cursor page size. Maximum 100. |
/projects/{project}Read one project, including detail fields, recent sessions, and summary stats.
Required ability: projects:read
Response excerpt
{
"id": "9b7d4f6a-...",
"title": "Draft novel",
"type": "novel",
"status": "drafting",
"current_word_count": 42100,
"target_word_count": 80000,
"target_unit": "words",
"progress_percent": 52.63,
"recent_sessions": []
}/projectsCreate a project.
Required ability: projects:write
Body fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Create | Project title. |
type | string | Create | Project type enum, for example novel. |
status | string | No | Project status enum, for example drafting. |
target_word_count | integer | No | Target count. Minimum 0. |
current_word_count | integer | No | Baseline/import count only. Prefer session logging for ongoing changes. |
target_date | date | No | Alias for target_completion_date. |
description | string | No | Alias for the short project description. |
Request example
{
"title": "Draft novel",
"type": "novel",
"status": "drafting",
"target_word_count": 80000
}/projects/{project}Update project metadata. This endpoint accepts the same fields as project creation, but all fields are optional.
Required ability: projects:write
{
"status": "revising",
"target_word_count": 90000
}/projects/{project}Move a project to the trash. It stays recoverable for 30 days, then is permanently purged along with its drafts, chapters, scenes, writing sessions, goals, submissions, and character arcs.
Linked characters, codex entries, and the project's timeline events and threads are kept by default. Send the optional fields below to also delete planning data that belongs only to this project; the choices are stored with the trashed project and applied when it is permanently purged.
Required ability: * (first-party only)
Body fields
| Field | Type | Required | Description |
|---|---|---|---|
delete_project_only_characters | boolean | No | Permanently delete characters whose only project link is this one. Characters shared with another project are always kept. Defaults to false. |
delete_project_only_codex_entries | boolean | No | Permanently delete codex entries whose only project link is this one. Shared entries are always kept. Defaults to false. |
delete_timeline_events | boolean | No | Permanently delete timeline events scoped to this project. When false, kept events remain on the global timeline. Defaults to false. |
delete_timeline_threads | boolean | No | Permanently delete timeline threads scoped to this project. When false, kept threads are unlinked from the project. Defaults to false. |
Request example
{
"delete_project_only_characters": true,
"delete_timeline_events": true
}Returns 204 No Content.
Sessions
Session endpoints
Session endpoints are the preferred way to update word counts because Quilvo stores the event history and updates the project total for you.
/sessionsList writing sessions.
Required ability: sessions:read
Query parameters
project_id | Filter sessions for a single project UUID. |
date_from | Start date in YYYY-MM-DD format. |
date_to | End date in YYYY-MM-DD format. |
per_page | Cursor page size. Maximum 100. |
/sessions/todayRead today's sessions and totals in the account timezone.
Required ability: sessions:read
{
"date": "2026-05-24",
"sessions": [],
"summary": {
"total_words": 750,
"total_sessions": 1,
"total_minutes": 45
}
}/sessions Log a single writing session. Use add for deltas or set_total when the client knows the new project total.
Required ability: sessions:write
Idempotency-Key header, or a top-level idempotency_key body field. Reuse the same key only for retrying the same request. Keys are stored for 24 hours. Body fields
| Field | Type | Required | Description |
|---|---|---|---|
project_id | uuid | Yes | The project to log progress against. |
word_count_action | string | No | add by default. Use set_total when sending the new project total. |
word_count | integer | Yes | For add, the delta. For set_total, the new total; Quilvo stores the calculated delta. |
date | date | No | YYYY-MM-DD. Defaults to today. Cannot be in the future. |
duration_minutes | integer | No | Duration from 0 to 1440 minutes. |
notes | string | No | Optional session notes. Maximum 1000 characters. |
Request example
curl -X POST https://quilvo.app/api/v1/sessions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: local-log-2026-05-24-0830" \
-H "Content-Type: application/json" \
-d '{
"project_id": "9b7d4f6a-...",
"word_count_action": "add",
"word_count": 750,
"date": "2026-05-24",
"duration_minutes": 45
}'Response excerpt
{
"id": "9c1a...",
"project_id": "9b7d4f6a-...",
"date": "2026-05-24",
"word_count": 750,
"unit": "words",
"duration_minutes": 45
}/sessions/bulkCreate up to 30 session records in one request. Bulk logging accepts deltas only.
Required ability: sessions:write
Idempotency-Key header or idempotency_key body field as POST /sessions. Body fields
| Field | Type | Required | Description |
|---|---|---|---|
sessions | array | Yes | 1 to 30 session objects. |
sessions.*.project_id | uuid | Yes | Project UUID owned by the authenticated user. |
sessions.*.date | date | Yes | YYYY-MM-DD. Cannot be in the future. |
sessions.*.word_count | integer | Yes | Delta only. set_total is intentionally not supported in bulk. |
{
"sessions": [
{
"project_id": "9b7d4f6a-...",
"date": "2026-05-23",
"word_count": 320
}
]
}Errors
Status codes
| Status | Meaning |
|---|---|
200 | Successful read or replayed write. |
201 | Resource created. |
401 | Missing or invalid bearer token. |
403 | Token is valid but missing the required ability. |
404 | Resource not found or not owned by this account. |
409 | Idempotency key conflict or in-progress request. |
422 | Validation failed. See `error.details`. |
429 | Too many requests. |