Skip to content

DocsReference

OpenPromo REST API

The OpenPromo REST API: API keys, the response format and every route for projects, brand profiles, assets, ideas, creations, renders and usage.

Everything the dashboard does goes through this API, so scripts and your own tools can do the same. The MCP server wraps the same routes for AI agents. The base address is https://api.openpromo.gg/api; on a self-hosted install, use your own API address.

Authentication

Create an API key in Settings and usage under API keys. Keys start with opro_, are shown once and act as your account. Send one as a bearer token:

Terminal
curl https://api.openpromo.gg/api/me \
  -H "Authorization: Bearer $OPENPROMO_API_KEY"

A few account settings can only be changed from the dashboard while signed in: your YepAPI key, the spending limit and creating or deleting API keys. With an API key, those routes answer 403 forbidden.

Responses

JSON
// Success
{ "ok": true, "data": { ... } }

// Success of a paid call: what it cost on your YepAPI key
{ "ok": true, "data": { ... }, "costUsd": 0.04 }

// Error
{ "ok": false, "error": { "code": "budget_reached", "message": "...", "details": ... } }

Error codes are listed in Errors and troubleshooting. Request bodies are JSON unless noted; an invalid field answers 400 validation_error with the field in details.

From website to reel

Terminal
# 1. Add a website. Reading it runs in the background (about a minute).
curl -X POST https://api.openpromo.gg/api/projects \
  -H "Authorization: Bearer $OPENPROMO_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "crumbandco.example"}'

# 2. Poll until brandStatus is "ready".
curl https://api.openpromo.gg/api/projects/PROJECT_ID -H "Authorization: Bearer $OPENPROMO_API_KEY"

# 3. Write a reel from a brief (one writing call).
curl -X POST https://api.openpromo.gg/api/projects/PROJECT_ID/creations \
  -H "Authorization: Bearer $OPENPROMO_API_KEY" -H "Content-Type: application/json" \
  -d '{"type": "reel", "brief": "Weekend offer: 20% off a first subscription"}'

# 4. Render it, then poll the render until status is "done".
curl -X POST https://api.openpromo.gg/api/creations/CREATION_ID/renders \
  -H "Authorization: Bearer $OPENPROMO_API_KEY" -H "Content-Type: application/json" -d '{}'
curl https://api.openpromo.gg/api/renders/RENDER_ID -H "Authorization: Bearer $OPENPROMO_API_KEY"

# 5. Download an output file by its asset id.
curl -L -o reel.mp4 "https://api.openpromo.gg/api/assets/ASSET_ID/file?download=1" \
  -H "Authorization: Bearer $OPENPROMO_API_KEY"

Account and usage

Account routes
RouteWhat it does
GET /api/meYou, whether a YepAPI key is connected, your spending limit, and this install’s MCP and docs addresses.
GET /api/balanceYour remaining YepAPI balance, with this month’s spend, paid calls and limit. Free.
GET /api/usageThis month’s spend: total, by feature, by day, and the 50 latest calls.
GET /api/api-keysYour API keys: name, prefix, last used. Never the key itself.
POST /api/api-keysCreate a key. Body: { "name": string }. Returns the full key once. Dashboard only.
DELETE /api/api-keys/:idRevoke a key. Dashboard only.
PUT /api/settings/yepapi-keySave your YepAPI key after checking it. Body: { "apiKey": string }. Dashboard only.
DELETE /api/settings/yepapi-keyRemove your YepAPI key. Dashboard only.
PUT /api/settings/budgetSet the monthly limit in dollars, or remove it. Body: { "monthlyBudgetUsd": number | null }. Dashboard only.

Projects and brand profiles

