Edit history.
X-style edit window. Edits within the window snapshot the prior state into post_revision before the new content lands. Past the window, content edits 422. Drafts edit freely.
1
Edit a post
Use the existing PATCH endpoint with body / title / attributes. The first edit:
- Snapshots the PRE-edit body / title / attributes into
post_revisionwithrevision_n=1. - Updates the post row with the new content, sets
edited_at=now(), bumpsedit_count.
All in one DB transaction — a failed update rolls back both pieces, no orphan revisions.
curl -X PATCH \
-H "Authorization: Bearer pcft_live_..." \
-H "Content-Type: application/json" \
-d '{"body":"updated wording"}' \
"https://social.productcraft.co/v1/communities/<communityId>/posts/<postId>"Each subsequent edit increments revision_n.post.edited_at is always the most recent edit; post.edit_count equals the count of revision rows.
2
The edit window
Default: 30 minutes after post.created_at. Past the window, a content edit returns:
{
"statusCode": 422,
"message": "Edit window expired (30 min after post creation)",
"code": "EDIT_WINDOW_EXPIRED"
}Override per-community via community.settings.edit_window_minutes:
curl -X PATCH \
-H "Authorization: Bearer pcft_live_..." \
-H "Content-Type: application/json" \
-d '{"settings":{"edit_window_minutes":120}}' \
"https://social.productcraft.co/v1/workspaces/<workspaceId>/communities/<communityId>"3
What counts as an edit
- Counts: body, title, attributes changes.
- Doesn't count: visibility, status, pinned, expires_at — pure-metadata PATCHes skip the window check AND don't snapshot. So archiving a post or changing visibility years later is fine.
- Drafts edit freely: while
status="draft", the window doesn't apply and revisions aren't recorded. Only published posts incur edit history. - Moderation actions don't snapshot: moderator hide / remove / restore go through
transitionStatuswhich doesn't touch body / title / attributes — no revision row is created.
4
Read the history
Cursor-paginated newest revision first. Each entry is the before state of the corresponding edit. The post row itself carries the current state.
curl -H "Authorization: Bearer pcft_live_..." \
"https://social.productcraft.co/v1/communities/<communityId>/posts/<postId>/revisions?limit=20"{
"data": [
{
"post_id": "bbbbbbbb-...",
"revision_n": 2,
"body": "edit one",
"title": null,
"attributes": {},
"edited_at": "2026-05-11T14:05:00.000Z"
},
{
"post_id": "bbbbbbbb-...",
"revision_n": 1,
"body": "original wording",
"title": null,
"attributes": {},
"edited_at": "2026-05-11T14:00:00.000Z"
}
],
"pagination": { "next_cursor": null, "has_more": false }
}UX
Surfacing the edit badge
Every post-returning endpoint now includes edited_at and edit_count:
- Show an “edited” badge when
edit_count > 0. - Tap it to load
/revisionsfor the diff view. - Suppress the badge for moderation status changes — they don't bump
edit_count.
Permissions
PAK scopes
- PATCH (the existing post update endpoint):
social.updateonpcft:agora:post/<postId>. - GET
/revisions:social.readon the same URN.