Social guides
Guides

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:

  1. Snapshots the PRE-edit body / title / attributes into post_revision with revision_n=1.
  2. Updates the post row with the new content, sets edited_at=now(), bumps edit_count.

All in one DB transaction — a failed update rolls back both pieces, no orphan revisions.

bash
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:

json
{
  "statusCode": 422,
  "message": "Edit window expired (30 min after post creation)",
  "code": "EDIT_WINDOW_EXPIRED"
}

Override per-community via community.settings.edit_window_minutes:

bash
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 transitionStatus which 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.

bash
curl -H "Authorization: Bearer pcft_live_..." \
  "https://social.productcraft.co/v1/communities/<communityId>/posts/<postId>/revisions?limit=20"
json
{
  "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 /revisions for 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.update on pcft:agora:post/<postId>.
  • GET /revisions: social.read on the same URN.