The builder exposes an MCP (Model Context Protocol) server, so an AI agent —
Claude, Cursor, ChatGPT/Codex, or your own client — can drive it: start a build
from a reference image, iterate on the popup, and turn the result into a
campaign. This article covers where to mint a credential, what the endpoint
speaks, and where its limits are.

Create an API key

Go to Settings → API keys. The panel opens with:


Connect the OptiMonk MCP server to AI agents like Claude or Cursor.

next to a Documentation link that points at the in-app article
/docs/authentication.

  1. Type a Key name (placeholder: "e.g. Claude connection") — the name is
    required; leaving it empty gives you "Give the key a name."

  2. Press New key.

  3. The Key created panel appears with the full secret and the warning "You
    can only see the full key now — copy and store it safely. It can't be shown
    again." Use Copy.

Afterwards the list shows only the key's 14-character prefix followed by dots,
its "last used" date and its creation date. Secrets are stored as a SHA-256
hash, never in plaintext, so there is no way to recover one — mint a new key
instead. Revoke kills a key immediately: "Any agent using this key loses
access immediately. This can't be undone."

Keys look like omk_live_<43 base64url chars>. The same page also lists
Connected apps — the OAuth equivalent, for clients that can run a browser
consent flow: "Apps you approved with Connect. They act on this account until
you disconnect them."

The endpoint

POST https://<your-host>/mcp
Authorization: Bearer omk_live_…

Transport is streamable HTTP and stateless — the server creates a fresh
session per request, so GET /mcp and DELETE /mcp both answer 405 method not allowed (stateless). The server identifies itself as optimonk-popup-builder
version 1.0.0.

Auth details worth coding against:

  • The bearer must start with omk_. An omk_at_… prefix is treated as an OAuth
    access token, anything else as an API key.

  • A missing, malformed, revoked or expired credential gets 401 with a
    WWW-Authenticate header. When OAuth is enabled that challenge carries a
    resource_metadata pointer (RFC 9728), which is what lets a capable client
    start the consent flow itself instead of asking you for a key.

  • Requests from a browser origin outside the allow-list get 403.

  • Request bodies are capped at 1 MB; larger ones get 413.

  • If both the API-key and OAuth doors are switched off server-side, /mcp
    answers 404 mcp disabled.

Both credential kinds carry the same four scopes: build:read, build:write,
campaign:read, campaign:write. A key created from the settings UI gets the
full set. Call whoami first — it returns the account id, the credential label,
the scopes and canPublish, which disambiguates "object not found" from
"credential pointed at the wrong account".

What the tools can do

26 tools are exposed. Grouped by job:

  • Identity:whoami.

  • Build:build_popup, get_build_status, watch_build,
    upload_reference_image, get_popup_html, get_popup_preview.

  • Iterate:edit_popup, patch_popup, restore_revision.

  • Design conversation:start_design_thread, send_design_message,
    get_design_thread, get_concept_board, select_variant.

  • Campaign:list_campaigns, get_campaign, create_campaign,
    set_campaign_name, get_campaign_settings, set_campaign_settings,
    publish_campaign.

  • Coupons:get_coupon, set_coupon.

  • Jobs:get_job, watch_job.

build_popup takes a publicly fetchable PNG/JPG/WEBP plus the target store
hostname and returns a runId. Builds are asynchronous: prefer watch_build
(it waits and emits progress notifications) over a polling loop, and use
get_build_status for a single read or from a client that cannot hold a request
open. interrupted is not a terminal status — the run resumes; treating it
as a failure is the most common mistake on this surface.

create_campaign makes a DRAFT campaign and needs a designer-session-backed
build: start_design_thread creates one, a standalone build_popup run does
not. publish_campaign publishes to OptiMonk and activates the campaign.

What it is not for

  • It is not the analytics or subscriber API. There is no tool for reports,
    leads or submits — the tool list above is the whole surface.

  • It cannot configure ESP/CRM integrations. No tool connects Klaviyo,
    Mailchimp or a webhook; that is UI-only, in the campaign hub.

  • It cannot manage the account. No user, domain, billing or API-key
    administration; key and connected-app endpoints are cookie-authenticated on
    purpose, so a credential can never enumerate or revoke its siblings.

  • Do not branch on HTTP status alone. MCP tool refusals — including scope
    errors and exhausted budgets — come back as isError: true with prose in
    content, inside a JSON-RPC HTTP 200 response. They do not use the REST typed
    error envelope or the rate-limit headers.

  • Do not retry a timed-out build blindly. Pass idempotencyKey to
    build_popup (the REST equivalent is an Idempotency-Key header, honoured
    for 24 hours per account); a retry with the same key returns the first run
    instead of paying for a second generation.

Scripting instead of an agent?

The same credentials work against a REST surface described by an OpenAPI 3.1
document. Both GET /.well-known/openapi.json and GET /llms.txt are readable
without a credential. REST errors are typed (type + code + request_id;
branch on those, not on message), rate-limited responses carry
X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a
budget refusal is a 429 with Retry-After.