Connect to Wavemaker

The session API, the twelve tools over HTTP and MCP, and the CLI reach the same workspace and credits. Start here for auth, base URLs, a first request and how billing applies.

Updated

Wavemaker's developer surface reaches the same workspace, credits and hosted agent as the web app. Use it to have the hosted agent make finished ads from a brief, to drive individual generation and editing jobs yourself, or to give your own agent Wavemaker's tools. This page explains the layers, how to authenticate, and how credits apply, then walks through a first request.

Your path from key to delivered ad
  1. Get a key

    Create a credential in Connections › Developer setup.

  2. Price it

    Quote the brief; a quote holds no credits.

  3. Run it

    Post the brief as a turn and follow its events.

  4. Collect

    Read the turn and download each delivery.

What you can build

  • A backend that sends a brief and receives finished videos, stills, audio or HTML5 banners, checked against a destination spec such as ctv/standard.
  • An editor or review tool where each "make this change" message is one more turn in the same conversation.
  • A pipeline that runs single jobs itself: search for a model or graph, price it, generate, follow the job and download the result.
  • An agent of your own (Claude, ChatGPT, Cursor, Grok or another MCP host) that uses Wavemaker's twelve tools in its own loop.
  • Terminal automation with the wavemaker CLI, once it is released. The CLI has no public release yet.

The three layers

LayerUse it whenEntry point
Session APIYou want the hosted Wavemaker agent to plan and make the work from a briefPOST /v1/sessions, then POST /v1/sessions/{id}/turns
The twelve toolsYou drive each step yourself, from code or from your own agentPOST /v1/tools/{tool} over HTTP, or the same tools at /mcp
CLIYou work from a terminal: sign in, call a tool, run a productionwavemaker

The twelve tools are search, read, write, generate, edit, compose, watch, listen, compare, review, deliver and run. The hosted agent uses the same tools, so anything it can do in a turn, your code can do with tool calls. HTTP, MCP and the CLI return the same result for the same call.

The Python, TypeScript and Go clients wrap the session API and the tools. Python, TypeScript and Go clients says whether each one is on a public registry yet; until a client is published, call the HTTP API or connect over MCP. Small example apps are described in Standalone starter apps.

Base URLs

PurposeURL
API, OAuth issuer and signed downloadshttps://api.wavemaker.io
MCP endpointhttps://api.wavemaker.io/mcp
Web apphttps://app.wavemaker.io

Paths answer directly, with no redirects. Three routes help you check the service before you write code:

  • GET /health answers {"ok": true, "service": "wmcore"} without a credential.
  • GET /v1/tools lists each tool's name, scope, summary and args_schema. It needs a credential.
  • GET /openapi.json lists every route the service answers.

The HTTP API page has the full route reference and a live operation browser.

Authentication options

Every request carries Authorization: Bearer {credential}. The credential fixes the workspace: every read, write and charge is scoped to it.

CredentialWho uses itHow you get it
Developer credentialYour backend, scripts and CIConnections › Developer setup › Create credential in the web app; lasts 1, 7 or 30 days
OAuth sign-inMCP hosts and the CLIThe host or wavemaker login opens a browser sign-in and consent page

Ask for the read, write and run scopes. Together they cover the session API and all twelve tools. publish is needed only for publishing versions and community listings. See Client credentials and provider keys for scopes, expiry, replacement and revocation.

Quickstart: your first brief in five minutes

This walkthrough uses curl. Each step shows an abbreviated response.

  1. In the web app, open Connections, choose the Developer setup tab and select Create credential.
  2. Give it a Name, keep Read projects and results, check Create and edit source and Run work, choose Expires in and select Create credential.
  3. Copy the credential from the Save your credential dialog. It is shown once.
  4. Save it in a private curl config file so it stays off the command line.
  5. Check which workspace the credential belongs to.
  6. Search and price the work. Neither step spends credits.
  7. Create a session, post the brief, follow the events and read the result.

Save the credential and check it:

