v3

latestOpenAPI 3.1.0raw.githubusercontent.com2026-08-012582298.4 KB
Drafts

Update draft

Update an existing draft with partial update semantics. Only provided fields are updated; omitted fields remain unchanged. Scheduled drafts require publish access to edit.

Note about Comment-thread markers

If the draft has comment threads, submitted posts[*].text and X Article platforms.x_article.content_markdown must preserve the Typefully comment-thread markers received from GET /drafts/{id}. Validation is platform-level: every comment thread anchored on a platform must appear somewhere in that platform's submitted text.

Recommended edit flow: GET the draft without exclude_comment_markers, modify text while preserving markers exactly, then PATCH with force_overwrite_comments: false (the default).

  • 409 COMMENTS_MARKER_MISMATCH will be thrown if an expected comment thread marker is missing unless "force_overwrite_comments": true is set, in which case the affected threads are resolved server-side.
  • 400 COMMENTS_MARKER_UNKNOWN_ID will be thrown if you submit an id that doesn't exist on this draft. - 400 COMMENTS_MARKER_MALFORMED will be thrown if the marker tag is malformed (bad UUID, unbalanced, attribute violations, etc.).

Pass ?exclude_comment_markers=true to render the response text without markers (read-only / display rendering — does NOT skip server-side marker validation on the request body). Do not PATCH content returned with that flag unless you intend to resolve or remove comment anchors.

Required permission: WRITE access to edit drafts. PUBLISH access is required to edit scheduled drafts, schedule, or publish.

patch/v2/social-sets/{social_set_id}/drafts/{draft_id}

Path parameters

social_set_idinteger required
draft_idinteger required

Query parameters

exclude_comment_markersboolean

Render the response's posts[*].text as plain text without <typ:comment-thread> markers, and render X Article content_markdown without comment markers. Render-only — does not affect request-body validation.

Render the response's posts[*].text as plain text without <typ:comment-thread> markers, and render X Article content_markdown without comment markers. Render-only — does not affect request-body validation.

Request body

draft_titlestring nullable

Human-readable title for the draft. This is for internal organization only and is not posted to social media. Omit to keep unchanged.

scratchpad_textstring nullable

Plain text scratchpad notes for the draft. Formatting is stripped. Omit to keep unchanged.

tagsstring[] nullable

List of tag slugs (not names) associated with this draft. Use the /tags endpoint to get available tags with their slugs. Tags must already exist in the social set. Omit to keep unchanged.

shareboolean nullable

Whether to generate a public share URL. Omit to keep unchanged.

force_overwrite_commentsboolean

Comment-thread anchor preservation toggle. When false (the default), submitting posts[*].text or X Article content_markdown whose <typ:comment-thread> markers don't match the draft's stored comment threads is rejected with 409 COMMENTS_MARKER_MISMATCH. Recover by re-including the missing markers and retrying. When true, missing markers are accepted: the affected comment threads are resolved server-side and their anchors are stripped from the draft. Markers that ARE submitted continue to be validated and re-anchored normally. StrictBool: only the JSON literals true/false are accepted (not "true" strings).

Example request

{
  "platforms": {
    "x": {
      "posts": [
        {
          "text": "Hello world! This is my first post.",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "quote_post_url": "https://x.com/typefully/status/2025894220243063023"
        }
      ],
      "settings": {
        "reply_to_url": "https://x.com/therajatkapoor/status/1399394576951959554"
      }
    },
    "linkedin": {
      "posts": [
        {
          "text": "Thanks @[Typefully](urn:li:organization:86779668) for the support!",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ],
          "linkedin_reshare_target": "urn:li:share:7437089188157554688"
        }
      ]
    },
    "mastodon": {
      "posts": [
        {
          "text": "Hello world! This is my first post.",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ]
        }
      ]
    },
    "threads": {
      "posts": [
        {
          "text": "Hello world! This is my first post.",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ]
        }
      ]
    },
    "bluesky": {
      "posts": [
        {
          "text": "Hello world! This is my first post.",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ]
        }
      ]
    },
    "substack": {
      "posts": [
        {
          "text": "Hello world! This is my first post.",
          "media_ids": [
            "550e8400-e29b-41d4-a716-446655440000"
          ]
        }
      ]
    },
    "x_article": {
      "content_markdown": "# Think Different, Draft Different\n\nGreat drafts start when builders **question defaults**, *shape the rough edges*, and ~~wait for perfect certainty~~ publish what helps.\n\n> The best interface is the one readers forget they are using.\n\n# Working notes\n\n- Start with a sharp title\n- Use structure before decoration\n- Link only when [context helps](https://typefully.com)\n\n## Final pass\n\n1. Cut filler\n2. Keep the useful tension\n3. Ship the clearer version",
      "cover_media_id": "550e8400-e29b-41d4-a716-446655440000"
    }
  },
  "draft_title": "Weekly Newsletter",
  "scratchpad_text": "line 1\nline 2\n\nline 4",
  "tags": [
    "marketing",
    "product"
  ]
}

Response

OK

idinteger required

Unique identifier for the draft

social_set_idinteger required

ID of the social set (account) this draft belongs to

draft_idinteger required

Deprecated: Use 'id' instead. Unique identifier for the draft.

status'draft' | 'scheduled' | 'published' | 'publishing' | 'error' | 'planned' required

