{"openapi":"3.1.0","info":{"title":"distribution API","version":"1.25.0","description":"Your own distribution workspace for your agents and systems. Every endpoint takes an API key you create in the workspace (Developers) as Authorization: Bearer <key> and returns exactly what the workspace shows you. Reads are GET. The writes (start a campaign, change its creators, set what its creators read, approve for a payment link) need a key with campaigns:write or plans:approve, an Idempotency-Key header, and act only inside the mandate your brand sets on the key in Developers: its maximum plan total, monthly cap, channels, whether it may sign, its expiry and the brand terms a person accepted for it. A request outside the mandate is refused before any spend with the limit and how much over. Approved creators on sale are listed by name, and a creator's X handle shows once your order for a plan with that creator is paid; not-reviewed, declined and paused creators are never listed (operator decisions 2026-10-08). What bookable means (DT-021): A creator is bookable (on sale) when all of these hold: our team approved the creator after vetting (verified and active); our vetting keeps the creator among those we sell, not flagged as an inactive account and not excluded; and at least one of the creator's formats has a fresh price: a price at most 30 days old, or a price quoted by our team. Every surface counts bookable creators with this one rule (the Creators list's priced, Market's Bookable now, the Overview, the chat, creators_search priced and catalog.priced, GET /api/network/facts and the guest quote), so the same filter shows the same number. An approved creator who is not bookable is still listed, with price on request. Any valid key may send feedback (POST /feedback) when something fails, is missing or could be better; it reaches the team directly. The same reads and writes are tools on the MCP server at /api/mcp. Changelog: 2026-10-19 (1.25.0): inventory (GET /inventory, inventory) and resolve_audience (GET /audience, resolve_audience) carry bookable_nodes on each channel, the creators bookable now by the one bookable rule, the same count as creators_search priced and catalog.priced, never above verified_nodes or the network's; priced_units now counts only those creators' posts on sale at a current price (before, it counted every purchasable post, stale prices included), and the note names bookable creators before posts (DT-021, DT-292). 2026-10-18 (1.24.0): creator views are one pool of 300 a day per workspace, shared by the app and every API key of the brand: a creator view is one different creator shown in a list or opened since midnight UTC, and a creator already seen today, in the app or through any key, is free. Before, the app and the API each counted their own 300, and each key had its own allowance under the brand's ceiling. Past 300 a list, and an open of a creator not yet seen today, answer 429 rate_limited with details.reason daily_seen, details.scope workspace and details.limit 300; Retry-After says when midnight UTC comes. The count is exact: a page served near the end of the pool lists only the creators that fit in it, so total can be larger than the creators returned. The short-window limits are unchanged (20 creator reads a minute and the pause after 40 creators opened in ten minutes), and so are the 60 searches and 60 creators opened a day per key and per brand. 2026-10-18 (1.23.1): the guest MCP door names only the channel on sale now: inventory and resolve_audience list x_creators only, and no channel is announced as next (the 1.21.0 note that the guest's channels are X creators and Reddit no longer holds). 2026-10-18 (1.23.0): an approved creator with nothing on sale is reachable from the API: creator_ask_price (POST /creators/{id}/price-request, scope creators:read, optional body campaign_id) asks our team for its price, the same ask as the app's Ask for a price button, and never contacts the creator. It answers 200 with requested, already (true when an ask was already open, so nothing new was sent), status (requested or priced) and requested_at; 409 conflict reason already_priced for a creator with a format on sale; 404 for any id that is not an approved creator; 429 rate_limited reason daily_limit past 3 asks for one creator or 20 in all in any 24 hours, with retry_after (also the Retry-After header) the seconds until that limit reopens and resets_at the moment it does; 502 when the ask did not reach our team (it is not kept; try again). Opening the creator counts as one creator opened today on the creator meter, free when already opened. Each creator (GET /creators rows and GET /creators/{id}, creators_search and creator_get) carries ask_price: true when nothing is on sale and the action is creator_ask_price, false when a format is on sale. price_estimate.label reads \"Est. $200 to $1,000\", the range joined by to, never a dash. 2026-10-17 (1.22.0): a creator's status value for a creator not yet reviewed is now not_reviewed (Creator.status, DT-272); a campaign a key starts that has no plan yet reads stage_id draft (GET /campaigns, campaign_status) and DELETE /campaigns/{id} deletes it, as for a draft the workspace starts (DT-270); POST /campaigns/{id}/creator-guidelines refuses a body field it does not take with 400 bad_request naming it, and set_creator_guidelines refuses an argument it does not take (DT-269); the RateLimit headers describe the fixed 60-second window (DT-271). 2026-10-17 (1.21.0): the guest MCP door (/api/mcp/guest) answers five of its 6 tools with no key. inventory gives the whole network per channel (no audience applied: approved creators, posts on sale at a current price, strong or thin, and catalog), resolve_audience the fit for a profile you describe (product, audience, geography; intent_id needs an account and answers needs_account), brain_get the empty context a guest has (version 0) with claim, and guest_status lists them in answers_now with the guest limits. plan_quote_guest answers 3 quotes per client address in any 7 days, says quotes_left, and refuses the next with rate_limited (reason guest_quote_limit, limit, window_days, retry_after, resets_at, claim); a call that prices nothing (a bad argument, a format with nothing on sale, a failed read) spends none. feedback_send still needs an account: its guest description says so and a guest call answers 401 with claim. The guest's channels are X creators and Reddit only. 2026-10-17 (1.20.0): a creator's X handle and profile link show only once the brand's order for the plan is paid. Before that, plan_quote (GET /plans/{id}/quote) lines carry creator.name, creator.id and creator_id with creator.handle and creator.profile_url null, and campaign_status (GET /campaigns/{id}) plan lines name no @handle in slot. creator_get (GET /creators/{id}) carries handle and url null, and its recent_posts and past_collabs carry no x.com link (url null); a paid creator's handle is on the paid plan's quote. 2026-10-16 (1.19.0): plan_move_dates (POST /plans/{id}/dates, body start and end as YYYY-MM-DD) moves a plan awaiting approval to new dates in one step: the plan's launch window, the campaign's dates and every creator's post date move together, each post keeping its place in the window and pulled inside a shorter one; prices do not change. Refusals are 409 conflict with reason bad_dates (a start before today, an end before the start, or more than a year apart), same_day (two posts by one creator would fall on one day; nothing moves) or plan_signed (a signed plan or one the team wrote). 2026-10-16 (1.18.0): a creators list that names nothing (GET /creators, creators_search) from a brand with an audience on file now returns that audience's creators (200) instead of 400 filter_required; only a brand with no audience on file is refused with filter_required. Creator lists and searches are limited to an audience whenever one applies: the segments passed in match, else the brand's own audience segments, and a segment named without match replaces the audience as the filter; q, reach_band and the filters narrow it, so total counts only creators that reach that audience. A brand with no audience on file that names only q, reach_band or a filter gets every approved creator those match, with no audience limit. inventory (GET /inventory) counts in x_creators verified_nodes only creators the creator lists can show, the same number as a bare list's total. 2026-10-16 (1.17.0): the guest MCP door (/api/mcp/guest; POST /api/mcp with no key answers 401 with the OAuth sign-in challenge, so a client that supports OAuth signs in there) lists exactly 6 tools, each with a title and its annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint): inventory, resolve_audience, brain_get and feedback_send, which need an account, and two that answer with no key, guest_status (what answers now, what needs an account, and claim) and plan_quote_guest (format post, quote or thread and posts 1 to 50: the all-in price range per post across every creator on sale now, times the posts, never a creator). A guest call to a tool that needs an account answers 401 with the claim link in the message and in error.data.claim (url, developers_url, sign_in, key): sign in at /connect, then create a key in Developers. The workspace's GET /api/keys/usage takes days=7, 30 or 90 (and key_id) and answers requests per UTC day for the whole range (range_days, timezone, days with day, ok and errors, total, errors), a day with no request as zeros and the totals the sum of the days; without days it pages the request log as before. 2026-10-16 (1.16.0): plan_quote (GET /plans/{id}/quote) carries over_budget: budget_cents, total_cents and over_by_cents when the plan is over its campaign's budget, at current prices when a creator's price rose past it (the plan keeps its earlier prices, so total_cents alone read as within the budget, and the quote said nothing); its policy then refuses with reason over_budget. The figures are the whole plan's overage, never the first creator's alone. Null within the budget. 2026-10-16 (1.15.0): creator reads through API keys are metered apart from the app's: each key has its own allowance (20 creator reads a minute, 60 searches a day, 60 creators opened a day and 300 different creators shown a day) and all of a brand's keys together, revoked ones included, share one brand ceiling of the same totals; before, the app, its chat and every key shared one per workspace, so an agent's reads could close the app with 429. A creator 429 carries details.scope, key (this key's allowance) or api (the brand's ceiling over its keys). The 3 new campaigns in 24 hours count every campaign started in the window, so archiving or deleting one no longer gives its slot back (429 rate_limited, details.reason daily_campaign_limit, with resets_at as before). 2026-10-15 (1.14.0): no creator is added to a plan past its campaign's budget, by any key or person: plan_add_creator (POST /plans/{id}/lines, a named plan or current) and plan_swap_creator (POST /plans/{id}/lines/{line_id}/swap) refuse a creator that would take the plan's all-in total over the budget with 409 conflict, reason over_budget, budget_cents, remaining_cents, price_cents and over_by_cents, and the plan is left as it was. A swap for a creator at or under the removed creator's price still goes through on a plan at its budget. A creator's price that rose past the budget is not taken onto the plan: approve_plan answers the same over_budget conflict with the figures at current prices. 2026-10-15 (1.13.1): approve_plan's body (ApproveInput) lists confirm_over_budget_cents again, deprecated and ignored if sent, so a client that still sends it passes the schema; it confirms nothing. 2026-10-15 (1.13.0): a plan over its campaign's budget is never approved, by any key or person: approve_plan (POST /plans/{id}/approve) refuses it with 409 conflict, reason over_budget and over_by_cents, until a creator is removed or the budget is raised. confirm_over_budget_cents is removed from approve_plan and from plan_quote's policy, and is ignored if sent; the mandate's may_exceed_budget is retired and always false. 2026-10-15 (1.12.0): GET /creators and creators_search carry catalog, the whole network's counts whatever the filter (catalog.approved approved creators, catalog.priced of them bookable now), the same numbers the app and the site show; left out when the network cannot be counted. 2026-10-15 (1.11.0): GET /creators and creators_search carry priced, how many of total have something on sale now. 2026-10-15 (1.10.0): every 422 carries details.problems, each a field and a message, the one error shape; details.field is removed from the 422s that carried it (POST /feedback and feedback_send, POST /campaigns/{id}/creator-guidelines and set_creator_guidelines), so read details.problems[].field instead. GET /campaigns answers 400 with details.problems to a parameter it does not take (limit, offset or anything else) or an include_archived that is not true or false; before, such a parameter was ignored. 2026-10-13 (1.9.0): GET /creators and creators_search refuse a list that names nothing to narrow it (no match, segment, q, reach_band or filter) with 400 filter_required; pass at least one. 2026-10-12 (1.8.0): a results item carries previous, the reading before the newest one per metric (views, likes, comments, shares and when it was captured), null with fewer than two readings. 2026-10-12 (1.7.0): a creator carries match_reasons, why it matches (topic, reach with its as-of date, launches posted about, engagement above the median of the creators listed); an evidence and a results item carry still_up, the first reading on or after day 7 that shows the post stayed up. 2026-10-12 (1.6.0): each quote line (plan_quote, GET /plans/{id}/quote) carries stage_id and stage, the same post stage model as a campaign's lines_by_stage, and creator_id beside creator.id; brand_terms carries current_number and accepted_number_for_this_key (the version number the app shows, version 3), and the terms resource carries number; creator_get takes creator_id again as another name for id (it was renamed id in 1.4.0 with no note here); a 403 that is not about the key's scope (mandate_refused, for one) no longer carries WWW-Authenticate insufficient_scope. 2026-10-11 (1.5.1): a quote line's creator carries its id (for creator_get) when known. 2026-10-11 (1.5.0): plan_swap_creator (POST /plans/{id}/lines/{line_id}/swap) replaces one line of a plan with another creator's format in one step, both or neither; the daily campaign limit's resets_at is when it truly reopens (a rolling 24 hours); creator status words now read Not reviewed, Reviewed and Under review. 2026-10-11 (1.4.1): the two view medians have names that say which is which: median_views_30d_network on the creator (all their posts, as the network measures it) and posts_summary.posts_sample_median_views (the held posts only); the old median_views_30d and posts_summary.median_views carry the same numbers, deprecated, until 2027-01-11; GET /campaigns and the MCP campaigns list leave archived campaigns out unless include_archived=true. 2026-10-11 (1.4.0): one version for the API and the MCP server; refresh_failed_at is documented on the creator. 2026-10-10 (1.3.0): a campaign has a stored name, \"<company>, <Goal>, <Month>\" until it is renamed; PATCH /campaigns/{id} (rename_campaign) renames it, the campaign lists carry it as display_name, and create_campaign answers with the budget it stored. 2026-10-10 (1.2.0): a campaign's stage is one of eight fixed values from one stage model (stage_id draft, sent, plan_ready, approved, paid, running, complete, cancelled, and stage the matching label: Draft, Sent, Plan ready, Approved, Paid, Running, Complete, Cancelled); before this, stage was free text, so branch on stage_id, never on the label. Each plan line also carries its post stage (stage_id planned, offered, creator_confirmed, scheduled, live, proof_attached, cancelled, and stage the label), the plan carries lines_by_stage, and the campaigns list carries waits_on_you (approve or pay). A refunded or cancelled order makes the campaign cancelled. Every response carries an x-request-id header (yours echoed when you send one of 8 to 128 letters, digits or . _ : -); quote it when you report a slow or failed call. A write still running after 25 seconds answers 503 with Retry-After: retry it with the same Idempotency-Key for its result."},"servers":[{"url":"https://app.distribution.tech/api/v1"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key from the workspace. Scopes: inventory:read (Network coverage for your audience), audience:read (Audience fit for a campaign or a profile), campaigns:read (Campaigns and where each stands), evidence:read (Proof of each paid post), results:read (Results of each paid post), brain:read (Your company context), creators:read (Approved creators on sale, by name, with price per format), campaigns:write (Start campaigns and change the creators on a plan, within its mandate), plans:approve (Sign a plan and get its payment link, within its mandate). Rate limit: 60 requests a minute per key."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["bad_request","filter_required","unauthorized","forbidden","not_found","method_not_allowed","rate_limited","unavailable","internal","mandate_refused","conflict","unprocessable","idempotency_conflict","in_progress"]},"message":{"type":"string"},"details":{"type":"object","description":"Machine-readable facts. mandate_refused: reason (no_mandate, mandate_expired, channel_not_allowed, approval_not_allowed, terms_not_accepted, over_max_plan_total, over_monthly_cap, over_budget), limit_cents, requested_cents, over_by_cents, spent_cents, and escalate: true (take it to a person at the brand). conflict: reason; for over_budget on plan_add_creator or plan_swap_creator also budget_cents, remaining_cents (the room the plan had before the creator), price_cents and over_by_cents. unprocessable: problems, each a field and a message."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"ChannelFit":{"type":"object","properties":{"channel":{"type":"string","enum":["x_creators","reddit","clipping"]},"label":{"type":"string"},"sale":{"type":"string","enum":["live","next"]},"level":{"type":"string","enum":["strong","thin","none"]},"verified_nodes":{"type":"integer","description":"Approved creators (or communities, clippers) that reach the audience."},"bookable_nodes":{"type":"integer","description":"Of those, the creators bookable now by the one bookable rule: the same count as creators_search priced and catalog.priced for the same audience, never above the network's."},"priced_units":{"type":"integer","description":"Their posts on sale at a current price: a count of posts, not creators. Bookable creators are counted by creators_search priced and catalog.priced."},"note":{"type":"string"}},"required":["channel","label","sale","level","verified_nodes","bookable_nodes","priced_units","note"],"additionalProperties":false},"Segment":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"],"additionalProperties":false},"Inventory":{"type":"object","properties":{"segments":{"type":"array","items":{"$ref":"#/components/schemas/Segment"}},"unresolved":{"type":"boolean"},"coverage_as_of":{"type":["string","null"],"format":"date-time"},"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelFit"}}},"required":["segments","unresolved","coverage_as_of","channels"],"additionalProperties":false},"AudienceFit":{"type":"object","properties":{"version":{"const":1},"computed_at":{"type":"string","format":"date-time"},"coverage_as_of":{"type":["string","null"],"format":"date-time"},"segments":{"type":"array","items":{"$ref":"#/components/schemas/Segment"}},"regions":{"type":"array","items":{"type":"string"}},"unresolved":{"type":"boolean"},"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelFit"}},"thin":{"type":"boolean"},"summary":{"type":"string"}},"required":["version","computed_at","coverage_as_of","segments","regions","unresolved","channels","thin","summary"],"additionalProperties":false},"CampaignSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string","description":"The campaign's name as the workspace shows it: the product, else the company, shortened; Untitled campaign when neither is set (a plan started from one creator)."},"company":{"type":["string","null"]},"product":{"type":["string","null"]},"objective":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"plan_status":{"type":["string","null"],"enum":["awaiting_approval","approved",null]},"open_change":{"type":"boolean"},"intent_status":{"type":["string","null"],"enum":["draft","ready",null]},"stage_id":{"type":"string","enum":["draft","sent","plan_ready","approved","paid","running","complete","cancelled"],"description":"draft (not sent), sent (no plan yet), plan_ready (a plan waits for approval), approved (signed, not paid), paid (the brand's payment cleared, no post started), running (a post is scheduled, live or delayed), complete (every post has its proof), cancelled (the order was cancelled or refunded)."},"stage":{"type":"string","enum":["Draft","Sent","Plan ready","Approved","Paid","Running","Complete","Cancelled","Archived"]},"waits_on_you":{"type":"boolean","description":"The campaign needs the brand: approve its plan, or pay its signed plan. A draft is never counted."},"refunded_at":{"type":["string","null"],"format":"date-time","description":"When the order was refunded; null unless it was (the workspace shows Cancelled, refunded on this date)."},"archived_at":{"type":["string","null"],"format":"date-time","description":"When the brand archived the campaign; null for a live one. An archived campaign's stage reads Archived, and renaming it or setting its creator guidelines is refused (409 conflict, reason archived)."}},"required":["id","display_name","company","product","objective","created_at","plan_status","open_change","intent_status","stage_id","stage","waits_on_you","refunded_at","archived_at"],"additionalProperties":false},"Campaigns":{"type":"object","properties":{"campaigns":{"type":"array","items":{"$ref":"#/components/schemas/CampaignSummary"}}},"required":["campaigns"],"additionalProperties":false},"CampaignStatus":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"campaign":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"refunded_at":{"type":["string","null"],"format":"date-time","description":"When the order was refunded; null unless it was."},"archived_at":{"type":["string","null"],"format":"date-time","description":"When the brand archived the campaign; null for a live one. An archived campaign's stage reads Archived, and renaming it or setting its creator guidelines is refused (409 conflict, reason archived)."},"intent_status":{"type":["string","null"],"enum":["draft","ready",null]},"plan_status":{"type":["string","null"],"enum":["awaiting_approval","approved",null]},"open_change":{"type":"boolean"},"stage":{"type":"string","enum":["Draft","Sent","Plan ready","Approved","Paid","Running","Complete","Cancelled","Archived"]},"stage_id":{"type":"string","enum":["draft","sent","plan_ready","approved","paid","running","complete","cancelled"],"description":"draft (not sent), sent (no plan yet), plan_ready (a plan waits for approval), approved (signed, not paid), paid (the brand's payment cleared, no post started), running (a post is scheduled, live or delayed), complete (every post has its proof), cancelled (the order was cancelled or refunded)."},"plan":{"oneOf":[{"type":"null"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"status":{"type":"string","enum":["awaiting_approval","approved"]},"launch_window_start":{"type":"string","format":"date"},"launch_window_end":{"type":"string","format":"date"},"currency":{"type":"string"},"sent_at":{"type":["string","null"],"format":"date-time"},"approved_at":{"type":["string","null"],"format":"date-time"},"total_cents":{"type":"integer"},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string","description":"Usually one of x_creators, reddit, clipping, linkedin, ugc, newsletter, podcast, other; read channel_label for display."},"channel_label":{"type":"string"},"slot":{"type":"string"},"scheduled_date":{"type":"string","format":"date"},"price_cents":{"type":"integer"},"status":{"type":"string","enum":["planned","booked","live","completed","blocked","cancelled"]},"stage_id":{"type":"string","enum":["planned","offered","creator_confirmed","scheduled","live","proof_attached","cancelled"],"description":"planned (no proposal out), offered (a creator has the proposal), creator_confirmed (accepted, date not booked yet), scheduled (booked, or booked and delayed), live, proof_attached (the still-up proof is recorded), cancelled (the line, or its order, was cancelled or refunded)."},"stage":{"type":"string","enum":["Planned","Offered","Creator confirmed","Scheduled","Live","Proof attached","Cancelled"]},"proposal":{"type":["object","null"],"description":"Set once the order is paid: sending (going to the creator), sent (the creator has it, 48 hours to answer), accepted, declined or no_reply (the next match is being found), unfilled (no other approved creator fits at the paid price yet). replaced_handle names the creator this one replaced.","properties":{"state":{"type":"string","enum":["sending","sent","accepted","declined","no_reply","unfilled"]},"creator_handle":{"type":"string"},"replaced_handle":{"type":["string","null"]},"updated_at":{"type":["string","null"],"format":"date-time"}},"required":["state","creator_handle","replaced_handle","updated_at"],"additionalProperties":false}},"required":["id","channel","channel_label","slot","scheduled_date","price_cents","status","stage_id","stage","proposal"],"additionalProperties":false}},"lines_by_status":{"type":"object","additionalProperties":{"type":"integer"}},"lines_by_stage":{"type":"object","properties":{"planned":{"type":"integer"},"offered":{"type":"integer"},"creator_confirmed":{"type":"integer"},"scheduled":{"type":"integer"},"live":{"type":"integer"},"proof_attached":{"type":"integer"},"cancelled":{"type":"integer"}},"required":["planned","offered","creator_confirmed","scheduled","live","proof_attached","cancelled"],"additionalProperties":false}},"required":["id","version","status","launch_window_start","launch_window_end","currency","sent_at","approved_at","total_cents","lines","lines_by_status","lines_by_stage"],"additionalProperties":false}]},"order":{"oneOf":[{"type":"null"},{"type":"object","properties":{"payment_state":{"type":"string"},"total_cents":{"type":"integer"},"currency":{"type":"string"},"signed_at":{"type":"string","format":"date-time"},"paid_at":{"type":["string","null"],"format":"date-time"}},"required":["payment_state","total_cents","currency","signed_at","paid_at"],"additionalProperties":false}]},"creator_guidelines":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CreatorGuidelines"}]}},"required":["id","campaign","created_at","refunded_at","archived_at","intent_status","plan_status","open_change","stage","stage_id","plan","order","creator_guidelines"],"additionalProperties":false},"CreatorGuidelines":{"type":"object","properties":{"pitch":{"type":"string","maxLength":800,"description":"What the post should get across. Empty when not set."},"key_messages":{"type":"array","items":{"type":"string","maxLength":200}},"references":{"type":"array","items":{"type":"string","format":"uri","maxLength":500}},"voice":{"type":"string","maxLength":300},"dos":{"type":"array","items":{"type":"string","maxLength":200}},"donts":{"type":"array","items":{"type":"string","maxLength":200}}},"required":["pitch","key_messages","references","voice","dos","donts"],"additionalProperties":false},"CreatorGuidelinesInput":{"type":"object","additionalProperties":false,"description":"Every field is optional; a field left out is cleared. Creators read pitch, dos and donts with their proposal and everything once they accept.","properties":{"pitch":{"type":"string","maxLength":800},"key_messages":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":200}},"references":{"type":"array","maxItems":8,"items":{"type":"string","pattern":"^https://","maxLength":500}},"voice":{"type":"string","maxLength":300},"dos":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":200}},"donts":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":200}}}},"GuidelinesSet":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"creator_guidelines":{"$ref":"#/components/schemas/CreatorGuidelines"}},"required":["campaign_id","creator_guidelines"],"additionalProperties":false},"EvidenceItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"brief_id":{"type":"string","format":"uuid","deprecated":true,"x-sunset":"2026-11-10","description":"Deprecated: the same id as campaign_id. Removed on 2026-11-10; read campaign_id."},"campaign":{"type":"string"},"slot":{"type":"string"},"status":{"type":"string","enum":["live","completed"]},"status_label":{"type":"string"},"date":{"type":"string"},"proof_url":{"type":["string","null"]},"published_at":{"type":["string","null"],"format":"date-time"},"disclosure":{"type":["string","null"]},"still_up":{"oneOf":[{"type":"null"},{"type":"object","properties":{"checked_at":{"type":"string","format":"date-time"},"views":{"type":["integer","null"]},"line":{"type":"string"}},"required":["checked_at","views","line"],"additionalProperties":false}],"description":"The first metrics snapshot on or after published_at plus 7 days, the proof the post stayed up (brand terms 8.1). Null while there is none."}},"required":["id","campaign_id","brief_id","campaign","slot","status","status_label","date","proof_url","published_at","disclosure","still_up"],"additionalProperties":false},"Evidence":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EvidenceItem"}}},"required":["items"],"additionalProperties":false},"ResultItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"brief_id":{"type":"string","format":"uuid","deprecated":true,"x-sunset":"2026-11-10","description":"Deprecated: the same id as campaign_id. Removed on 2026-11-10; read campaign_id."},"campaign":{"type":"string"},"slot":{"type":"string"},"scheduled_date":{"type":"string","format":"date"},"date":{"type":"string"},"status":{"type":"string","enum":["live","completed"]},"status_label":{"type":"string"},"proof_url":{"type":["string","null"]},"published_at":{"type":["string","null"],"format":"date-time"},"disclosure":{"type":["string","null"]},"latest":{"oneOf":[{"type":"null"},{"type":"object","properties":{"line":{"type":"string"},"as_of":{"type":"string"},"views":{"type":["integer","null"]},"clicks":{"type":["integer","null"]},"likes":{"type":["integer","null"]},"comments":{"type":["integer","null"]},"shares":{"type":["integer","null"]},"more":{"type":"array","items":{"type":"object","properties":{"line":{"type":"string"},"as_of":{"type":"string"}},"required":["line","as_of"],"additionalProperties":false}}},"required":["line","as_of","views","clicks","more"],"additionalProperties":false}]},"snapshots":{"type":"integer"},"still_up":{"oneOf":[{"type":"null"},{"type":"object","properties":{"checked_at":{"type":"string","format":"date-time"},"views":{"type":["integer","null"]},"line":{"type":"string"}},"required":["checked_at","views","line"],"additionalProperties":false}],"description":"The first metrics snapshot on or after published_at plus 7 days, the proof the post stayed up (brand terms 8.1). Null while there is none."},"previous":{"oneOf":[{"type":"null"},{"type":"object","properties":{"views":{"type":["integer","null"]},"likes":{"type":["integer","null"]},"comments":{"type":["integer","null"]},"shares":{"type":["integer","null"]},"captured_at":{"type":"string","format":"date-time"}},"required":["views","likes","comments","shares","captured_at"],"additionalProperties":false}],"description":"The reading before the newest one (raw values of that snapshot), for the change since it; null with fewer than two readings. Since 1.8.0."},"versus":{"type":"string"},"schedule":{"type":["string","null"]},"channel_label":{"type":"string"},"spend_cents":{"type":["integer","null"]},"currency":{"type":["string","null"]}},"required":["id","campaign_id","brief_id","campaign","slot","scheduled_date","date","status","status_label","proof_url","published_at","disclosure","latest","snapshots","still_up","previous","versus","schedule"],"additionalProperties":false},"Results":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ResultItem"}}},"required":["items"],"additionalProperties":false},"Brain":{"type":"object","properties":{"version":{"type":"integer"},"confirmed_at":{"type":["string","null"],"format":"date-time"},"context":{"type":"object","properties":{"name":{"type":"string"},"summary":{"type":"string"},"audience":{"type":"string"}},"additionalProperties":false},"versions":{"type":"array","items":{"type":"object","properties":{"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}},"required":["version","created_at"],"additionalProperties":false}}},"required":["version","confirmed_at","context","versions"],"additionalProperties":false},"BrainSection":{"type":"object","properties":{"version":{"type":"integer"},"confirmed_at":{"type":["string","null"],"format":"date-time"},"section":{"type":"string","enum":["name","summary","audience"]},"value":{"type":["string","null"]}},"required":["version","confirmed_at","section","value"],"additionalProperties":false},"BrainResponse":{"oneOf":[{"$ref":"#/components/schemas/Brain"},{"$ref":"#/components/schemas/BrainSection"}]},"Offering":{"type":"object","properties":{"unit_id":{"type":"string","format":"uuid"},"format":{"type":"string","enum":["post","quote","thread"]},"label":{"type":"string"},"deliverable":{"type":["string","null"],"description":"One line on what the creator delivers for this format."},"price_cents":{"type":"integer","description":"The one all-in price you pay, when buyable is true. When buyable is false this is the last price on file and is not bookable: a creator's price counts for 30 days, so an older one needs re-confirming (Ask for a price, creator_ask_price or POST /creators/{id}/price-request, asks our team for a current price)."},"buyable":{"type":"boolean","description":"True when this format can be booked now at price_cents: the creator is approved and the price is current (at most 30 days old, or a price our team set). False means price on request until the price is re-confirmed."},"price_as_of":{"type":"string","format":"date"},"expected_views":{"type":["integer","null"]},"cost_per_1k_views_cents":{"type":["integer","null"]},"provenance":{"type":"object","description":"DT-159: where this number came from: source, method, measured_at, expires_at, label (Verified, Creator-reported or Estimated), stale, and as_of text.","properties":{"source":{"type":"string"},"method":{"type":"string"},"measured_at":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"label":{"type":"string","enum":["Verified","Creator-reported","Estimated"]},"stale":{"type":"boolean"},"as_of":{"type":["string","null"]}}},"calc":{"type":"object","description":"How this number was made (DT-117): the calculation version and its inputs, the same on every surface. Never a cost or a fee.","properties":{"calc_version":{"type":"string"},"inputs":{"type":"object"}},"required":["calc_version","inputs"]}}},"PastCollab":{"type":"object","required":["project","role"],"properties":{"project":{"type":"string","description":"The project or brand."},"title":{"type":["string","null"],"description":"The launch's own title, when it says more than the project name."},"date":{"type":["string","null"],"format":"date","description":"When the launch went out."},"role":{"type":"string","enum":["Launch post","Quoted the launch","Paid partnership"],"description":"What the creator did."},"url":{"type":["string","null"],"description":"The creator's post, or the launch post, on X."},"brand":{"type":"object","description":"Who the launch was for (DT-128): the account that posted it. Logo: avatar_url, else the site's favicon, else initials.","properties":{"handle":{"type":["string","null"],"description":"The brand's X handle."},"avatar_url":{"type":["string","null"],"description":"The brand's X avatar (https)."},"site":{"type":["string","null"],"description":"The brand's site as a bare domain."},"initials":{"type":"string","description":"One or two letters for the fallback mark."}}}}},"ListedCollab":{"type":"object","description":"A collaboration in a list row: PastCollab without url (the creator's own post names them; DT-127).","required":["project","role"],"properties":{"project":{"type":"string","description":"The project or brand."},"title":{"type":["string","null"],"description":"The launch's own title, when it says more than the project name."},"date":{"type":["string","null"],"format":"date","description":"When the launch went out."},"role":{"type":"string","enum":["Launch post","Quoted the launch","Paid partnership"],"description":"What the creator did."},"brand":{"type":"object","description":"Who the launch was for, without a handle (a list names no X account): avatar_url, else the site's favicon, else initials.","properties":{"avatar_url":{"type":["string","null"]},"site":{"type":["string","null"]},"initials":{"type":"string"}}}}},"Creator":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"handle":{"type":["string","null"],"description":"Null in every creator read: a creator is named before payment, and its X handle shows once the brand's order for a plan with that creator is paid, on that plan's quote (plan_quote)."},"name":{"type":["string","null"]},"url":{"type":["string","null"],"description":"Null in every creator read, as handle: the X profile link shows on the paid plan's quote."},"status":{"type":"string","enum":["approved","borderline","not_reviewed","declined"]},"status_label":{"type":"string"},"status_reason":{"type":"string"},"in_automatic_plans":{"type":"boolean"},"match_score":{"type":["integer","null"]},"match_label":{"type":["string","null"]},"on_sale":{"type":"boolean"},"reach_band":{"type":"string","enum":["nano","micro","mid","macro","mega"],"description":"The creator's size by followers, smallest to largest."},"median_views_30d":{"type":["integer","null"],"deprecated":true,"x-sunset":"2027-01-11","description":"Deprecated: the same number as median_views_30d_network. Removed on 2027-01-11; read median_views_30d_network."},"median_views_30d_network":{"type":["integer","null"],"description":"Median views per post over the creator's last 30 days, as the network measures it across all their posts. Prices, expected views and format advice use this number. It can differ from posts_summary.posts_sample_median_views, which covers only the posts we hold."},"followers":{"type":["integer","null"],"description":"X followers, as the network last measured them. Null when not measured."},"verified_badge":{"type":["boolean","null"],"description":"Whether the account carries the X blue check. Null when unknown."},"country":{"type":["string","null"],"description":"The country or region X shows on the account's About panel. Null when X shows none; never inferred."},"language":{"type":["string","null"],"description":"The language the creator posts in, as a name (for example English). Null when unknown."},"segments":{"type":"array","items":{"type":"string"}},"bio":{"type":["string","null"]},"positioning":{"type":["string","null"],"description":"One line on who the creator is, taken from their own bio (never written by us); null when the bio has none."},"avatar_url":{"type":["string","null"]},"ask_price":{"type":"boolean","description":"true when nothing is on sale for this creator: the action is Ask for a price (creator_ask_price, POST /creators/{id}/price-request), which asks our team, never the creator; price_estimate is an estimate, never a price. false when a format is on sale: add it from offerings with plan_add_creator."},"price_estimate":{"type":["object","null"],"description":"For a creator with nothing on sale: an estimated price range from its metrics (the ERP's suggested budget band), never a price; null when it has a price. Ask for a price (creator_ask_price, POST /creators/{id}/price-request) asks our team for a real one; the creator is never contacted directly.","properties":{"min_usd":{"type":"integer"},"max_usd":{"type":"integer"},"label":{"type":"string","description":"As the app shows it, e.g. \"Est. $1,200 to $2,500\" (\"to\", never a dash)."},"provenance":{"type":"object","description":"DT-159: where this number came from: source, method, measured_at, expires_at, label (Verified, Creator-reported or Estimated), stale, and as_of text.","properties":{"source":{"type":"string"},"method":{"type":"string"},"measured_at":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"label":{"type":"string","enum":["Verified","Creator-reported","Estimated"]},"stale":{"type":"boolean"},"as_of":{"type":["string","null"]}}},"calc":{"type":"object","description":"How this number was made (DT-117): the calculation version and its inputs, the same on every surface. Never a cost or a fee.","properties":{"calc_version":{"type":"string"},"inputs":{"type":"object"}},"required":["calc_version","inputs"]}},"required":["min_usd","max_usd","label","calc"]},"engagement_rate_30d":{"type":["number","null"]},"posts_per_week":{"type":["number","null"]},"match_reasons":{"type":"array","description":"Why this creator (row 7858), each from a number the network holds: topic (the brand's segments the creator posts about; a topic match, not audience overlap), reach (median views a post over 30 days, with its as-of date), past_launches (launches posted about), engagement (only when above the median of the creators listed). Empty when none can be said; never a price.","items":{"type":"object","properties":{"kind":{"type":"string","enum":["topic","reach","past_launches","engagement"]},"text":{"type":"string"}},"required":["kind","text"],"additionalProperties":false}},"past_collabs":{"type":"array","description":"Launches the creator posted or quoted among the launches the network tracks, newest first (at most 12), then detected paid partnerships. An empty list means none was found in the launches we track, not that the creator never worked with a brand.","items":{"$ref":"#/components/schemas/PastCollab"}},"recent_posts":{"type":"array","description":"The creator's own posts with their numbers, newest first: up to 30 from the last 30 days for an approved creator.","items":{"type":"object"}},"posts_summary":{"type":["object","null"],"description":"posts_sample_median_views is the median over the posts in recent_posts only (at most 30 held posts), so it can differ from median_views_30d_network, which covers all the creator's posts. Counted from recent_posts: null unless 3 or more dated posts fall in the 30 days up to as_of. A summary of their posts; top_post.excerpt quotes the creator's own post.","properties":{"posts":{"type":"integer"},"window_days":{"type":"integer"},"capped":{"type":"boolean","description":"true when we hold the most posts we keep (30), so there may be more"},"median_views":{"type":["integer","null"],"deprecated":true,"x-sunset":"2027-01-11","description":"Deprecated: the same number as posts_sample_median_views. Removed on 2027-01-11."},"posts_sample_median_views":{"type":["integer","null"],"description":"Median views over the held posts in the window that carry a view count."},"top_post":{"type":["object","null"],"properties":{"url":{"type":["string","null"],"description":"Null in a creator read: no x.com link before payment."},"views":{"type":"integer"},"excerpt":{"type":["string","null"]}}},"recurring":{"type":"array","items":{"type":"string"}},"latest_at":{"type":"string","format":"date-time"},"as_of":{"type":"string","format":"date-time","description":"The end of the 30-day window: when the posts were last synced"}}},"offerings":{"type":"array","items":{"$ref":"#/components/schemas/Offering"}},"synced_at":{"type":["string","null"],"format":"date-time","description":"When the creator's profile and posts were last synced (ISO 8601). Null when unknown."},"refresh_failed_at":{"type":["string","null"],"format":"date-time","description":"When the last nightly refresh of this creator failed (ISO 8601); null when the last refresh worked or none has run. The figures then stay as of synced_at."},"advice":{"type":"object","properties":{"recommended":{"type":["string","null"],"enum":["post","quote",null]},"reason":{"type":"string"}}}}},"Creators":{"type":"object","properties":{"total":{"type":"integer","description":"How many creators this answer lists: the shortlist, never a count of the network."},"priced":{"type":"integer","description":"How many of total are bookable now by the one rule in the API description (What bookable means); the rest carry price_estimate, never a price."},"catalog":{"type":"object","description":"The whole network, whatever this call filtered: the same counts as the app and the site (GET /api/network/facts on the app host), refreshed at most every five minutes. Left out when the network cannot be counted right now, never guessed.","required":["approved","priced"],"properties":{"approved":{"type":"integer","minimum":0,"description":"Every approved, verified, active creator in the network, priced or not."},"priced":{"type":"integer","minimum":0,"description":"Of those, the creators bookable now by the one rule in the API description (What bookable means): the number the app and the site show."}}},"cap":{"type":"integer","description":"How many creators the selection holds (the same as total)."},"limit":{"type":"integer","description":"This page's size: default 24, at most 50."},"offset":{"type":"integer","description":"Where this page starts, at most total (an offset past the end is answered as total); the next page starts at offset + limit while it is below total."},"creators":{"type":"array","description":"Summary rows, best fits first by score and in the order asked for: no handle, link or posts. GET /creators/{id} (creator_get) opens one in full.","items":{"$ref":"#/components/schemas/CreatorSummary"}}}},"CreatorSummary":{"type":"object","description":"A creator in a list: the Creator fields without handle, url, recent_posts and posts_summary, and collaborations without their link (DT-127).","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"status":{"type":"string","enum":["approved","borderline","not_reviewed","declined"]},"status_label":{"type":"string"},"status_reason":{"type":"string"},"in_automatic_plans":{"type":"boolean"},"match_score":{"type":["integer","null"]},"match_label":{"type":["string","null"]},"on_sale":{"type":"boolean"},"reach_band":{"type":"string","enum":["nano","micro","mid","macro","mega"],"description":"The creator's size by followers, smallest to largest."},"median_views_30d":{"type":["integer","null"],"deprecated":true,"x-sunset":"2027-01-11","description":"Deprecated: the same number as median_views_30d_network. Removed on 2027-01-11; read median_views_30d_network."},"median_views_30d_network":{"type":["integer","null"],"description":"Median views per post over the creator's last 30 days, as the network measures it across all their posts. Prices, expected views and format advice use this number. It can differ from posts_summary.posts_sample_median_views, which covers only the posts we hold."},"followers":{"type":["integer","null"],"description":"X followers, as the network last measured them. Null when not measured."},"verified_badge":{"type":["boolean","null"],"description":"Whether the account carries the X blue check. Null when unknown."},"country":{"type":["string","null"],"description":"The country or region X shows on the account's About panel. Null when X shows none; never inferred."},"language":{"type":["string","null"],"description":"The language the creator posts in, as a name (for example English). Null when unknown."},"segments":{"type":"array","items":{"type":"string"}},"bio":{"type":["string","null"]},"positioning":{"type":["string","null"],"description":"One line on who the creator is, taken from their own bio (never written by us); null when the bio has none."},"avatar_url":{"type":["string","null"]},"ask_price":{"type":"boolean","description":"true when nothing is on sale for this creator: the action is Ask for a price (creator_ask_price, POST /creators/{id}/price-request), which asks our team, never the creator; price_estimate is an estimate, never a price. false when a format is on sale: add it from offerings with plan_add_creator."},"price_estimate":{"type":["object","null"],"description":"For a creator with nothing on sale: an estimated price range from its metrics (the ERP's suggested budget band), never a price; null when it has a price. Ask for a price (creator_ask_price, POST /creators/{id}/price-request) asks our team for a real one; the creator is never contacted directly.","properties":{"min_usd":{"type":"integer"},"max_usd":{"type":"integer"},"label":{"type":"string","description":"As the app shows it, e.g. \"Est. $1,200 to $2,500\" (\"to\", never a dash)."},"provenance":{"type":"object","description":"DT-159: where this number came from: source, method, measured_at, expires_at, label (Verified, Creator-reported or Estimated), stale, and as_of text.","properties":{"source":{"type":"string"},"method":{"type":"string"},"measured_at":{"type":["string","null"]},"expires_at":{"type":["string","null"]},"label":{"type":"string","enum":["Verified","Creator-reported","Estimated"]},"stale":{"type":"boolean"},"as_of":{"type":["string","null"]}}},"calc":{"type":"object","description":"How this number was made (DT-117): the calculation version and its inputs, the same on every surface. Never a cost or a fee.","properties":{"calc_version":{"type":"string"},"inputs":{"type":"object"}},"required":["calc_version","inputs"]}},"required":["min_usd","max_usd","label","calc"]},"engagement_rate_30d":{"type":["number","null"]},"posts_per_week":{"type":["number","null"]},"match_reasons":{"type":"array","description":"Why this creator (row 7858), each from a number the network holds: topic (the brand's segments the creator posts about; a topic match, not audience overlap), reach (median views a post over 30 days, with its as-of date), past_launches (launches posted about), engagement (only when above the median of the creators listed). Empty when none can be said; never a price.","items":{"type":"object","properties":{"kind":{"type":"string","enum":["topic","reach","past_launches","engagement"]},"text":{"type":"string"}},"required":["kind","text"],"additionalProperties":false}},"past_collabs":{"type":"array","description":"Launches the creator posted or quoted among the launches the network tracks, newest first (at most 12), then detected paid partnerships. An empty list means none was found in the launches we track, not that the creator never worked with a brand.","items":{"$ref":"#/components/schemas/ListedCollab"}},"offerings":{"type":"array","items":{"$ref":"#/components/schemas/Offering"}},"synced_at":{"type":["string","null"],"format":"date-time","description":"When the creator's profile and posts were last synced (ISO 8601). Null when unknown."},"refresh_failed_at":{"type":["string","null"],"format":"date-time","description":"When the last nightly refresh of this creator failed (ISO 8601); null when the last refresh worked or none has run. The figures then stay as of synced_at."},"advice":{"type":"object","properties":{"recommended":{"type":["string","null"],"enum":["post","quote",null]},"reason":{"type":"string"}}},"views_series":{"type":"array","maxItems":30,"items":{"type":"integer","minimum":0,"maximum":100},"description":"The shape of their recent posts' views, oldest first, at most 30 points, each 0 to 100 against the highest (a sparkline, not view counts: those are median_views_30d). A post without a views count is left out; empty when none has one."}}},"Money":{"type":"integer","description":"US cents."},"PaymentOption":{"type":"object","properties":{"rail":{"type":"string","enum":["checkout","invoice"]},"label":{"type":"string"},"clears":{"type":"string"}},"required":["rail","label","clears"],"additionalProperties":false},"Mandate":{"type":["object","null"],"properties":{"key_id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"max_plan_cents":{"type":"integer"},"monthly_cap_cents":{"type":"integer"},"channels":{"type":"array","items":{"type":"string"}},"may_approve":{"type":"boolean"},"may_exceed_budget":{"type":"boolean","deprecated":true,"description":"Retired, always false. No key and no person can approve a plan over its campaign's budget: approve_plan refuses it with over_budget until a creator is removed or the budget is raised."},"expires_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"spent_this_month_cents":{"type":"integer"},"terms_version":{"type":["string","null"],"description":"The brand terms a person accepted for this key. Null on a mandate that may not sign (the terms govern signing) and on the workspace's own agent key."},"terms_accepted_at":{"type":["string","null"],"format":"date-time"},"terms_accepted_email":{"type":["string","null"]}}},"QuoteLine":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"creator":{"oneOf":[{"type":"null"},{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The creator's id, for creator_get. Left out when not known."},"name":{"type":["string","null"]},"handle":{"type":["string","null"],"description":"The creator's X handle once this plan's order is paid; null before (the name shows before payment)."},"profile_url":{"type":["string","null"],"description":"The creator's X profile link once this plan's order is paid; null before."},"avatar_url":{"type":"string","format":"uri","description":"The creator's live profile photo. Left out when there is none."},"followers":{"type":"integer","minimum":0,"description":"The creator's follower count on the channel. Left out when not measured."}},"required":["name","handle","profile_url"],"additionalProperties":false}]},"creator_id":{"type":["string","null"],"format":"uuid","description":"The creator's id at the top level (the same as creator.id); null when not known."},"unit_id":{"type":["string","null"],"format":"uuid"},"stage_id":{"type":"string","enum":["planned","offered","creator_confirmed","scheduled","live","proof_attached","cancelled"],"description":"Where this post stands; the same stage model as a campaign's lines_by_stage. Branch on this, never on stage."},"stage":{"type":"string","description":"The label for stage_id: Planned, Offered, Creator confirmed, Scheduled, Live, Proof attached, Cancelled."},"channel":{"type":"string"},"channel_label":{"type":"string"},"format":{"type":["string","null"]},"deliverable":{"type":"string"},"scheduled_date":{"type":"string","format":"date"},"price_cents":{"type":"integer","description":"The all-in price of this line. Never split into parts."},"vetting":{"type":["string","null"]},"reason":{"type":["string","null"]},"expected_views_low":{"type":["integer","null"]},"expected_views_high":{"type":["integer","null"]},"on_sale":{"type":"boolean"}},"required":["id","creator","creator_id","unit_id","stage_id","stage","channel","channel_label","format","deliverable","scheduled_date","price_cents","vetting","reason","expected_views_low","expected_views_high","on_sale"],"additionalProperties":false},"Quote":{"type":"object","description":"A plan as the person sees it and as an agent signs it (v1-product-spec 8.5 Quote).","properties":{"plan_id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"status":{"type":"string","enum":["awaiting_approval","approved"]},"currency":{"type":"string"},"launch_window_start":{"type":"string","format":"date"},"launch_window_end":{"type":"string","format":"date"},"terms_fingerprint":{"type":"string","description":"Send exactly this to approve. It changes when a line, a price or the dates change."},"total_cents":{"type":"integer"},"totals":{"type":"object","description":"creators, total_cents, views_low, views_high, unmeasured, cpm_low_cents, cpm_high_cents, tiers, budget_cents, remaining_cents."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLine"}},"payment_options":{"type":"array","items":{"$ref":"#/components/schemas/PaymentOption"}},"agent_payment":{"type":"string","enum":["checkout","team_invoice"]},"brand_terms":{"type":"object","properties":{"current_version":{"type":["string","null"],"description":"The current brand terms version id (a date)."},"current_number":{"type":["integer","null"],"description":"The number the app shows for that version (version 3)."},"url":{"type":["string","null"]},"accepted_for_this_key":{"type":["string","null"]},"accepted_number_for_this_key":{"type":["integer","null"]}},"required":["current_version","current_number","url","accepted_for_this_key","accepted_number_for_this_key"],"additionalProperties":false},"mandate":{"$ref":"#/components/schemas/Mandate"},"policy":{"type":"object","description":"allowed: whether this key's mandate lets it sign now; refusal: the reason and numbers when not (over_budget when the plan is over the campaign's budget, which no mandate can approve: remove a creator or have the brand raise the budget).","properties":{"allowed":{"type":"boolean"},"refusal":{"type":["object","null"]}}},"blocked_lines":{"type":"array","items":{"type":"string","format":"uuid"}},"over_budget":{"type":["object","null"],"description":"The plan over its campaign's budget: budget_cents, total_cents and over_by_cents, at current prices when a creator's price rose past the budget (the plan then keeps its earlier prices, so total_cents alone reads as within it). Null within the budget, with no budget, or once signed. Approval refuses it until a creator is removed or the budget is raised.","properties":{"budget_cents":{"type":"integer"},"total_cents":{"type":"integer"},"over_by_cents":{"type":"integer"}}},"order":{"type":["object","null"]},"valid_while":{"const":"terms_fingerprint_unchanged"}}},"CampaignInput":{"type":"object","required":["goal","product","moment","window_start","window_end","budget_usd"],"description":"Left out, audience and company come from your company context (the audience your website read found; with no website read yet, send audience), geography is worldwide and desired_outcome is the goal's usual outcome; the answer's defaults names each field filled. A 422 names every required field that is missing, each in details.problems.","properties":{"goal":{"type":"string","enum":["launch","funding","feature","program"]},"product":{"type":"string","maxLength":2000},"moment":{"type":"string","maxLength":2000,"description":"What goes live and when."},"audience":{"type":"string","minLength":10,"maxLength":2000},"geography":{"type":"string","maxLength":300},"window_start":{"type":"string","format":"date"},"window_end":{"type":"string","format":"date"},"budget_usd":{"type":"integer","minimum":10,"description":"The most to spend, in US dollars. The plan is held to this key's mandate: never above its maximum plan total or what is left of its monthly cap."},"budget_min_usd":{"type":"integer","minimum":1,"description":"The least to spend. Above the mandate's maximum plan total, or what is left of its monthly cap, the campaign is refused (mandate_refused). Left out, the budget is held to the mandate instead of refused."},"desired_outcome":{"type":"string","minLength":5,"maxLength":2000},"company":{"type":"string","maxLength":300},"constraints":{"type":"string","maxLength":2000}}},"CampaignCreated":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["plan_ready","no_plan"]},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Quote"}]},"plan_note":{"type":["string","null"]},"defaults":{"type":"array","items":{"type":"string","enum":["company","audience","geography","desired_outcome"]},"description":"The fields filled because the request left them out."},"budget":{"type":"object","properties":{"min_usd":{"type":["integer","null"]},"max_usd":{"type":["integer","null"]},"held":{"type":"boolean"}},"required":["min_usd","max_usd","held"],"additionalProperties":false,"description":"The budget the campaign was stored with. held is true when budget_usd alone was held lower, to what the mandate allows."}},"required":["campaign_id","status","plan","plan_note"],"additionalProperties":false},"AskPriceInput":{"type":"object","description":"Optional. Send {} or no body to ask from no campaign.","properties":{"campaign_id":{"type":"string","format":"uuid","description":"One of your campaigns this ask is for; the priced answer then shows on that campaign's plan. Another brand's or an unknown id is dropped."}},"additionalProperties":false},"PriceAsked":{"type":"object","properties":{"creator_id":{"type":"string","format":"uuid"},"requested":{"const":true},"already":{"type":"boolean","description":"true: an ask for this creator is still open (an earlier call, or a teammate's click in the app); nothing new was sent. An ask is held for 48 hours: once it is answered or expires, the next call opens a new ask and answers already false."},"status":{"type":"string","enum":["requested","priced"],"description":"requested: our team is pricing it. priced: a price is on the creator now (creator_get offerings) and held for you for 48 hours."},"requested_at":{"type":"string","format":"date-time"},"next":{"type":"string","description":"What happens next, in one sentence."}},"required":["creator_id","requested","already","status","requested_at","next"],"additionalProperties":false},"CampaignArchived":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"archived_at":{"type":"string","format":"date-time"}},"required":["campaign_id","archived_at"],"additionalProperties":false},"CampaignRenamed":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":80}},"required":["campaign_id","name"],"additionalProperties":false},"RenameInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"The new name; spaces are collapsed."}},"required":["name"],"additionalProperties":false},"CampaignDeleted":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"deleted":{"const":true}},"required":["campaign_id","deleted"],"additionalProperties":false},"LineInput":{"type":"object","properties":{"unit_id":{"type":"string","format":"uuid","description":"A format's unit_id from /creators."}},"required":["unit_id"],"additionalProperties":false},"ApproveInput":{"type":"object","properties":{"terms_fingerprint":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"The terms_fingerprint from /plans/{id}/quote."},"confirm_over_budget_cents":{"type":"integer","deprecated":true,"description":"Retired and ignored if sent. No plan over its campaign's budget is approved, so nothing confirms an overage: remove a creator or raise the budget."}},"required":["terms_fingerprint"],"additionalProperties":false},"LineAdded":{"type":"object","properties":{"line_id":{"type":"string","format":"uuid"},"plan":{"$ref":"#/components/schemas/Quote"}},"required":["line_id","plan"],"additionalProperties":false},"LineRemoved":{"type":"object","properties":{"removed_line_id":{"type":"string","format":"uuid"},"plan":{"$ref":"#/components/schemas/Quote"}},"required":["removed_line_id","plan"],"additionalProperties":false},"LineSwapped":{"type":"object","properties":{"line_id":{"type":"string","format":"uuid"},"removed_line_id":{"type":"string","format":"uuid"},"plan":{"$ref":"#/components/schemas/Quote"}},"required":["line_id","removed_line_id","plan"],"additionalProperties":false},"MoveDatesInput":{"type":"object","properties":{"start":{"type":"string","format":"date","description":"The new first day, YYYY-MM-DD, today or later."},"end":{"type":"string","format":"date","description":"The new last day, YYYY-MM-DD, on or after start, at most a year later."}},"required":["start","end"],"additionalProperties":false},"DatesMoved":{"type":"object","properties":{"lines_moved":{"type":"integer","description":"How many creators' post dates moved."},"plan":{"$ref":"#/components/schemas/Quote"}},"required":["lines_moved","plan"],"additionalProperties":false},"Approved":{"type":"object","properties":{"plan_id":{"type":"string","format":"uuid"},"status":{"const":"approved"},"approved_at":{"type":"string","format":"date-time"},"already_signed":{"type":"boolean"},"order":{"type":["object","null"]},"payment":{"type":"object","properties":{"next":{"type":"string","enum":["checkout","invoice_sent","team_invoice","none","retry"]},"pay_url":{"type":["string","null"],"description":"The Stripe Checkout link the brand or its finance person pays."},"options":{"type":"array","items":{"$ref":"#/components/schemas/PaymentOption"}}}}}},"FeedbackContext":{"type":"object","description":"Identifiers only. Any other key is dropped; a url keeps only its origin and path.","properties":{"tool":{"type":"string","maxLength":80},"request_id":{"type":"string","maxLength":120},"url":{"type":"string","maxLength":2000},"error_code":{"type":"string","maxLength":80},"status":{"type":"integer","minimum":100,"maximum":599}}},"FeedbackInput":{"type":"object","properties":{"kind":{"type":"string","enum":["bug","gap","idea","praise","other"],"description":"bug, gap (a missing capability or an empty or wrong field), idea, praise or other."},"title":{"type":"string","minLength":1,"maxLength":200,"description":"One line: what happened or what is missing."},"details":{"type":"string","minLength":1,"maxLength":8000,"description":"What happened (the exact error), how to repeat it, what you expected. Identifiers only: never an API key, a secret or a payload, and never personal data beyond what the user wrote."},"context":{"$ref":"#/components/schemas/FeedbackContext"}},"required":["kind","title","details"],"additionalProperties":false},"FeedbackSent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"notified":{"type":"string","enum":["pending","duplicate","slack","team","not_sent"],"description":"pending: stored and queued for delivery to the team; retried if it fails. duplicate: the same report from this key in the last 15 minutes, nothing new stored or sent. slack, team: where it was delivered. not_sent: stored, delivery failed, and it is retried."},"duplicate":{"type":"boolean","description":"true: the same kind, title and details from your brand in the last 15 minutes; id is that report, nothing new was stored or posted, and it does not count against the hourly limit."}},"required":["id","notified","duplicate"],"additionalProperties":false},"FeedbackItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"source":{"type":"string","enum":["mcp","rest","app_agent","app_ui"]},"kind":{"type":"string","enum":["bug","gap","idea","praise","other"]},"title":{"type":"string"},"details":{"type":"string","description":"Only on a report this key sent."},"context":{"$ref":"#/components/schemas/FeedbackContext"},"status":{"type":"string","enum":["new","triaged","shipped","wont_fix"]},"created_at":{"type":"string","format":"date-time"}},"required":["id","kind","title","status","created_at"],"additionalProperties":false},"FeedbackList":{"type":"object","properties":{"feedback":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackItem"}}},"required":["feedback"],"additionalProperties":false}}},"paths":{"/inventory":{"get":{"summary":"Network coverage for your audience","description":"Scope: inventory:read.","security":[{"apiKey":["inventory:read"]}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inventory"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/audience":{"get":{"summary":"Audience fit for one of your campaigns, or for a profile","description":"Scope: audience:read.","security":[{"apiKey":["audience:read"]}],"parameters":[{"name":"intent_id","in":"query","required":false,"description":"One of your campaigns. Or leave out and send a profile.","schema":{"type":"string","format":"uuid"}},{"name":"product","in":"query","required":false,"schema":{"type":"string","maxLength":500}},{"name":"audience","in":"query","required":false,"schema":{"type":"string","maxLength":500}},{"name":"geography","in":"query","required":false,"schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudienceFit"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No campaign of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns":{"get":{"summary":"Your campaigns and where each stands","description":"Scope: campaigns:read.","security":[{"apiKey":["campaigns:read"]}],"parameters":[{"name":"include_archived","in":"query","required":false,"description":"Archived campaigns are left out unless this is true (DT-135). The only parameter: the list is every campaign, so limit, offset or any other parameter is a 400.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaigns"}}}},"400":{"description":"A parameter this list does not take (limit, offset or any other), or include_archived that is not true or false: details.problems names each one. Since 1.9.0; before, such a parameter was ignored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Start a campaign","description":"From a goal to a priced plan in one call: goal (launch, funding, feature or program), product, moment (what goes live and when), window_start, window_end and budget_usd; optionally audience and company (left out, they come from your company context), geography (worldwide), desired_outcome (the goal's usual outcome), constraints and budget_min_usd. The answer's defaults lists every field it filled. The budget is held to this key's mandate: the plan is built within the smaller of budget_usd, the mandate's maximum plan total and what is left of its monthly cap, and a budget_min_usd above either limit is refused (mandate_refused, over_max_plan_total or over_monthly_cap, with the numbers); with no budget_min_usd the campaign is held to the mandate instead. The campaign is started for the brand exactly as from the workspace and the planner builds the plan from creators on sale now. Returns campaign_id and the plan as plan_quote returns it, or plan_note when nothing on sale fits yet. Needs an idempotency_key; a retry with the same key never starts a second campaign. A brand starts at most 3 campaigns in any 24 hours (rate_limited, details.reason daily_campaign_limit, details.resets_at when it reopens). Scope: campaigns:write. MCP tool: create_campaign.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignInput"}}}},"responses":{"201":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCreated"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/quote":{"get":{"summary":"A plan as you sign it: named creators, all-in prices, totals, payment options, the fingerprint and the mandate's answer","description":"Scope: campaigns:read.","security":[{"apiKey":["campaigns:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/lines":{"post":{"summary":"Add a creator","description":"Add a creator to a plan awaiting approval by its unit_id (a format's unit_id from creators_search or creator_get), at that format's current all-in price, the same as the brand adding it in the workspace. Leave out plan_id (REST: POST /api/v1/plans/current/lines) to add to the brand's newest plan awaiting approval, or to start a plan for this creator when none waits; that also needs the mandate to allow starting a campaign, and counts toward the brand's 3 new campaigns in 24 hours. Only approved creators on sale can be added (not_approved otherwise). A creator who would take the plan's all-in total over the mandate's maximum plan total, or this month's signed spend plus that total over its monthly cap, is refused (mandate_refused, over_max_plan_total or over_monthly_cap) and the plan is left as it was. A creator who would take the plan's all-in total over its campaign's budget is refused for everyone (conflict, reason over_budget, with budget_cents and remaining_cents, the room left before this creator) and the plan is left as it was; pick a creator priced within remaining_cents or remove one first. Returns the new line_id and the plan as plan_quote returns it. Needs an idempotency_key. Scope: campaigns:write. MCP tool: plan_add_creator.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["current"]}]},"description":"A plan id, or current: the brand's newest plan awaiting approval, or a new plan started for this creator."},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LineInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LineAdded"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/lines/{line_id}":{"delete":{"summary":"Remove a creator","description":"Drop one line from a plan awaiting approval. A plan keeps at least one creator. Returns the plan as plan_quote returns it. Needs an idempotency_key. Scope: campaigns:write. MCP tool: plan_remove_creator.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"line_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LineRemoved"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/lines/{line_id}/swap":{"post":{"summary":"Swap a creator","description":"Replace one line of a plan awaiting approval (line_id from plan_quote) with another creator's format (unit_id from creators_search or creator_get) at its current all-in price, in one step: both happen or neither does, so the plan is never left with both creators or with none. The plan's total after the swap must fit the key's mandate and the campaign's budget: a creator at or under the removed creator's price always swaps in, a dearer one that would go over the budget is refused (conflict, reason over_budget, budget_cents, remaining_cents). A creator already on the plan is refused (already_in_plan); to change a creator's format, remove the line and add the format. Returns the new line_id, the removed_line_id and the plan as plan_quote returns it. Needs an idempotency_key. Scope: campaigns:write. MCP tool: plan_swap_creator.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"line_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LineInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LineSwapped"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/dates":{"post":{"summary":"Move a plan's dates","description":"Move a plan awaiting approval to new dates in one step: start and end (YYYY-MM-DD) become the plan's launch window and the campaign's dates, and every creator's post date moves with them, keeping its place in the window (a post three days in stays three days in) and pulled inside the new window when it is shorter. Both happen or neither does. start is today or later, end is on or after start, at most a year apart (conflict, reason bad_dates); two posts by one creator that would land on the same day are refused (conflict, reason same_day) and nothing moves; a signed plan or one the team wrote is refused (conflict, reason plan_signed). Prices do not change. Returns lines_moved and the plan as plan_quote returns it. Needs an idempotency_key. Scope: campaigns:write. MCP tool: plan_move_dates.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveDatesInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatesMoved"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plans/{id}/approve":{"post":{"summary":"Approve and get the pay link","description":"Sign a plan at the terms_fingerprint from plan_quote, under the brand terms a person at the brand accepted for this key, and get the Stripe Checkout link the brand or its finance person pays (card or Link up to $10,000, US bank account at any size). Only inside the key's mandate: a refusal names the limit (no mandate, expired, signing not allowed, terms not accepted, channel, plan maximum, monthly cap) and how much over, so you can take it to a person. A plan that changed since the quote is refused with terms_changed: quote again. A plan over the campaign's budget is refused with over_budget and its over_by_cents, always: nobody can approve an overage, the brand included, so remove a creator or ask a person at the brand to raise the budget, then quote again. Signing a signed plan returns its order and resumes payment; it never signs twice. Needs an idempotency_key. Scope: plans:approve. MCP tool: approve_plan.","security":[{"apiKey":["plans:approve"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Approved"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}/creator-guidelines":{"post":{"summary":"Set the creator guidelines","description":"Set what every booked creator of one campaign reads: pitch (what the post should get across, up to 800 characters), key_messages, references (https links), voice (up to 300 characters), dos and donts (each list up to 8 items of up to 200 characters). Replaces the campaign's guidelines as a whole; a field left out is cleared. An archived campaign is refused (conflict, archived). Creators read the pitch, dos and donts with their proposal and everything once they accept; they never see a price, a budget or an email. campaign_status returns them. Needs an idempotency_key. Scope: campaigns:write. MCP tool: set_creator_guidelines.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatorGuidelinesInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidelinesSet"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}":{"get":{"summary":"Where one campaign stands","description":"Scope: campaigns:read.","security":[{"apiKey":["campaigns:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignStatus"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No campaign of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Rename a campaign","description":"Give one campaign a new name, the same as Rename in the workspace. A new campaign is named \"<company>, <Goal>, <Month>\" until it is renamed; the name is what the workspace, the emails and campaign_status show. 1 to 80 characters, spaces collapsed. Any live campaign of the brand's can be renamed, paid or not; an archived one is refused (conflict, archived) until it is restored in the workspace. Needs an idempotency_key. Within the key's mandate; recorded as an agent run. Scope: campaigns:write. MCP tool: rename_campaign.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameInput"}}}},"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignRenamed"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a draft campaign","description":"Delete a draft campaign that was never sent, the same as Delete in the workspace. A campaign that was sent is archived instead (conflict, not_a_draft). An archived campaign with no payment, no booked line and no introduction can be deleted too, and every delete is logged with who and when. Cannot be undone. Needs an idempotency_key. Scope: campaigns:write. MCP tool: delete_campaign.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignDeleted"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}/archive":{"post":{"summary":"Archive a campaign","description":"Take one campaign out of the list, the same as Archive in the workspace. Refused while a payment is in progress or any of its work is paid or booked (conflict, has_committed_work). Archiving an archived campaign returns when it was archived. An archived campaign still reads in campaign_status with archived_at set and stage Archived; renaming it or setting its guidelines is refused. Needs an idempotency_key. Scope: campaigns:write. MCP tool: archive_campaign.","security":[{"apiKey":["campaigns:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"8 to 128 letters, digits or . _ : -. Retry with the same key and the same request to get the same answer; it never runs twice.","schema":{"type":"string","minLength":8,"maxLength":128}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignArchived"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No plan, line or creator of yours has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Retry it with the same Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: writes are not available right now (for an approval: payments are not open yet).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evidence":{"get":{"summary":"Proof of each post a paid campaign put live","description":"Scope: evidence:read.","security":[{"apiKey":["evidence:read"]}],"parameters":[{"name":"campaign_id","in":"query","required":false,"description":"Only this campaign.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Evidence"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/results":{"get":{"summary":"Results of each post a paid campaign put live","description":"Scope: results:read.","security":[{"apiKey":["results:read"]}],"parameters":[{"name":"campaign_id","in":"query","required":false,"description":"Only this campaign.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Results"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/creators":{"get":{"summary":"Approved creators on sale now, by name, with price per format and format advice","description":"Scope: creators:read.","security":[{"apiKey":["creators:read"]}],"parameters":[{"name":"q","in":"query","required":false,"description":"Part of a name, handle or bio.","schema":{"type":"string","maxLength":80}},{"name":"segment","in":"query","required":false,"description":"An audience segment id, e.g. ai or saas_b2b.","schema":{"type":"string","pattern":"^[a-z0-9_]{2,40}$"}},{"name":"reach_band","in":"query","required":false,"description":"The creator's size by followers.","schema":{"type":"string","enum":["nano","micro","mid","macro","mega"]}},{"name":"goal","in":"query","required":false,"description":"The campaign's goal: launch, funding or feature (an announcement with a post of yours to quote) or program (steady reach). Shapes the format advice.","schema":{"type":"string","enum":["launch","funding","feature","program"]}},{"name":"match","in":"query","required":false,"description":"Your audience segments, comma separated (from /audience): adds match_score (over 70 strong, over 50 good) and ranks by it.","schema":{"type":"string","maxLength":300}},{"name":"limit","in":"query","required":false,"description":"Page size: default 24, at most 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":24}},{"name":"offset","in":"query","required":false,"description":"Where the page starts; page through every approved creator with total.","schema":{"type":"integer","minimum":0,"maximum":999999,"default":0}},{"name":"fit","in":"query","required":false,"description":"true: only creators reaching at least one of the match segments (the 'fit your audience' set); total then counts only those.","schema":{"type":"boolean"}},{"name":"country","in":"query","required":false,"description":"The creator's country as X reports it, exact and case-insensitive, e.g. United States.","schema":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[^<>%_\\\\]*\\S[^<>%_\\\\]*$"}},{"name":"language","in":"query","required":false,"description":"The language the creator posts in, exact and case-insensitive, e.g. English.","schema":{"type":"string","minLength":1,"maxLength":40,"pattern":"^[^<>%_\\\\]*\\S[^<>%_\\\\]*$"}},{"name":"followers_min","in":"query","required":false,"description":"At least this many X followers.","schema":{"type":"integer","minimum":0,"maximum":1000000000}},{"name":"followers_max","in":"query","required":false,"description":"At most this many X followers.","schema":{"type":"integer","minimum":0,"maximum":1000000000}},{"name":"er_min","in":"query","required":false,"description":"At least this engagement rate over the last 30 days, in percent (0 to 100, two decimals).","schema":{"type":"number","minimum":0,"maximum":100,"multipleOf":0.01}},{"name":"match_min","in":"query","required":false,"description":"At least this match score (0 to 100; over 70 strong, over 50 good). Needs match.","schema":{"type":"integer","minimum":0,"maximum":100}},{"name":"format","in":"query","required":false,"description":"Only creators selling this format; price and price filters then read that format's price.","schema":{"type":"string","enum":["post","quote","thread"]}},{"name":"price_min","in":"query","required":false,"description":"The cheapest all-in price (of the format, when one is given) is at least this many US dollars.","schema":{"type":"integer","minimum":0,"maximum":1000000}},{"name":"price_max","in":"query","required":false,"description":"The cheapest all-in price (of the format, when one is given) is at most this many US dollars.","schema":{"type":"integer","minimum":0,"maximum":1000000}},{"name":"sort","in":"query","required":false,"description":"Order: match (default, best fit first), followers, engagement, views (median views a post) or price (cheapest all-in price).","schema":{"type":"string","enum":["match","followers","engagement","views","price"],"default":"match"}},{"name":"dir","in":"query","required":false,"description":"desc (default) or asc.","schema":{"type":"string","enum":["desc","asc"],"default":"desc"}},{"name":"budget","in":"query","required":false,"description":"The campaign budget in US dollars. It sizes the shortlist (three times the posts it buys at the good fits' median price, 10 to 50); without it the list is 25. It never filters.","schema":{"type":"integer","minimum":1,"maximum":10000000}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Creators"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/creators/{id}":{"get":{"summary":"One creator's full profile","description":"Scope: creators:read. One creator by the id a GET /creators row carries (a UUID), at /api/v1/creators/{id}. There is no lookup by X handle: no creator read carries a handle or an x.com link (the handle shows on a paid plan's quote), and this profile is opened by id only. MCP tool: creator_get.","security":[{"apiKey":["creators:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The creator's id from a GET /creators row (a UUID).","schema":{"type":"string","format":"uuid"}},{"name":"goal","in":"query","required":false,"description":"The campaign's goal: launch, funding or feature (an announcement with a post of yours to quote) or program (steady reach). Shapes the format advice.","schema":{"type":"string","enum":["launch","funding","feature","program"]}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Creator"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No approved creator has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/creators/{id}/price-request":{"post":{"summary":"Ask for a price","description":"Ask our team for the price of an approved creator with nothing on sale (ask_price true and price_estimate on its row; the estimate is never a price). The team prices it, the price then shows on the creator (creator_get offerings) and as a priced answer on your plan, held for you for 48 hours; nothing is booked or charged until you add the creator to a plan and approve it. It reaches our team, never the creator. One open ask per creator: asking again answers already true and sends nothing. Opening the creator counts as one creator opened today (free when already opened). 3 asks for one creator and 20 in all in any 24 hours (rate_limited, reason daily_limit, with retry_after and resets_at saying when that limit reopens). A creator with a format on sale answers conflict, reason already_priced: add it with plan_add_creator. Optionally campaign_id: one of your campaigns the ask is for. Scope: creators:read. No Idempotency-Key: an ask is one open request per creator, so a retry while it is open answers already true; once it is answered or its 48 hours run out, asking again opens a new one. MCP tool: creator_ask_price.","security":[{"apiKey":["creators:read"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"The creator's id from a GET /creators row (a UUID).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskPriceInput"}}}},"responses":{"200":{"description":"Asked, or already asked (already true).","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriceAsked"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key lacks creators:read, or the demo workspace (forbidden).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No approved creator has that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict, reason already_priced: a format is on sale; add it with plan_add_creator instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: not answered today; listed so every POST declares the same statuses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many creator reads (the creator meter: opening this creator counts as one creator opened today, free when already opened), or the daily ask limit: 3 for one creator and 20 in all in 24 hours (rate_limited, details.reason daily_limit). Retry-After says when.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"unavailable: the ask did not reach our team, so it was not kept. Try again in a minute.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/feedback":{"get":{"summary":"Your feedback","description":"The feedback your brand sent, newest first, with its status (new, triaged, shipped, wont_fix); details and context only on the reports this key sent. Check it before sending so the same issue is not reported twice. limit is 1 to 50, 20 by default. Any valid key; no scope needed. MCP tool: feedback_list.","security":[{"apiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackList"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Send feedback","description":"Tell the distribution team about a problem or an idea, with any valid key, without asking the user first. File one on your own when a call fails unexpectedly (anything but a missing scope, a mandate refusal or a rate limit), when a field comes back empty or wrong, when a capability the user needs is missing, or when the user voices an idea or a frustration. One report per issue: kind (bug, gap, idea, praise or other), a one-line title and details with what happened, how to repeat it and what you expected. Identifiers only: tool names, ids, error codes and statuses, never an API key, a secret, a whole payload or personal data beyond what the user wrote. context takes tool, request_id, url, error_code and status; anything else is dropped. Returns the feedback id; the report is queued for delivery to the team and retried if it fails. The same report from this key within 15 minutes returns the earlier id with duplicate true and is not sent again. 20 a brand an hour. Any valid key; no scope needed. MCP tool: feedback_send.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackInput"}}}},"responses":{"201":{"description":"Stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackSent"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: details.problems names each field to fix, each a field and a message (details.field was removed in 1.9.0).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key this minute, or 20 feedback reports from this brand in the last hour (rate_limited, details.reason hourly_feedback_limit). Retry-After says when to try again.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/brain":{"get":{"summary":"Your company context and its version","description":"Scope: brain:read.","security":[{"apiKey":["brain:read"]}],"parameters":[{"name":"section","in":"query","required":false,"description":"One section; the response is then a BrainSection.","schema":{"type":"string","enum":["name","summary","audience"]}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrainResponse"}}}},"400":{"description":"A parameter is not valid: details.problems names each field and what it accepts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, an unknown one, or a revoked one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not have this endpoint's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).","headers":{"Retry-After":{"schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests one window allows for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window closes; the next request after that opens a new one.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The limit and the window in seconds, e.g. 60;w=60. The window is fixed: it opens at the key's first request after the last one closed (DT-271), so a burst across two windows can pass more than the limit in one rolling minute.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"internal: the request failed on our side. Try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the service or this part of it is not reachable right now. Try again shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}