umask 077
printf 'header = "Authorization: Bearer %s"\n' "$WAVEMAKER_KEY" > ~/.config/wavemaker-curl
curl --config ~/.config/wavemaker-curl --fail-with-body https://api.wavemaker.io/v1/identity
# → 200 {"ok": true, "data": {"schema": "wmcore.identity/1", "workspace": "...",
#        "kind": "api_key", "mode": "live", "scopes": ["read", "run", "write"],
#        "projects": null, "expires_at": 1793000000.0}, "error": null, ...}

Search the catalog. search never spends:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  --json '{"args": {"query": "vertical video ad", "kinds": ["card", "format"], "limit": 5}}' \
  https://api.wavemaker.io/v1/tools/search
# → 200 {"ok": true, "data": {"results": [{"kind": "card", "id": "...", "title": "...",
#        "uri": "wm://card/..."}], "next": "..."}, ...}

Price the brief without starting anything:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  --json '{"text": "A 15-second vertical video ad for a neighborhood coffee shop.",
           "deliverables": [{"id": "spot", "kind": "video", "aspect": "9:16", "duration_s": 15}]}' \
  https://api.wavemaker.io/v1/quotes
# → 200 {"ok": true, "data": {"schema": "wmcore.quote/1", "quote_id": "q_...",
#        "p50_microcredits": 52000000, "p90_microcredits": 81000000,
#        "hold_microcredits": 81000000, "expires_at": ..., "balance_microcredits": ...}, ...}

Create a session. The response carries the controller token you need for every later write:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  --json '{"request_id": "coffee-session-1", "title": "Coffee shop spring spot"}' \
  https://api.wavemaker.io/v1/sessions
# → 201 {"ok": true, "data": {"schema": "wmcore.session/1", "id": "ses_...",
#        "state": "active", "harness": "claude", "collaboration": "autopilot",
#        "controller": {"token": "wmc_...", "expires_at": ..., "generation": 1}}, ...}

Post the brief as the first turn:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  --json '{"request_id": "coffee-brief-1", "controller": "wmc_...",
           "text": "A 15-second vertical video ad for a neighborhood coffee shop.",
           "deliverables": [{"id": "spot", "kind": "video", "aspect": "9:16", "duration_s": 15}]}' \
  https://api.wavemaker.io/v1/sessions/ses_.../turns
# → 202 {"ok": true, "data": {"schema": "wmcore.turn/1", "id": "trn_...", "state": "queued", ...}, ...}

Follow the events with a long poll. Save next_after after you process each page, and read again until the turn ends:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  "https://api.wavemaker.io/v1/sessions/ses_.../events?after=0&wait_s=25"
# → 200 {"ok": true, "data": {"schema": "wmcore.events/1", "items": [
#        {"seq": 2, "type": "turn.queued", ...}, {"seq": 3, "type": "turn.started", ...}],
#        "next_after": 3, "more": false, "session_state": "active", "active_turn_id": "trn_..."}, ...}

When a turn.completed, turn.failed or turn.interrupted event arrives, read the turn by the request_id you posted:

curl --config ~/.config/wavemaker-curl --fail-with-body \
  https://api.wavemaker.io/v1/sessions/ses_.../requests/coffee-brief-1
# → 200 {"ok": true, "data": {"schema": "wmcore.turn/1", "state": "completed",
#        "outcome": {"status": "delivered", "deliveries": [{"deliverable_id": "spot",
#        "mime": "video/mp4", "sha256": "...", "url": "https://api.wavemaker.io/v1/downloads/...",
#        "url_expires_at": ...}]}, "cost": {"charged_microcredits": ..., "settled": true}}, ...}

Check that it worked

  • outcome.status is delivered when every requested deliverable was delivered, and partial when only some were.
  • Each delivery's url downloads the bytes without a credential until url_expires_at. Check the downloaded file against its sha256.
  • cost.charged_microcredits is what the turn cost. Unused hold returns to your balance when the turn settles.

The full session reference, including approvals, interrupts and deliverable specs, is in Make an ad.

