What Ships Under /features/api?
A versioned REST API. Most public routes use /v1, while Workbench resources use /v2. Workspace-scoped routes cover content, media, inbox, analytics, integrations, workbench, campaigns, API keys, and more.
Use your own code for supported Maeve workflows. Draft the social versions the moment a blog post ships, turn a one-line Slack brief into a week of scheduled content, pull a month of analytics into the spreadsheet your client actually reads, or export scheduled posts to CSV for the person who lives in one. It is an ordinary REST API: JSON in, JSON out, a Maeve API key in the header, and the post your script schedules is on your team's calendar a second later. The same wiring plugs Maeve into an n8n workflow through the HTTP Request node.
# Bearer auth with a Maeve API key from workspace settings $ curl -s https://api.maevesocial.com/v1/workspaces/$WS/content \ -H "Authorization: Bearer $MAEVE_API_KEY" \ -H "Content-Type: application/json" \ -d @create-content.json { "data": { "id": "cnt_8f3k2", "status": "scheduled" }, "meta": { "requestId": "req_01j9…" } } # A second later it is on the calendar, same audit log as the app
The API is not a separate copy of Maeve, it is the same Maeve reached a different way. The permissions, the rules, and the history are all shared, so a fix you make in code shows up in the same history as one someone clicks in the app, and your code and your team are always working on the same thing.
There is more than one way in: the scheduler to work in by hand, the MCP server for AI assistants like Claude or Cursor, and the CLI for the terminal. Whatever you learn in one carries over to the rest.
NestJS generates the OpenAPI 3.x spec from controller and DTO metadata. Read it as an interactive Scalar reference at https://api.maevesocial.com/docs, grab the raw JSON at https://api.maevesocial.com/docs/openapi.json, or point an SDK generator at it. The maeve-cli is maintained separately as a REST client with manually registered commands and schemas. For a running start, the API quickstart walks the first authenticated call end to end.
Requests come back in a consistent envelope: your data under data, pagination under meta, and on failure a structured error with a code, a message, and a request ID you can quote in support.
Issue an API key in workspace settings and copy the secret once; Maeve stores only a SHA-256 hash plus a visible prefix. Every call is checked server-side against the key's role and the workspace plan, so a read-only key cannot publish and Standard-only routes refuse politely on lower tiers. The auth doc covers how Maeve API keys work in full, from issuing a key to rotating it.
Rate limits run per workspace, per minute: 120 reads, 30 writes, 15 for expensive actions like publish and retry, with a 429 and a Retry-After header when you cross one. And every authenticated call writes an audit row, the same table the web app, CLI, and MCP server write to, so a flaky integration is debuggable without extra logging. That retry route is how you retry failed posts through the API instead of reopening each one in the app.
Supported product areas expose versioned routes for integrations and automation.
Every endpoint reads or writes the same data the web app uses. Build the integration once and the other surfaces inherit it.
A versioned REST API. Most public routes use /v1, while Workbench resources use /v2. Workspace-scoped routes cover content, media, inbox, analytics, integrations, workbench, campaigns, API keys, and more.
Bearer token in an Authorization header. Issue a Maeve API key in workspace settings, grant it one or more workspaces, and copy the raw secret once. We hash the secret with SHA-256 and store only the hash plus a visible prefix for identification. Keys are workspace-granted; revoke and rotate them from settings.
Yes. NestJS generates it from controller and DTO metadata. The JSON document is at https://api.maevesocial.com/docs/openapi.json, with the interactive reference at https://api.maevesocial.com/docs. The maeve-cli is a separately maintained REST client, not generated from this spec.
Per workspace, per minute. Reads sit at 120/min on most controllers. Writes drop to 30/min. The expensive ones (publish, retry, send-review, bulk-delete) drop to 15/min. Crossing a limit returns 429 with a Retry-After header. Throttle metadata lives next to every route, so the OpenAPI doc shows it inline.
Not yet. Inbound webhooks exist for Facebook, Instagram, and Threads platform events (comments, messages, reactions) and are reconciled into your inbox. Outbound webhooks for your own scheduled-post lifecycle are on the roadmap. Until they ship, GET /v1/workspaces/:id/content with a since timestamp is the supported way to poll, or run an MCP listener.
A viewer-scoped key can read but cannot mutate. An editor-scoped key can draft and update but cannot manage workspace members. Plan tier matters too: client-reviews and approval-history endpoints require the Standard plan and 401 with a clear reason on lower tiers. The server enforces both. The client never has to know the rule.
JSON body in, JSON envelope out. The shape is { data, meta } where meta carries pagination (limit/offset/total/hasMore for offset routes, nextCursor/hasMore for cursor routes). Errors return a structured envelope on 4xx/5xx with code, message, and a request ID you can quote in support. Idempotency on inbox webhook delivery; not yet on POST writes.
They are distinct clients with separate credentials. Use the REST API for integrations, the maeve-cli for terminal work and CI, and the MCP server for AI agents. All three operate on the same Maeve data and enforce the same workspace permissions.
Basic and up. Most endpoints work on Basic. Standard-only routes are flagged in the spec: anything under client-reviews, content:approval-history, and the PDF analytics report. Free trials run for 3 days with full API access.
Every authenticated call writes a row: actor (user or API key prefix), organization, workspace, route, status, duration, and outcome. The web app, the CLI, the MCP server, and direct REST callers all land in the same table. Failures are recorded too, so a flaky integration is debuggable without flipping on extra logging.