Promeo

Developer documentation

Connect to Promeo

Manage your Projects and posts from scripts, integrations, and AI assistants with the REST API or Model Context Protocol (MCP).

Scoped API keysYour Projects · Your posts

Create an API key in your dashboard, choose its permissions, and connect through either interface. Read Projects and posts, edit Project profiles and editable posts, or delete saved records.

Get an API key

  1. Sign in to Promeo, verify your email, and complete Workspace setup.
  2. Open Manage → API keys in the dashboard and select Create API key.
  3. Give the integration a name, choose one Project or all Projects, and select its permissions. New keys start with read permissions only.
  4. Choose an expiry of 30 days, 90 days, or one year.
  5. Create the key and save its value in your integration's protected secret settings. The complete key is shown only once.

The dashboard lists each key's name, masked prefix, Project access, permissions, creation date, expiry, and last use. Last use is recorded at most once per minute. You can have up to 20 active keys. Selecting Revoke and confirming stops subsequent requests with that key; already accepted requests may finish. To rotate a key, create its replacement, update your integration, then revoke the old key.

A key scoped to All Projects also includes future Projects owned by the account. A key scoped to one Project cannot access another Project. Deleting that Project removes its scoped keys. Account deletion, a disabled account, or revoked email verification prevents API access.

Permissions

Scroll across to see all columns.

PermissionAllowed action
projects:readList accessible Projects
projects:updateUpdate Project profile fields
projects:deleteDelete a Project, its content, and its connections
posts:readList recent posts in an accessible Project
posts:updateEdit a draft or scheduled post's copy, tags, or timing
posts:deleteDelete a Promeo post record and its stored media

Permissions are independent. For example, an integration with posts:update needs posts:read as well if it should inspect posts before editing them. Grant delete permissions only to integrations that should remove saved data. Deleting a Project includes its stored posts and assets even if the key does not separately have posts:delete.

Authentication

Send your API key in the same header for REST and MCP:

http
Authorization: Bearer <promeo-api-key>

The examples use PROMEO_API_KEY, supplied through your client's protected credential facility. Never put a real key in source control, logs, URLs, shared configuration files, or support messages. Promeo stores only a hash of the key, so a lost value cannot be recovered; revoke it and create another.

Verified Firebase ID tokens issued for Promeo's Firebase project (promeo-e55d3) remain supported in the same Bearer header. They expire and must be refreshed through Firebase Authentication. Firebase sessions have the account's full integration permissions and share the account's request limits. For unattended integrations, use a scoped dashboard API key.

The account must retain a verified email and current business Terms acceptance. The OpenAPI document and MCP initialize handshake are public. Data requests, MCP tool discovery, and tool execution require authentication.

Rate limits

REST and MCP use shared limits. Switching interfaces, creating more keys, or refreshing a Firebase ID token does not reset the account's allowance.

Scroll across to see all columns.

LimitAllowance
Each API key60 requests per minute; 5,000 per day
Account, across all keys and Firebase sessions120 requests per minute; 10,000 per day
Update and delete attempts, per account20 per minute; 200 per day
Project profile saves, shared with the dashboard50 per day
Draft saves, shared with the dashboard60 per day
Scheduled post edits, shared with dashboard scheduling30 per day
Post deletions, shared with the dashboard100 per day
API/MCP Project deletions20 per day

Account/key windows start with the first request after the previous window expires. Existing dashboard operation limits use fixed UTC time buckets. Authenticated requests count even when their route input or permissions are rejected. Requests rejected at an earlier limit do not consume later quotas. MCP tool discovery and authenticated pings also count. Requests are limited to 256 KiB; MCP accepts one JSON-RPC message per request, with no batches.

A 429 response includes Retry-After, the number of seconds to wait. This applies to both REST errors and MCP JSON-RPC errors. Wait at least that long and add backoff; do not immediately retry in a loop.

Promeo also applies shared pre-authentication limits to both surfaces, including public discovery: 1,200 requests per minute overall and 600 per minute per transport peer. Reverse proxies can share a peer allowance; these are conservative service protection limits, not individual customer quotas. They do not trust caller-supplied forwarding headers. These controls run in the application and are not a separately deployed network DDoS protection service.

REST API

Responses use JSON. The X-Promeo-API-Version response header is 2026-09-07. The OpenAPI specification describes every route, request body, and required permission. Encode path segments with your HTTP client's URL library.

List Projects

bash
curl --fail-with-body \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  https://promeo.ai/api/v1/projects