The response envelope

Every /v1 JSON response is the same envelope: {ok, data, error, job, cost, hints}.

  • ok: true means data holds the result and error is null.
  • ok: false means data is null and error is {code, message, retryable, retry_after_s?, details?}.
  • The HTTP status follows error.code, for example 401 unauthenticated, 402 insufficient_credits or 429 rate_limited.
  • Branch on error.code and error.retryable, never on message.
  • Unknown request fields are refused with invalid_request and details.path. Ignore response fields you don't recognize; new ones can appear at any time.

See Errors and retries for every code.

Request identity and safe retries

Every write that can start work takes a request_id, a string you choose for that one piece of work.

  • Sending the same request again with the same request_id returns the original result. Nothing runs or is charged twice. Session API replies carry the header Wavemaker-Replayed: true on a replay.
  • Reusing a request_id for different work is refused: request_id_mismatch (409) on the session API and request_conflict (409) on the tools (compose answers conflict, also 409).
  • After a dropped connection or your own timeout, resend the identical request with the same request_id, or read the original. Never mint a new id for the same intent.
  • A spending tool call needs a request_id unless it only prices or checks the work (quote_only or validate_only).

How credits apply to API use

API, MCP and CLI work draws on the same workspace credit balance as the web app. Amounts are integer microcredits: 1 credit is 1,000,000 microcredits.

ActionSpends credits?
search, read, write, watch, deliverNo
Creating a sessionNo. The hosted agent starts on the first turn
A turn of the hosted agentYes: the agent's model use plus every tool call it makes
generate, edit, compose, runYes
listen, compare, reviewYes, for the model call each one makes
Any call with quote_only: trueNo. It returns a price and holds nothing

How a charge works:

  1. A quote gives p50_microcredits (the typical cost) and hold_microcredits (what is reserved). A session quote lasts 1,800 seconds.
  2. When work starts, the hold is reserved against your balance.
  3. When it settles, you are charged the measured usage, which can be below the quote and never exceeds the turn's cap. The rest of the hold is released.

Caps you can set:

  • max_microcredits on a session caps the whole session.
  • max_microcredits on a turn caps that turn. Posting a turn with a quote_id makes the quote's hold the cap, unless you also set max_microcredits.
  • Without a cap, each tool call holds its own quoted cost against your balance. There is no other per-run credit ceiling.

What happens when money runs short:

  • At post time, a balance below the hold is refused insufficient_credits (402) with required_microcredits and balance_microcredits. Top up, then post again with a new request_id.
  • A turn cap too small for the agent's first model calls is refused cap_exceeded (402) with details.minimum_microcredits. The first turn of a new session needs more than later turns.
  • If credits run out mid-turn, the turn ends completed with outcome.status partial or stopped and reason: budget. What was already made is kept.

read of wm://credits returns the workspace balance, and each finished turn links its receipt. When a saved provider key funds a call, the provider's model charge is zero credits; Wavemaker's own compute for the call is still charged. See Client credentials and provider keys. For plan and credit prices, see Plans and Credits.

Limits

LimitValue
JSON request body2 MB. Larger files go through the write upload flow
Long poll on session eventswait_s up to 25 seconds
Long poll on a job (read of wm://job/{id})wait_s up to 85 seconds
Agent turns running at once24 per workspace; one more is refused rate_limited with details.limit hosted_turns_per_workspace and retry_after_s 30
Tool calls per turn10 per second of requested output, at least 300
Requests per credentialA per-credential rate; over it you get rate_limited with retry_after_s

Versioning and changes

  • Each data object carries a schema literal such as wmcore.turn/1. A breaking change bumps the literal; additive fields don't.
  • The session API contract is version 1.0.0-draft.3. The tool schemas are dated, currently 2026-10-18.
  • Older operations at /api/v1/ops/{name} still answer in their older wmlab.result/1 envelope. See Account and workspace API access.

Changes to the API, the tools and the clients are listed in Changes.

Next steps

Related guidance