Skip to content

RFC 115: Write API#115

Open
thibaudcolas wants to merge 6 commits into
wagtail:mainfrom
thibaudcolas:115-write-api
Open

RFC 115: Write API#115
thibaudcolas wants to merge 6 commits into
wagtail:mainfrom
thibaudcolas:115-write-api

Conversation

@thibaudcolas

@thibaudcolas thibaudcolas commented May 15, 2026

Copy link
Copy Markdown
Member

View as HTML. Feedback welcome! (see below). Pending approval by the core team, we’re tentatively planning to work on this with an initial version of the API shipping in Wagtail 8.0 in August 2026.

This RFC proposes a new official CMS API that supports programmatic creation and modification of Wagtail-managed content, including pages, snippets, revisions, and editorial workflow state transitions.
The goal is to support integrations, automation, structured content workflows, and AI-assisted tooling while preserving Wagtail’s editorial governance, permissions, accessibility, and auditability guarantees. This is based on the existing wagtail-write-api, in addition to prior work like Revisions admin API RFC 15.

Key design decisions

  • API framework: DRF vs. Django Ninja: Ninja (generally less established but still 5%+ of Django usage, and better at OpenAPI support)
  • CLI client in core vs. separate: separate (more room for experimentation)
  • Models’ API fields opt-in / opt-out for authenticated reads and writes: TBC
  • API tokens management: how / how much integrated in Wagtail do we want it to be: tentatively keen to have our own "API token" model and admin features.

Feedback welcome

Very keen to hear general feedback, and potential use cases people are interested in: what kinds of clients you’d want to see and how you’d use them.

@thibaudcolas thibaudcolas moved this to 🔍 Reviewing in Wagtail 8.0 release planning May 15, 2026
@thibaudcolas thibaudcolas added the 2:Accepted The core team has accepted the RFC for further review label May 15, 2026
@andreasnuesslein

andreasnuesslein commented May 16, 2026

Copy link
Copy Markdown

hi @thibaudcolas, so I know ninja is more well known but I have been looking into django-bolt. IF it was actually used my something as large as Wagtail, it would hopefully thrive. What I will say: I did develop this https://github.com/sinnwerkstatt/wagtail-ninja and I have a bunch of thoughts; if you're interested maybe we'll videocall about it?

@thibaudcolas

thibaudcolas commented May 19, 2026

Copy link
Copy Markdown
Member Author

@andreasnuesslein I’d love to chat! will DM you on Slack. I’d love to do a "Wagtail on django-bolt" prototype. I expect it’s not going to score well with our criteria (compatibility is paramount, speed not so much). But it’d be a good stress-test of how well our implementation is layered.

@thibaudcolas thibaudcolas added 3:Review The RFC is undergoing detailed design review and consensus-building with the community and removed 2:Accepted The core team has accepted the RFC for further review labels Jun 10, 2026
Comment thread text/115-write-api.md

- Clients send `Authorization: Bearer <token>` on every v3 request.
- Token issuance TBC - [`wagtail-write-api`](https://github.com/tomdyson/wagtail-write-api) precedent for reference:
- Tokens are 40-character hex keys, Wagtail-specific `ApiToken` model, many-to-one user. Keys are generated with `secrets.token_hex(20)` on creation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DTAP, code moves trough each environment from D to P.
Data moves the other way: PRD data is often copied under DEV to replicate a bug, or under ACC to validate something. ACC environments are also used to build and validate external integrations against. Like Write API clients.

Storing tokens in the DB means that copying the PRD data under ACC will destroy existing ACC tokens. Breaking those ACC Write API clients.

I'd like a way to dump and restore tokens. Maybe that is just ./manage.py dumpdata ... and loaddata.
Maybe Wagtail can help with persisting tokens? For example loading them on startup from a setting?

I can see the advantage in Wagtail Admin managed tokens, but there might be projects where you'd want tokens to be developer managed, and not editable via a management interface at all.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep that makes sense to me! I expect our core token implementation has to be usable enough so people don’t have to create custom auth code per project, but flexible enough that other forms of API auth and token management are also supported? Hence why the plan is for an admin interface. Management via the environment makes sense too, though would need to check how we’d make that work in conjunction to user accounts - would those tokens also map to a specific user account or not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Projects I work on have the same user on ACC and PRD. And we can restore tokens by selecting the user by username. We broke client authentication more often then I'd like to admit ;)

