{"openapi":"3.1.0","info":{"title":"Postlane API","version":"1.5.0","description":"Public REST API for Postlane. Authenticate with an API key from Settings › API (`Authorization: Bearer tddy_…`). Writes accept an `Idempotency-Key` header. Rate limit: 60 req/min per key. Keys carry scopes (read/publish/community/manage/ads) and a mode: review-mode keys queue agent posts as pending_approval for a human."},"servers":[{"url":"https://vhludoussbmvvjxtywwm.supabase.co/functions/v1/api-v1"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer"}}},"paths":{"/account":{"get":{"summary":"Workspace, plan, limits and current usage (scope: read)","security":[{"apiKey":[]}]}},"/channels":{"get":{"summary":"List connected channels (scope: read)","security":[{"apiKey":[]}]}},"/posts":{"get":{"summary":"List posts (filters: status, q, limit, offset) (scope: read)","security":[{"apiKey":[]}]},"post":{"summary":"Create a post: draft | scheduled (needs scheduled_at) | pending_approval. Body: content, channel_ids[], scheduled_at?, status?, first_comment?, media[{url,type}]?, tag_ids[]? (scope: publish)","security":[{"apiKey":[]}]}},"/posts/{id}":{"get":{"summary":"Get one post with channels, media, tags and its latest publish job (error included if it failed) (scope: read)","security":[{"apiKey":[]}]},"patch":{"summary":"Edit an editable post: content, first_comment, scheduled_at, status, channel_ids[], tag_ids[] (replaces tags) (scope: publish)","security":[{"apiKey":[]}]},"delete":{"summary":"Delete a post (never sent/publishing; review keys only draft/pending_approval) (scope: publish)","security":[{"apiKey":[]}]}},"/posts/{id}/publish":{"post":{"summary":"Publish NOW: queues the post for immediate publication (runner sends it within ~2 min). Review-mode keys get pending_approval instead (scope: publish)","security":[{"apiKey":[]}]}},"/posts/{id}/approve":{"post":{"summary":"Approve a pending_approval post → scheduled (body.scheduled_at optional; defaults to now = publish asap). Review-mode keys cannot approve (scope: manage)","security":[{"apiKey":[]}]}},"/posts/{id}/reject":{"post":{"summary":"Reject a pending_approval post → back to draft (body.note optional) (scope: manage)","security":[{"apiKey":[]}]}},"/media":{"post":{"summary":"Upload media to the public bucket. Body: { url } OR { data_base64, content_type }. Returns a public URL to use in posts. Max 25 MB (scope: publish)","security":[{"apiKey":[]}]}},"/ideas":{"get":{"summary":"List ideas (scope: read)","security":[{"apiKey":[]}]},"post":{"summary":"Create an idea { title, content?, emoji? } (scope: manage)","security":[{"apiKey":[]}]}},"/ideas/{id}":{"patch":{"summary":"Edit an idea: title, content, emoji, status (scope: manage)","security":[{"apiKey":[]}]},"delete":{"summary":"Delete an idea (scope: manage)","security":[{"apiKey":[]}]}},"/tags":{"get":{"summary":"List org tags (scope: read)","security":[{"apiKey":[]}]},"post":{"summary":"Create a tag { name, color? } (scope: manage)","security":[{"apiKey":[]}]}},"/posting-slots":{"get":{"summary":"Preferred posting slots per channel (dow 0-6, slot_time) — the workspace's chosen best times (scope: read)","security":[{"apiKey":[]}]}},"/metrics":{"get":{"summary":"Daily channel metrics rows (channel_id?, from?, to?) (scope: read)","security":[{"apiKey":[]}]}},"/post-metrics":{"get":{"summary":"Per-published-post performance (impressions, reach, likes, comments, engagement, permalink). Filters: channel_id?, limit? (scope: read)","security":[{"apiKey":[]}]}},"/analytics/summary":{"get":{"summary":"Aggregated KPIs per channel + totals over the last N days (days?, default 30) (scope: read)","security":[{"apiKey":[]}]}},"/conversations":{"get":{"summary":"List community-inbox conversations (status?, limit?) (scope: read)","security":[{"apiKey":[]}]}},"/conversations/{id}":{"get":{"summary":"Get a conversation with its messages (scope: read)","security":[{"apiKey":[]}]},"patch":{"summary":"Update conversation status: open | assigned | resolved | snoozed | replied (scope: community)","security":[{"apiKey":[]}]}},"/conversations/{id}/reply":{"post":{"summary":"Reply on the native platform { message } (scope: community)","security":[{"apiKey":[]}]}},"/conversations/{id}/like":{"post":{"summary":"Like/unlike the comment on the origin network { liked? } (twitter, facebook, mastodon, bluesky) (scope: community)","security":[{"apiKey":[]}]}},"/conversations/{id}/hide":{"post":{"summary":"Hide/unhide the comment on the origin network { hidden? } (instagram, facebook, youtube, twitter, threads) (scope: community)","security":[{"apiKey":[]}]}},"/saved-replies":{"get":{"summary":"List the workspace's saved replies (canned responses) (scope: read)","security":[{"apiKey":[]}]}},"/approvals":{"get":{"summary":"List post approvals (scope: read)","security":[{"apiKey":[]}]}},"/brand-profile":{"get":{"summary":"The workspace's AI brand profile (voice, tone ranges, required/avoid rules, objectives) — use it to write on-brand content (scope: read)","security":[{"apiKey":[]}]}},"/reports":{"get":{"summary":"List saved analytics reports (id, name, definition) (scope: read)","security":[{"apiKey":[]}]}},"/report-schedules":{"get":{"summary":"List scheduled report deliveries (frequency, recipients, next_run) (scope: read)","security":[{"apiKey":[]}]}},"/members":{"get":{"summary":"List workspace members (name, email, role) (scope: read)","security":[{"apiKey":[]}]}},"/notifications":{"get":{"summary":"Recent in-app notifications for the workspace (limit?) (scope: read)","security":[{"apiKey":[]}]}},"/webhooks":{"get":{"summary":"List registered outbound webhook endpoints (scope: manage)","security":[{"apiKey":[]}]},"post":{"summary":"Register a webhook { url, events? } → returns the signing secret ONCE. Events: post.published, post.failed (scope: manage)","security":[{"apiKey":[]}]}},"/webhooks/{id}":{"delete":{"summary":"Delete a webhook endpoint (scope: manage)","security":[{"apiKey":[]}]}},"/webhooks/{id}/deliveries":{"get":{"summary":"Recent delivery attempts (status codes/errors) for an endpoint (scope: read)","security":[{"apiKey":[]}]}},"/ads/goals":{"get":{"summary":"Paid-ads goals: metric targets ({ list: [{ id: reporting metric id, op, value }] }) + legacy roas/cpa/monthlyBudget (scope: ads|read)","security":[{"apiKey":[]}]},"put":{"summary":"Replace the paid-ads goals. Body: { list: [{ id, op: '>='|'<=', value }], alertPct? } — ids are the SAME metric ids as Reporting (scope: ads)","security":[{"apiKey":[]}]}},"/ads/caps":{"get":{"summary":"Per-network spend caps (scope: ads|read)","security":[{"apiKey":[]}]},"put":{"summary":"Set one network's spend cap { provider: meta|google|tiktok|linkedin, amount, period?: daily|weekly|monthly, alert_pct? } (scope: ads)","security":[{"apiKey":[]}]}},"/ads/automations":{"get":{"summary":"List paid-ads automations (simple rules and node/edge workflows) (scope: ads|read)","security":[{"apiKey":[]}]},"post":{"summary":"Create an automation { name, kind: rule|workflow, definition, provider?, scope?, frequency?, enabled? }. Rule definition: { conditions: [{metric,op,value,goal?}], match, action: {type,budget?,pct?}, requireApproval? }. kind 'workflow': a DIRECTED GRAPH in definition {nodes,edges}. Each node has a unique _id + type: trigger{source} (exactly one), condition{field,op,value,goal?} (passes its out-edge only when true), branch{field,op,value,goal?} (follows edges with port 'then' when true / 'else' when false), delay{amount,unit}, action{action,p}. edges:[{from:_id,to:_id,port?}] (port defaults 'out'; omit edges to auto-chain nodes in order). Fields: roas|cpa|cpc|cpm|ctr|cvr|spend|revenue|conversions|frequency|fatigue|provider|objective|status; goal:true compares to the live ad goal. Executable actions: pause_campaign,resume_campaign,duplicate,set_budget{eur},increase_budget{pct,max},decrease_budget{pct,min},sync,archive,notify{msg},webhook_out{url}. The server validates+normalizes the graph (assigns missing _id, auto-chains when no edges) and returns warnings; invalid graphs are rejected with a clear error. (scope: ads)","security":[{"apiKey":[]}]}},"/ads/automations/{id}":{"patch":{"summary":"Update an automation; body { enabled } alone toggles it (scope: ads)","security":[{"apiKey":[]}]},"delete":{"summary":"Delete an automation (scope: ads)","security":[{"apiKey":[]}]}},"/ads/automations/{id}/runs":{"get":{"summary":"Execution history for one automation (limit?) (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/automation-runs":{"get":{"summary":"Execution history across all automations (limit?) (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/campaigns":{"get":{"summary":"List paid campaigns with KPIs (spend, ROAS, CTR, conversions) (scope: ads|read)","security":[{"apiKey":[]}]},"post":{"summary":"Create a campaign DRAFT with full config { name, provider, objective, budget, budgetType, start?, end?, locations?, ageMin?, ageMax?, gender?, placements?, primaryText?, headline?, cta?, url?, imageUrl? } (scope: ads)","security":[{"apiKey":[]}]}},"/ads/campaigns/{id}":{"get":{"summary":"Get one campaign (scope: ads|read)","security":[{"apiKey":[]}]},"patch":{"summary":"Update a campaign's config (scope: ads)","security":[{"apiKey":[]}]},"delete":{"summary":"End (archive) a campaign in the workspace (scope: ads)","security":[{"apiKey":[]}]}},"/ads/campaigns/{id}/action":{"post":{"summary":"Platform action { action: pause|resume|set_budget|adjust_budget|duplicate, budget?, pct? } — executes on the ad network (scope: ads)","security":[{"apiKey":[]}]}},"/ads/campaigns/{id}/launch":{"post":{"summary":"Launch the draft natively (real Meta campaign+adset+creative+ad; other networks stay draft). Body { launch?: bool } — false creates it paused (scope: ads)","security":[{"apiKey":[]}]}},"/ads/boost":{"post":{"summary":"Promote published organic posts as ads { posts: [{ platform, external_id, permalink?, caption? }], objective?, budget?, budget_type?, locations?, age_min?, age_max?, gender?, url?, launch? } (scope: ads)","security":[{"apiKey":[]}]}},"/ads/sync":{"post":{"summary":"Refresh campaigns + daily metrics from the connected ad networks now { provider?, include_creatives? } (scope: ads)","security":[{"apiKey":[]}]}},"/ads/metrics":{"get":{"summary":"Daily paid-ads metric rows (days?, provider?) (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/creatives":{"get":{"summary":"Synced ad creatives + system recommendations (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/approvals":{"get":{"summary":"Pending ads approval queue (from automations that require approval) (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/approvals/{id}/decide":{"post":{"summary":"Approve/reject a queued action { approve: bool } — approving executes it on the network (scope: ads)","security":[{"apiKey":[]}]}},"/ads/accounts":{"get":{"summary":"Connected ad accounts per network (status, currency, connected) (scope: ads|read)","security":[{"apiKey":[]}]}},"/ads/accounts/{id}/disconnect":{"post":{"summary":"Disconnect an ad account (deletes stored credentials) (scope: ads)","security":[{"apiKey":[]}]}}}}