Workflows

Six patterns that combine the composer, the API, the CLI and the agent connector into something worth having. Every command here runs against the real API.

Fan-out

Same post, every brand

One announcement to six workspaces without opening six tabs.

Compose once, select every channel across the workspace, and publish. One post counts once against the plan no matter how many channels it reaches — that is what per-workspace pricing means in practice. For several workspaces, loop the API over the workspace keys you hold.

for WS in wf_live_aaa wf_live_bbb wf_live_ccc; do
  curl -s -X POST https://api.postwharf.com/v1/posts \
    -H "Authorization: Bearer $WS" -H "Content-Type: application/json" \
    -d '{"text":"Doors open Monday.","channels":["ch_..."]}'
done
Agents

Draft with an agent, approve yourself

Let Claude write the variants; keep the publish decision.

Register the MCP connector, then ask for scheduled posts rather than published ones. Scheduling is reversible right up to the slot, so the approval step costs a glance instead of a retraction.

claude mcp add --transport http wharf https://mcp.postwharf.com/mcp \
  --header "Authorization: Bearer $POSTWHARF_KEY"

# then, in the conversation:
"Draft three variants of this, respect each network's limit,
 and queue them for Tuesday 9am. Show me before you do."
Automation

Publish from CI when you tag a release

A release note goes out when the tag lands, not when someone remembers.

The API is a single HTTP call, so any CI runner can publish. Keep the workspace key in the runner's secret store — never in the repository.

- name: Announce the release
  run: |
    curl -s -X POST https://api.postwharf.com/v1/posts \
      -H "Authorization: Bearer ${{ secrets.POSTWHARF_KEY }}" \
      -H "Content-Type: application/json" \
      -d "{\"text\":\"${{ github.ref_name }} is out.\",\"channels\":[\"ch_...\"]}"
Reliability

Get told when a post fails

A failure becomes a message in your inbox rather than a gap in your feed.

Register a webhook and you receive delivery.failed with an action field naming the fix, and channel.token_expiring before a channel goes dark.

curl -X POST https://api.postwharf.com/v1/webhooks \
  -H "Authorization: Bearer $POSTWHARF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hooks/postwharf",
       "events":["delivery.failed","channel.token_expiring"]}'
Reliability

Weekly audit of what actually went out

Reconcile intention against reality once a week, automatically.

Read the event feed and group by cause. This is the check that catches the failure mode a calendar cannot show you: posts that reported success and are not there.

curl -s "https://api.postwharf.com/v1/events?limit=200" \
  -H "Authorization: Bearer $POSTWHARF_KEY" \
| jq -r '.data[] | select(.type=="delivery.failed")
         | [.payload.platform, .payload.action] | @tsv' \
| sort | uniq -c | sort -rn
Migration

Move a brand off another tool

Export, reshape, validate, import — without a week of double-posting.

Export the queue from your current tool, run it through the schedule validator to catch duplicates the export introduced, then create the posts. Keep both tools running for one cycle with the old one paused, not deleted.

# one post per line: YYYY-MM-DD HH:MM channel_id "text"
while IFS=$'\t' read -r when ch text; do
  curl -s -X POST https://api.postwharf.com/v1/posts \
    -H "Authorization: Bearer $POSTWHARF_KEY" -H "Content-Type: application/json" \
    -d "{\"text\":\"$text\",\"channels\":[\"$ch\"],\"publish_at\":\"$when\"}"
done < queue.tsv