In think db stored and admin interface managed tokens are the way to go. It seems the desired way to manage tokens in the majority of projects. And has more advantages, like token invalidation. Permission on the model is sufficient to disallow access it if needed.

Being able to set the tokens, even if only programmatically is important. Maybe that is a sufficient requirement for now?

@laymonage laymonage left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very well-written, thanks Thibaud!

I'm happy with the proposal. There are lots of unknowns that aren't easy to determine at this stage, but I think this is a solid foundation to build the work on.

Comment thread text/115-write-api.md

TBC: Schemas should be cacheable client-side via a process-lifetime ETag.

It’s important the schema contains information that goes beyond data validation (like `help_text` overrides, `HelpPanel` contents, etc), so external CMS clients can provide the same information to their users.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see its usefulness, but given things like HelpPanel require template rendering (and result in HTML), I wonder if that is something we do want to include in the API 🤔

Something to think about when implementing later I guess?

Comment thread text/115-write-api.md Outdated
Comment on lines +603 to +607
### Do we really want auto-incrementing IDs in the API?

Maybe, maybe not? See [Add a UUIDField to the Page model #6162](https://github.com/wagtail/wagtail/issues/6162), and [Support customizing/encoding IDs in the API #6917](https://github.com/wagtail/wagtail/issues/6917).

The write API is viable regardless of the IDs being used but it’s a good time to revisit this if we wanted.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't see this as a problem, given that the existing read API already works this way, and write access will only be given to those with the same permissions in the admin (which also use the auto ID by default).

Comment thread text/115-write-api.md
1. **Schema layer** — request shape, types, required vs. optional fields. Generated from per-content-type Pydantic schemas (Django Ninja). Failure → **422** (Ninja/Pydantic default).
2. **Content format layer** — StreamField block types validated against registered block definitions; rich text content validated against the declared `RichTextField` features whitelist. Failure → **422**.
3. **Model layer** — `full_clean()` and other model-level constraints. Failure → **422**.
4. **Permission layer** — checked before model save. Failure → **403**.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that this makes sense if we put (and use) the permission checks in the operations layer, but FWIW permission checks for the CMS itself is usually done in the view at the beginning of the request handling, after the object was retrieved.

I think this was probably the main motivation behind skip_permission_checks in the actions module. (If the view has already checked for permissions, it can be skipped during the operation execution.)

Not sure how much it matters, but worth flagging if we want the behaviour to be as close as the CMS/admin UI as much as possible.

It probably is better to put the permission checks inside the operations layer and use it that way in the API. This ensures future operations have the permission checks built into them, and any code that uses them won't have to worry about it. Then eventually maybe we refactor the admin views to use the same pattern.

Comment thread text/115-write-api.md

#### Workflow as validation

Some operations are valid in field-shape but invalid in workflow state, like submitting an already-published page to workflow.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be the best example, isn't "submitting an already-published page to workflow" a normal use case when you want to moderate further edits?

Maybe something like "submitting a page that has an in-progress workflow to a new workflow", or "approving/cancelling a page that has completed its (or is not currently in a) workflow)"

Comment thread text/115-write-api.md
Comment on lines +331 to +332
- [`FieldPanel`](https://docs.wagtail.org/en/stable/reference/panels.html) configuration: `help_text`, `read_only`, `required_on_save`, `permission`, `disable_comments`.
- Capabilities of other panels, such as [`PageChooserPanel`](https://docs.wagtail.org/en/stable/reference/panels.html#wagtail.admin.panels.PageChooserPanel) page-type filtering.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit wary about coupling api_fields with panels. It does make sense if we view the API as a headless version of the CMS, but I can imagine people wanting to keep them separate.

Also we'll probably need a mechanism to "retrieve the panel instance for a given field of a model". I don't think it exists yet atm, and not sure how much work it is to get right (and performant).

I'm not against the idea, just thought it's worth flagging.

@Stormheg Stormheg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is really comprehensive. The scope and implementation plan looks fine to me. There's nothing I can think of right now that is missing.

My only question – already tackled in this document – what happens to the v2 api?

It is not easy to deprecate and remove, since many implementers will have build their sites/apps with it may have customized it with new filters and endpoints and such. I know I have done this.

For this reason, even if the v3 api matches the v2 api mostly, I feel we should continue to support the v2 api, with a long deprecation cycle since it is such an extensively used component that's hard to swap out for something new (clients need to be updated).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3:Review The RFC is undergoing detailed design review and consensus-building with the community

Projects

Status: 🔍 Reviewing

Development

Successfully merging this pull request may close these issues.

5 participants