GET /api/v1/projects requires projects:read. Returns up to 100 accessible Projects, newest first. A Project-scoped key sees only its selected Project.

json
{
  "projects": [{
    "id": "AbCdEfGhIjKlMnOpQrSt",
    "name": "Example Project",
    "description": "Short-form product education",
    "audience": "Independent retailers",
    "features": "Product demonstrations and customer stories",
    "voice": "Clear, practical, and warm",
    "createdAt": "2026-08-20T09:30:00.000Z",
    "updatedAt": "2026-09-07T14:10:00.000Z"
  }]
}

Update a Project

PATCH /api/v1/projects/{projectId} requires projects:update. Include only fields you want to change; omitted fields are preserved. Supported fields are name (1–100 characters) and description, audience, features, and voice (1–20,000 characters each). The resulting profile must have all its context fields completed, just as when saving Project settings in the dashboard.

bash
curl --fail-with-body --request PATCH \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"name":"Updated Project","voice":"Friendly and concise"}' \
  https://promeo.ai/api/v1/projects/AbCdEfGhIjKlMnOpQrSt

Returns { "project": { ... } } using the Project shape above. A concurrent change detected during the update returns 409; read the current Project before retrying.

Delete a Project

DELETE /api/v1/projects/{projectId} requires projects:delete. This removes the Project, its stored content, and its connected accounts from Promeo. Pending scheduled, processing, or publishing posts must be cancelled or finished first. Existing provider revocation and media cleanup run as they do for dashboard deletion. Already published social content remains on its platform.

bash
curl --fail-with-body --request DELETE \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  https://promeo.ai/api/v1/projects/AbCdEfGhIjKlMnOpQrSt

Returns { "deleted": true }. Confirm the user's intent in your integration before sending this request.

List recent Project posts

GET /api/v1/projects/{projectId}/posts requires posts:read. Returns the 50 most recent posts, ordered by scheduled time from newest to oldest.

bash
curl --fail-with-body \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  https://promeo.ai/api/v1/projects/AbCdEfGhIjKlMnOpQrSt/posts

The result is { "posts": [...] }. Each post includes:

Scroll across to see all columns.

FieldMeaning
idPost ID for update or delete requests
statusdraft, scheduled, processing, publishing, published, failed, or cancelled
title, description, tagsShared title, caption, and up to ten tags
scheduledAtISO 8601 UTC time; an unscheduled draft returns an empty string
destinationsSelected channel snapshots with platform, connection ID, and display name
destinationOverridesOptional per-destination copy, media, and settings
destinationResultsOptional per-destination publishing results
media, mediaCountSaved media metadata, including public delivery URLs
privacyLevel, allowComment, autoAddMusicSaved publishing settings
brandContentToggle, brandOrganicToggle, photoCoverIndexDisclosure and cover settings
awaitingApprovalWhether a scheduled post still needs approval
publishStatus, failReasonOptional processing details
automationId, automationPostTypeOptional automation provenance

Update a post

PATCH /api/v1/projects/{projectId}/posts/{postId} requires posts:update. Only drafts and scheduled posts can be edited. Include at least one editable field and approved: true to confirm review of the exact changes.

Scroll across to see all columns.

Editable fieldBehavior
titleShared title, at most 90 characters
descriptionShared caption, at most 4,000 characters; destination limits still apply
tagsReplace tags with up to ten values, each at most 32 user-perceived characters; [] clears them
scheduledAtChange an existing schedule, or a draft's proposed time; "" clears a draft's proposed time
timezoneTimezone saved with the post

Omitted fields, media, destinations, destination-specific overrides, and publishing settings are preserved. Shared copy changes do not replace existing destination-specific copy. A draft stays a draft; this endpoint cannot create a post, schedule a draft, change channels/media, generate content, or publish immediately. Scheduled saves must meet the existing scheduling and destination validation rules; ordinarily the time must be between two minutes and 90 days from now. Editing a generated draft detaches it from its automation, matching the dashboard.

For a post with a TikTok destination, also send musicUsageConfirmed: true after the user accepts TikTok's Music Usage Confirmation. When applicable, include brandedContentPolicyConfirmed: true after explicit acceptance. Promeo never invents these confirmations for an integration.

bash
curl --fail-with-body --request PATCH \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"description":"Updated caption","tags":["launch"],"approved":true}' \
  https://promeo.ai/api/v1/projects/AbCdEfGhIjKlMnOpQrSt/posts/PostDocumentId

