brandmint api
integrate voice-matched content generation into any agent, cli, or workflow. extract voice profiles, generate posts, check quality, manage drafts, search post history, and publish to linkedin and x programmatically.
introduction
brandmint is a content engine that learns how you write. it reads your linkedin and x (twitter) posts, builds an 8-dimension voice profile (tone, hooks, rhythm, formatting, vocabulary, themes, structures, engagement patterns), and generates new posts that match your authentic voice.
the api exposes this as discrete endpoints. an agent can extract your voice, generate a post on a topic, check it for ai tells, manage drafts through a review pipeline, schedule posts, and publish to connected platforms, all without touching a browser. the mcp server wraps these same capabilities for claude code and other mcp-compatible clients.
authentication
all api requests require a key. create one in the brandmint app under settings → api keys, or via the key management endpoint.
pass the key in either header:
keys are scoped to a single user account. all data returned is scoped to that user's posts, profile, and memories.
create a key (api)
if you're already authenticated via session (logged in), you can create keys programmatically:
quickstart
generate a post in your voice with one request. auto-extracts your voice, generates with a 3-step quality pipeline, and returns both the post and the reusable voice profile:
curl -X POST https://brandmint.app/api/v1/posts/generate \
-H "Authorization: Bearer bm_your_key" \
-H "Content-Type: application/json" \
-d '{"angle": "why most content strategies fail"}'response:
voice_profile back on subsequent calls to skip extraction and speed things up.error responses
all errors return a json object with an error field and an appropriate http status code.
status codes
400-missing or invalid parameters (e.g. no topic, no post text)401-missing or invalid api key429-daily rate limit exceeded500-server error (database failure, upstream api error)
common error messages:
voice extraction
analyzes your last 15 posts to extract your authentic voice across 8 dimensions: tone, hooks, rhythm, formatting, vocabulary, themes, structures, and engagement patterns. voice extraction is platform-scoped: if you have posts on both linkedin and x, each platform gets its own voice profile.
the voice profile is a text block. pass it to /posts/generate to skip re-extraction and speed up generation.
generate post
writes a post in your voice using the full 3-step pipeline: voice extraction (platform-scoped), generation with format-specific rules, and quality check (ai-tell scan + anti-pattern enforcement). supports linkedin and x.
POST /api/v1/posts/generate { "angle": "why ops pilots fail", // use the hook from generate_ideas for best results "objective": "authority", // optional: authority | engagement | dms | lead-magnet "platform": "linkedin", // optional: linkedin | x (scopes voice extraction) "format": "linkedin-post", // optional: format key for structure rules "angle_rationale": "contrarian take on...", // optional: from ideas "Why It Works" "subtopics": ["hiring", "retention"], // optional: from ideas "Subtopics to Cover" "voice_profile": "..." // optional: pass cached profile to skip extraction } → { "post": "...", "voice_profile": "..." }
best results: call /posts/ideas first, pick an idea, then pass its hook as angle, its rationale as angle_rationale, and its subtopics as subtopics. this mirrors the app's swipe-to-draft flow. topic is accepted as an alias for angle for backwards compatibility. if platform is set, voice extraction only analyzes posts from that platform. format loads format-specific hooks, structures, and closes (defaults to linkedin-post).
quality check
scans a draft for ai tells and structural anti-patterns, then returns a cleaned version with violations removed.
POST /api/v1/posts/check { "draft": "your post text here...", "voice_profile": "..." // optional } → { "cleaned_post": "..." }
catches common ai writing patterns including filler phrases, false dichotomies, rhetorical-question openers, and engagement bait.
generate ideas
turns a seed topic into 4-6 post ideas. each includes a hook, content gap analysis, subtopics, and cta. grounded in your recent posts so it avoids repeating what you've already covered.
search posts
search your post history with 5 ranking modes. semantic uses vector similarity, bm25 uses full-text keywords, hybrid combines both with reciprocal rank fusion.
POST /api/v1/posts/search { "query": "leadership lessons", "rank_by": "hybrid", // auto | semantic | bm25 | hybrid | engagement | recent "limit": 5, "min_reactions": 10, "days_ago": 90, "creator": "janesmith", // optional: filter by creator handle "exclude_self": false // optional: exclude your own posts }
post analytics
aggregate your post data with counts, sums, and grouping. use for performance analysis: total reactions, posts per month, engagement by hook type, top-performing structures.
aggregation functions
["Count"]- count posts["Sum", "reactions"]- sum a numeric field (reactions, comments, views)
for averages, request both sum and count, then compute client-side.
content strategy
analyzes your content performance and produces a data-backed strategy. covers: what's working (by hook type, structure, media format), what's underperforming, and specific recommendations with cited data points.
profile
read your creator profile (name, audience, content themes, post stats, saved memories) or update individual fields.
drafts
full crud for drafts. drafts progress through a review pipeline: generated (pending) → approved (kept, shown in calendar) or rejected (passed, hidden). status is derived from the swipe_decisions table, not a column on drafts.
list drafts
create a draft
create via public api / mcp
drafts created via the public api or mcp save_draft tool are auto-approved (a "kept" swipe decision is inserted) so they appear in the calendar immediately.
update a draft
delete a draft
draft generation
generates a post from an idea angle using sse streaming. extracts voice (or uses a cached profile), writes the post, and saves it to the drafts table. the stream keeps the connection alive during generation (typically 10-20 seconds).
returns an sse stream with status updates and a final result:
draft_id is provided, the endpoint updates the existing row instead of creating a new one. this supports the placeholder pattern where a draft row is created first with empty post_text, then filled by this endpoint.swipe decisions
records keep/pass decisions on ideas and drafts. each decision stores a full snapshot of the item at swipe time, enabling preference learning. draft status (pending vs kept vs passed) is derived from this table via postgres views.
record a decision
list decisions
rejection reasons
the app uses per-phase reason sets:
- ideas: wrong topic, weak angle, overdone, wrong audience, too broad, not now
- drafts: wrong tone, weak hook, wrong structure, too pushy, needs editing, not now
memories
persistent facts minty learns about you: preferences, corrections, rules, audience details, tone notes. saved automatically during chat (via the update_user_memory tool) and visible in the app under /app/memory.
list memories
create a memory
deactivate a memory
knowledge base
upload reference documents (brand guides, case studies, positioning docs) that minty can search while drafting. content is chunked and embedded for semantic search via the search_knowledge_base tool.
list documents
upload a document
search_knowledge_base tool during chat.delete a document
media upload
upload images to supabase storage. returns a public url and an optional vision summary (gpt-4o mini describes the image in one sentence for llm context).
uploaded images can be attached to drafts in the editor. their vision summaries are passed to minty as media_context during chat, so she can see what the image contains without viewing it directly.
publish
publishes a draft to a connected social platform. the draft must have content, not be already published, and the user must have an active connection for the draft's platform.
error cases
400- draft_id missing, draft has no content, or no connection for platform404- draft not found409- draft already published401- token expired (reconnect your account)
supported platforms: linkedin, instagram. token refresh is handled automatically when possible.
connections
manage social platform connections. connections store oauth tokens and are used by the publish endpoint.
list connections
start oauth flow
redirect the user to the returned url. after consent, the callback stores the token and redirects back to the app.
disconnect
content pillars
recurring themes that organize your content. pillars are discovered automatically during onboarding and can be created or updated manually. used by the generator to ground ideas in your established themes.
list pillars
create a pillar
update a pillar
settings
read or update your account settings: name, audience, objective, timezone, content themes, and connected social handles.
get settings
update settings
rate limits
default: 1,000 requests per day per key. resets at midnight utc. exceeded limits return 429 Too Many Requests.
usage is tracked per key and visible in the app under settings → api keys (calls today / daily limit).
sse events
the chat and draft generation endpoints use server-sent events (sse) to stream responses. each event has a type and a json data payload.
chat endpoint
the chat endpoint accepts optional context fields for the editor:
when draft_id is present, the system prompt includes an <active_draft> block with the draft text, platform, original angle, voice snapshot from generation, and any attached media summaries.
chat events
session-sent once at the start. containsconversation_id.text-streaming text chunks.{"text": "..."}status-progress updates.{\"text\": \"analyzing your voice...\"}tool_output-structured results for client-side rendering (e.g. idea cards, strategy data).{\"content\": \"...\"}done-stream complete. containsconversation_idandusage(tokens, cost).error-something failed.{"error": "message"}
draft generation events (/api/drafts/generate)
status-progress updates: "extracting voice...", "writing draft...", "saving..."done-generation complete. containspost,voice_profile, anddraft_id.error-generation failed.{"message": "..."}
consuming sse in javascript
mcp server
brandmint exposes a hosted mcp endpoint. paste the url into any mcp-compatible client and all tools appear. no npm install, no local server.
claude code
cursor / windsurf
same endpoint and auth. add it in your mcp settings with the url https://brandmint.app/api/mcp and your api key as the bearer token.
once connected, all 28 tools appear automatically in your client. the server includes dynamic instructions that guide your mcp client through the recommended workflow. new users get onboarding steps; fully set up users get the standard ideas-first flow.
onboarding
the mcp server detects your setup state on every connection. if posts, audience, or social connections are missing, the server instructions tell your client to resolve them first. call get_setup_status to check what's configured and what's missing.
try these prompts
- "generate post ideas about remote hiring"
- "write a linkedin post about why most ops pilots fail"
- "extract my voice profile from my recent posts"
- "check this draft for ai tells" (paste your text)
- "how did my posts perform this month?"
- "save this as a draft and publish it to linkedin"
what happens under the hood
generate_post runs the same 3-step pipeline as the app: voice extraction (platform-scoped), generation (format-aware), and quality check (ai-tell scan + anti-pattern enforcement). the returned post is already cleaned. save_draft auto-approves the draft so it appears in your calendar immediately, and persists the voice profile for editor context.
example workflows
chain tools together for end-to-end content workflows. these examples work via the mcp server or rest api.
idea to published post
the recommended flow: generate ideas, pick one, write it, save, and publish. quality check is built into generate_post (no separate step needed).
performance review
analyze what's working and generate ideas to double down on top-performing themes.
voice-first batch
extract voice once, then reuse it across multiple generations to skip the extraction latency.
carousels
create, read, update, and delete carousels. each carousel contains a slides array (jsonb), a visual style, aspect ratio, and optional brand kit link.
list carousels
GET /api/v1/carousels -H "Authorization: Bearer bm_your_key" → [ { "id": "uuid", "title": "5 hiring mistakes", "aspect": "1:1", "style_id": "bold", "slide_count": 8, "slides": [{ ... }], // first slide only (preview) "created_at": "...", "updated_at": "..." } ]
the list response returns only the first slide per carousel (for thumbnail previews) plus a slide_count. use ?id=uuid to fetch all slides.
get a single carousel
create a carousel
update a carousel
delete a carousel
writable fields
title- carousel nameslides- full slides jsonb array (each slide has elements, background, layout)aspect- canvas ratio:1:1,4:5,3:4,9:16style_id- visual style key (see styles endpoint below)framework- content framework used to generate slidessource_type- how the carousel was createdbrand_kit_id- FK to a brand kitdraft_id- FK to the draft this carousel is attached tothumbnail_url- preview image url
carousel styles
read-only list of the 10 built-in visual styles. use id as the style_id when creating or updating carousels.
available styles
minimal- clean, whitespace, calmbold- high contrast, big type, dark slideseditorial- magazine, refined, typographicstartup- stripe/linear feel, tight grid, hairlinescreator- punchy, loud hooks, lime slidescorporate- executive, measured, boardroom-readystat- numbers and proof, one big number per slidemono- monospace, terminal-flavored, technical takespunch- color-blocked, oversized type, one word popsessay- explainer, calm thought-leadership, whitespace
brand kits
brand kits define fonts, colors, logos, and byline for carousels. each user can have multiple kits. one kit can be marked as the default.
list brand kits
get a single kit
create a brand kit
POST /api/v1/carousels/brand-kits -H "Authorization: Bearer bm_your_key" -H "Content-Type: application/json" -d '{ "name": "acme corp", "fonts": { "heading": "Inter Tight", "body": "Inter", "mono": "JetBrains Mono" }, "colors": ["#0E0E0C", "#D6FF3B", "#F7F6F3"], "logos": ["https://example.com/logo.svg"], "byline": "Jane Smith", "is_default": true }'
update a brand kit
delete a brand kit
linking a kit to a carousel
set brand_kit_id when creating or updating a carousel:
brand_kit_id links the kit to the carousel but does not automatically rewrite slide content. the kit's fonts, colors, and logos are applied at render time by the carousel editor. to programmatically apply kit values, read the kit and update the carousel's slides array with the desired font/color overrides.webhooks
subscribe to events to keep external systems in sync. webhook configuration is coming soon.
draft.saved-a draft was saved via the api or apppost.scheduled-a draft was placed on the calendarpost.published-a post went live via a connectorvoice.extracted-a voice profile was generated