Current status of the draft. 'draft' = saved but not scheduled, 'scheduled' = queued for publishing, 'published' = successfully posted, 'error' = publishing failed, 'planned' = dated but inert (it has a scheduled_date but never auto-publishes until confirmed in the Typefully app). This reflects the stored draft lifecycle; it does not flip to 'publishing' while an immediate publish is in flight - use publish_state to track that.

publish_state'in_progress' | 'finished' nullable

Async publish-progress signal, separate from status. null = no publish initiated; 'in_progress' = at least one platform is currently being posted; 'finished' = publishing has completed for all platforms. 'finished' means the job is done, not that it succeeded - read status and the per-platform published URLs (x_published_url, etc.) for the outcome. After publish_at="now", poll GET /drafts/{id} until publish_state is 'finished'.

created_atstring date-time required

Timestamp when the draft was created (ISO 8601 format in UTC)

updated_atstring date-time nullable

Timestamp when the draft was last edited (ISO 8601 format in UTC). Null if never edited.

scheduled_datestring date-time nullable

Timestamp when the draft is scheduled to publish (ISO 8601 format in UTC). Null if not scheduled.

published_atstring date-time nullable

Timestamp when the draft was published on any enabled platform (ISO 8601 format in UTC). Null if not yet published.

draft_titlestring nullable

Human-readable title for the draft. This is for internal organization only and is not posted to social media.

tagsstring[]

List of tag slugs (not names) associated with this draft. Use the /tags endpoint to get available tags with their slugs.

previewstring required

Text preview of the draft, smart-trimmed with a 100-character limit

share_urlstring nullable

Public share URL for the draft. Null if the draft is not publicly shared.

private_urlstring required

Private URL for accessing the draft in Typefully. Can be shared with team members without requiring public sharing.

x_published_urlstring nullable

URL of the published post on X (Twitter). Null if not published to X or URL not available.

linkedin_published_urlstring nullable

URL of the published post on LinkedIn. Null if not published to LinkedIn or URL not available.

mastodon_published_urlstring nullable

URL of the published post on Mastodon. Null if not published to Mastodon or URL not available.

threads_published_urlstring nullable

URL of the published post on Threads. Null if not published to Threads or URL not available.

bluesky_published_urlstring nullable

URL of the published post on Bluesky. Null if not published to Bluesky or URL not available.

substack_published_urlstring nullable

URL of the published note on Substack. Null if not published to Substack or URL not available.

x_article_published_urlstring nullable

URL of the published X Article. Null if not published or URL not available.

x_post_published_atstring date-time nullable

Timestamp when the post was published to X (ISO 8601 format in UTC). Null if not published to X.

linkedin_post_published_atstring date-time nullable

Timestamp when the post was published to LinkedIn (ISO 8601 format in UTC). Null if not published to LinkedIn.

mastodon_post_published_atstring date-time nullable

Timestamp when the post was published to Mastodon (ISO 8601 format in UTC). Null if not published to Mastodon.

threads_post_published_atstring date-time nullable

Timestamp when the post was published to Threads (ISO 8601 format in UTC). Null if not published to Threads.

bluesky_post_published_atstring date-time nullable

Timestamp when the post was published to Bluesky (ISO 8601 format in UTC). Null if not published to Bluesky.

substack_post_published_atstring date-time nullable

Timestamp when the note was published to Substack (ISO 8601 format in UTC). Null if not published to Substack.

x_article_published_atstring date-time nullable

Timestamp when the X Article was published (ISO 8601 format in UTC). Null if not published.

scratchpad_textstring nullable

Plain text scratchpad notes for the draft. Formatting is stripped.

Example response

{
  "id": 12345,
  "social_set_id": 67890,
  "draft_id": 12345,
  "status": "draft",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-16T09:15:00Z",
  "scheduled_date": "2025-01-20T14:00:00Z",
  "published_at": "2025-01-20T14:00:05Z",
  "draft_title": "Weekly Newsletter",
  "tags": [
    "marketing",
    "product"
  ],
  "preview": "Excited to announce our new feature! 🚀",
  "share_url": "https://typefully.com/share/abc123",
  "private_url": "https://typefully.com/?d=12345&a=67890",
  "platforms": {
    "x": {
      "posts": [
        {
          "subscribers_only": true,
          "paid_partnership": true,
          "made_with_ai": true
        }
      ],
      "settings": {
        "reply_to_url": "https://x.com/therajatkapoor/status/1399394576951959554"
      }
    }
  },
  "x_published_url": "https://x.com/username/status/1234567890",
  "linkedin_published_url": "https://www.linkedin.com/feed/update/urn:li:share:1234567890",
  "mastodon_published_url": "https://mastodon.social/@username/1234567890",
  "threads_published_url": "https://www.threads.net/@username/post/ABC123",
  "bluesky_published_url": "https://bsky.app/profile/username.bsky.social/post/abc123",
  "substack_published_url": "https://substack.com/@username/note/c-123456789",
  "x_article_published_url": "https://x.com/i/article/1234567890",
  "x_post_published_at": "2025-01-20T14:00:05Z",
  "linkedin_post_published_at": "2025-01-20T14:00:08Z",
  "mastodon_post_published_at": "2025-01-20T14:00:10Z",
  "threads_post_published_at": "2025-01-20T14:00:12Z",
  "bluesky_post_published_at": "2025-01-20T14:00:15Z",
  "substack_post_published_at": "2025-01-20T14:00:15Z",
  "x_article_published_at": "2025-01-20T14:00:15Z",
  "scratchpad_text": "line 1\nline 2\n\nline 4"
}