Returns { "postId": "PostDocumentId", "status": "draft" } or the same shape with "scheduled". A publishing claim or concurrent edit returns 409; read the current post before retrying.

Delete a post

DELETE /api/v1/projects/{projectId}/posts/{postId} requires posts:delete. It removes the Promeo post record and stored media. Processing or publishing posts return 409. Deleting a published record does not delete the content from its social platform.

bash
curl --fail-with-body --request DELETE \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  https://promeo.ai/api/v1/projects/AbCdEfGhIjKlMnOpQrSt/posts/PostDocumentId

Returns { "deleted": true }. Confirm the user's intent before calling. A repeat delete after successful removal returns 404.

Errors and status codes

json
{
  "error": {
    "code": "permission-denied",
    "message": "This API key needs the posts:update permission."
  }
}

Scroll across to see all columns.

HTTP statusMeaning and recovery
400Invalid input, unknown fields, malformed ID, or excessive request size
401Missing, invalid, expired, or revoked credential; use a valid replacement
403Missing key permission or unsupported browser origin
404Route or accessible resource was not found
405Unsupported method; inspect Allow
409Resolve account setup, required approval, resource state, or a concurrent edit
415Send a JSON request with Content-Type: application/json
429Wait for Retry-After, then retry with backoff
500Unexpected failure; keep the safe reference code when contacting support

Do not automatically replay updates or deletes after a timeout or server error: read the current resource first because the original request may have succeeded. Use bounded backoff for transient failures.

MCP

Promeo provides stateless Streamable HTTP at https://promeo.ai/mcp using protocol version 2025-06-18. Send one JSON-RPC 2.0 message per HTTP POST. There are no session IDs, batches, or SSE stream; GET returns 405.

Use a client that supports a custom Authorization header. Configuration names vary between clients; a common shape is:

json
{
  "mcpServers": {
    "promeo": {
      "type": "http",
      "url": "https://promeo.ai/mcp",
      "headers": {"Authorization": "Bearer ${PROMEO_API_KEY}"}
    }
  }
}

Use your client's secret facility if it does not support environment-variable interpolation. Never commit a literal API key to the configuration.

Initialize

bash
curl --fail-with-body https://promeo.ai/mcp \
  --header 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"example-client","version":"1.0.0"}}}'

Send notifications/initialized after the handshake if your client requires it. Notifications receive 202 and never execute tools.

List tools

bash
curl --fail-with-body https://promeo.ai/mcp \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

The catalog includes only tools allowed by the key's permissions:

Scroll across to see all columns.

ToolArgumentsResult
list_projects{}{ "projects": [...] }
list_posts{ "projectId": "..." }{ "posts": [...] }
update_project{ "projectId": "...", "changes": { ... } }{ "project": { ... } }
delete_project{ "projectId": "..." }{ "deleted": true }
update_post{ "projectId": "...", "postId": "...", "changes": { ... } }{ "postId": "...", "status": "draft" } or "scheduled"
delete_post{ "projectId": "...", "postId": "..." }{ "deleted": true }

changes accepts exactly the corresponding REST PATCH fields and follows the same approval and state rules. Write tools advertise destructive annotations. The client should request user confirmation for destructive operations.

Call a tool

bash
curl --fail-with-body https://promeo.ai/mcp \
  --header "Authorization: Bearer $PROMEO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"update_post","arguments":{"projectId":"AbCdEfGhIjKlMnOpQrSt","postId":"PostDocumentId","changes":{"description":"Updated caption","approved":true}}}}'

Successful results provide both content containing JSON text and an object in structuredContent. Validation, permission, and ownership errors return a tool result with isError: true. Authentication failures and rate limits use HTTP errors with a JSON-RPC error; limits always return HTTP 429 and Retry-After. Protocol errors use -32600 (invalid request), -32601 (unknown method), or -32602 (invalid parameters); unexpected failures use -32603.

Compatibility and support

  • Ignore unknown response fields unless your integration needs them.
  • Keep the advertised API and MCP versions in safe diagnostics.
  • The integration surface does not offer post creation, media upload, generation, immediate publishing, OAuth client registration, webhooks, or pagination cursors. Use the dashboard for those existing workflows.
  • Never expose API keys, Firebase tokens, channel credentials, or full user content in logs or support requests.

For unexpected failures, include the request path or MCP method, timestamp, HTTP status, advertised version, and any safe error reference. Contact Promeo support with those details.