Skip to content
Wahlu API

Drafts, History and planning

Read brand activity and safely manage drafts, Autopilot ideas and held schedules.

These actions use the workspace and brand access on your API key. Every item must belong to the brand in the path. Start with a read, show the proposed change, then ask the user before a write. The production MCP tools and CLI use these same routes.

List drafts

GET/v1/brands/:brand_id/drafts

Requires posts:read. Returns up to 50 unused drafts, newest first, in data.items. Each item has its ID, name, caption preview (up to 280 characters), media count, thumbnail, account IDs and last update time. Add ?label=label_id to return only drafts with that label. Use an ID from the brand labels endpoint. Filtering happens before the 50-draft limit.

Edit or delete an unused draft

PATCH/v1/brands/:brand_id/drafts/:draft_id
DELETE/v1/brands/:brand_id/drafts/:draft_id

Requires posts:write. Both actions need confirm_draft_idin the JSON body, matching the path ID, and an idempotency key. Editing acceptsname (1 to 200 characters), caption (up to 20,000 characters), or both. An empty caption clears it. Caption edits require a single shared caption; edit separate platform copy in Wahlu. Media stays unchanged.

Scheduled, queued or published content cannot be edited or deleted here. Deleting a draft keeps its media and never removes a post from a social account.

Edit one draft
curl -X PATCH "https://api.wahlu.com/v1/brands/brand_123/drafts/draft_123" \
  -H "Authorization: Bearer $WAHLU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: autumn-draft-edit-1" \
  -d '{"confirm_draft_id":"draft_123","name":"Autumn launch"}'

Read History

GET/v1/brands/:brand_id/history

Requires publications:read. Send limit (1 to 50, default 20) and page (starting at 1). The result has items andhas_more. Each item includes its platform, post name, status and dates.permalink_url is a safe public post link, or null when no link is available. This does not fetch engagement data from a social platform.

Read Link in bio

GET/v1/brands/:brand_id/bio
GET/v1/brands/:brand_id/bio/stats

Both require posts:read. The page read returns data.pagewith the handle, draft and published page, or null if none exists. The stats read accepts days=7 (default) or days=28 and returns views, visitors and link click counts. These routes never edit or publish the page.

Find the active Autopilot plan

GET/v1/brands/:brand_id/autopilot/plan

Requires posts:read. Returns data.plan with the active plan ID, status and up to 100 recent week numbers, or null when none exists.has_more_weeks reports whether older weeks exist. This read creates nothing and starts no generation.

Read an Autopilot week

GET/v1/brands/:brand_id/autopilot/weeks/:week_number

Requires posts:read and a plan_id query parameter. Use the plan ID and a week number from the active-plan read above. The result includes the plan ID, week, status, theme and items. Each item includes its topic, review status and any content or schedule ID. It creates no plan, draft or schedule.

Approve or regenerate an Autopilot idea

POST/v1/brands/:brand_id/autopilot/weeks/:week_number/items/:item_id/approve
POST/v1/brands/:brand_id/autopilot/weeks/:week_number/items/:item_id/regenerate

Both require a paid plan, posts:write, an idempotency key and a JSON body with plan_id and confirm_item_id. The confirmation must match the path. Approval marks an idea as approved; it does not queue generation, approve a schedule or publish a post.

Any schedule later generated from that idea is held as pending_review, even with auto-approval on. A person must approve it in Wahlu, or use the held-schedule approval route with schedule:write and publish:execute.

Regeneration replaces one unused topic and needs a paid plan. Optional guidance can contain up to 2,000 characters. It does not generate Studio images or videos. If the result is uncertain, the same key cannot start a second regeneration. Read the week before deciding what to do next.

Read notifications

GET/v1/brands/:brand_id/notifications

Requires notifications:read. Returns only notifications visible to the key owner for this brand. Send limit (1 to 50, default 20),filter=all (default) or filter=unread, and the returnednext_cursor as cursor for the next page. Items contain the type, category, title, message, read state and date. Reading never marks an alert as read.

Approve a held schedule

POST/v1/brands/:brand_id/schedules/:schedule_id/approve

Requires schedule:write and publish:execute. Sendconfirm_schedule_id in the JSON body and an idempotency key. Only a future held API or Autopilot schedule can be approved. Wahlu checks current publishing access and readiness. Approval lets the normal pipeline publish the post at its set time.

Move a schedule to drafts

POST/v1/brands/:brand_id/schedules/:schedule_id/move-to-draft

Requires schedule:write and posts:write. Sendconfirm_schedule_id and an idempotency key. Removes an unsent schedule and keeps its content as a draft. It fails if execution has started or another use remains.

Delete a schedule

DELETE/v1/brands/:brand_id/schedules/:schedule_id

Requires schedule:write. Send confirm_schedule_id in the JSON body and an idempotency key. Deletes only an unsent schedule before execution starts. Its content and media remain. This never deletes a post from a social platform.

Write responses and retries

Send the key in Idempotency-Key or the body fieldidempotency_key. If both are present, they must match. Each new write above returns 200 with the resource id and an outcome: updated, deleted, approved, moved_to_draft or regenerated. A replay keeps the original outcome and adds Idempotency-Replayed: true. Reusing a key with different input fails. All responses retain the request ID in meta.request_id.

Studio generation, Insights, comment-to-DM and Link in bio editing are not exposed.