Project routes
RouteWhat it does
GET /api/projectsYour projects with brand status, tagline, main colors and logo asset id.
POST /api/projectsAdd a website and start reading it. Body: { "url": string, "name"?: string }. Needs a YepAPI key. Answers 201 with brandStatus: "ingesting". Costs about $0.05 – $0.15.
GET /api/projects/:idThe project with its full brand profile, read status and progress, and agent notes (context).
PATCH /api/projects/:idRename it or replace the agent notes. Body: { "name"?: string, "context"?: object }.
DELETE /api/projects/:idDelete the project, everything in it and its files.
PUT /api/projects/:id/brandSave an edited brand profile. Body: { "brand": BrandProfile }, the whole profile as read from the project. Changed fields are remembered and survive a refresh.
POST /api/projects/:id/brand/refreshRead the website again. Body: { "reset"?: boolean }; reset: true also forgets your edits. 409 while a read is running.
GET /api/projects/:id/pagesThe pages the profile was built from, with their text, for checking where a claim came from.

Assets and files

Asset routes
RouteWhat it does
GET /api/projects/:id/assetsThe library. Query: role (comma-separated), creationId, limit (1–500, default 200).
POST /api/projects/:id/assetsUpload a file as multipart form data: field file, optional field role (logo, product, photo, screenshot, background, broll, music or voice; default photo). PNG, JPEG, WebP, SVG, GIF, MP4, WebM, MP3, WAV or M4A, up to 200 MB.
GET /api/assets/:id/fileThe file itself. Supports Range requests for video seeking; add ?download=1 to download it with a file name.
PATCH /api/assets/:idRename it or change its role. Body: { "name"?: string, "role"?: string }.
DELETE /api/assets/:idDelete the asset and its file.
Upload a product photo
curl -X POST https://api.openpromo.gg/api/projects/PROJECT_ID/assets \
  -H "Authorization: Bearer $OPENPROMO_API_KEY" \
  -F "[email protected]" -F "role=product"

Ideas

Idea routes
RouteWhat it does
GET /api/projects/:id/ideasSaved ideas, newest first.
POST /api/projects/:id/ideasWrite new ideas from the brand profile. Body: { "count"?: 1–20, "goal"?, "channel"?, "type"?, "notes"?: string }. Count defaults to 8. Answers 201 with the ideas and costUsd. About $0.02 – $0.08.
PATCH /api/ideas/:idEdit an idea. Body: any of title, hook, body, caption, hashtags (array), status (new, used or archived) and plannedFor (YYYY-MM-DD or null).
DELETE /api/ideas/:idDelete an idea.

Goals: "launch", "promo", "education", "proof", "feature", "story". Channels: "instagram", "tiktok", "youtube", "linkedin", "facebook", "x".

Creations and renders

Creation routes
RouteWhat it does
GET /api/projects/:id/creationsCreations with their latest render. Query: type.
POST /api/projects/:id/creationsWrite a creation from an idea or a brief. Body: { "type", "format"?, "ideaId"?, "brief"?, "voice"?: boolean, "allowGenerated"?: boolean }. Give ideaId or brief. voice and allowGenerated default to true. Takes 10 to 30 seconds; answers 201 with the scenes, checks and costUsd.
GET /api/creations/:idThe creation with its scenes (spec), checks, caption and its last 20 renders.
PUT /api/creations/:idSave edits. Body: { "spec"?, "title"?, "caption"?, "format"? }; send the whole spec as read. Checks run again. 409 while it is rendering.
DELETE /api/creations/:idDelete the creation.
GET /api/creations/:id/previewOne scene as an HTML page, as the editor shows it. Query: scene (default 0), format. Free.
POST /api/creations/:id/rendersStart a render. Body: { "format"?, "quality"?: "draft" | "final" }. Answers 202. Refused while checks have errors or another render is running. Spends only on AI pieces that are not cached yet.
GET /api/renders/:idStatus and progress; when done, the output, poster and caption file asset ids.

Types and the sizes each one can have:

Creation types
TypeFormats
imagesquare, portrait, story, link, x_header, linkedin_banner
carouselsquare, portrait
reelstory
promolandscape, square, story
tutoriallandscape, story

All formats: "square", "portrait", "story", "landscape", "link", "x_header", "linkedin_banner".