One remote server, every primitive. Connect it once to the AI you already use, sign in as yourself, and say what you want. Address: https://api.myapihq.com/mcp
The server speaks the Model Context Protocol over Streamable HTTP and signs you in with OAuth. Nothing to install on a server of your own.
https://api.myapihq.com/mcp and press Add.https://api.myapihq.com/mcp.claude mcp add --transport http myapi https://api.myapihq.com/mcphttps://api.myapihq.com/mcp. It discovers sign-in from /.well-known/oauth-authorization-server and registers itself; there is no client id to copy.Then say list my organizations. If it answers, you are connected.
Connecting means this app acts as you. It can reach every organisation in your account, including ones created later, and spend up to a monthly cap, five dollars by default. The consent page asks nothing else.
Limit it later, not at connect time: GET /hq/connections lists every connected app with the organisations it may touch, its cap and when it was last used; PATCH /hq/connections/{id} narrows it to specific organisations or changes the cap; DELETE /hq/connections/{id} revokes it. A revoked connection stops working within a minute. A connection cannot widen itself.
Every call names the organisation it acts on with org_id. A call outside the connection's organisations is refused with a message that names the fix.
56 tools. Each one carries the hints clients use to decide when to ask you first: read tools change nothing, write tools create or change something in your account, destructive tools delete or stop something, and reaches outside marks tools that publish, send, charge or register with the outside world. The set shown in a directory listing may be a subset of this list.
Three tools cover the whole API: search_routes finds a route, describe_route shows its contract, and read_route or write_route calls it. Every other tool is a shortcut for one common task.
| Find and call any route | ||
|---|---|---|
| search_routes | read | Search API routes. Find API operations by keyword: matches method, path, summary, tags and parameter names across the full published API (~350 operations). Use this when no task tool covers the job, then describe_route for the contract and execute_route to call it. |
| describe_route | read | Describe API route. The full contract of one API operation: summary, request body schema, query and header parameters, response shape, and the error codes it can return. Pass the method and templated path exactly as search_routes returned them. |
| read_route | read | Read API route. Read any published MyAPI operation by concrete path — a GET against the API described at https://api.myapihq.com/schema/v1/openapi.json (search_routes finds the path, describe_route shows its contract). Reads only: it never changes anything. Only routes scoped to the connection's org are callable. |
| write_route | destructive · reaches outside | Write API route. Call a published MyAPI operation that changes something — POST, PUT, PATCH or DELETE against the API described at https://api.myapihq.com/schema/v1/openapi.json (search_routes finds the path, describe_route shows its body). Only routes scoped to the connection's org are callable, and operations that need a live confirmation (domain register, org delete, payment charges and refunds) are refused here — use their dedicated tool. |
| execute_route | destructive · reaches outside | Execute API route. Call any published API operation by method and concrete path — the whole API through one tool. The capability cap behind this connection is load-bearing: only routes scoped to the connection's org are callable (the path must carry this org's id), routes outside the published schema are refused, and operations that need a live confirmation (domain register, org delete, payment charges and refunds) are refused here — use their dedicated flow. |
| Account, organisations, keys | ||
| check_balance | read | Check balance. Return the account balance, credits, and whether a payment method is on file. These are account-level finances, so this needs a connection that acts as the account (the default when you connect); a connection limited to one org is refused. |
| org_list | read | List organisations. List the organisations this connection can see. Takes NO required arguments — an org-bound connection sees exactly its own org, a connection that acts as the account lists the whole account. org_id is optional and, if given, must match the bound org. |
| create_org | write | Create organisation. Create an organisation. Needs a connection that acts as the account (the default when you connect); a connection limited to one org is refused. org_id names an EXISTING org in the account (the anchor for the call — every tool takes org_id); the new org is created beside it and returned with its id. |
| key_list | read | List API keys. List the account's active API keys — id, name, kind, grants, org lock, spend cap, and lineage spend. The raw key is never returned. Key management is account-level, so this needs a connection that acts as the account (the default when you connect); a connection limited to one org is refused. |
| key_mint | write | Mint API key. Mint a scoped API key and return it ONCE. grants and spend_cap_cents are REQUIRED — name exactly the slots the key may use (or {"*":"write"} on purpose) and its spending ceiling in cents; an agent must never mint a key wider or more open-ended than it needs. The key is attenuated to the minting connection: its grants must be a subset of the caller's. Needs a connection that acts as the account. |
| key_revoke | destructive | Revoke API key. Revoke an API key by id — the key stops working immediately and cannot be restored. Destructive, so it is a two-step confirm: the first call returns immediately, refused with CONFIRM_REQUIRED carrying a single-use confirm_token; repeat the SAME call with confirm_token to revoke. The first call never blocks — this is an incident-response and automation path, so it does not wait for a live approval. Needs a connection that acts as the account. |
| Sites, domains, launch | ||
| publish_page | destructive · reaches outside | Publish page. Publish HTML to a slug on the org's site and return its live_url. Pushing to a slug that already has a page OVERWRITES that page. If the org has exactly one funnel it is used; with more than one, funnel_id is required and the refusal names the candidates. |
| register_domain | destructive · reaches outside | Register domain. Register a new domain into the org. This spends real money and cannot be undone, so it is a two-step confirm flow: the first call is refused with CONFIRM_REQUIRED and carries will_do plus a single-use confirm_token (valid 10 minutes); show what will happen to the person operating the client, then repeat the SAME call with confirm_token to register. Check price and availability first with execute_route on GET /domain/orgs/{org_id}/check/available/{domain}. |
| domain_status | read | Domain status. Status of one org domain: provisioning state, DNS, expiry, email readiness. |
| launch_site | destructive · reaches outside | Launch site. Launch a business on a domain in one call: site + published page + email + form-to-CRM wiring, optionally an auth tenant. Async saga: the call starts a launch job and waits server-side up to 90 seconds (SSE clients with a progressToken hear step progress), then returns the job with per-step statuses. Money: creating the job charges the composition fee, and each step charges at its catalog price as it runs. When the domain is NOT already in the org the launch REGISTERS it — that spends registrar money and cannot be undone, so the purchase is confirmed first, like register_domain: the first call is refused with CONFIRM_REQUIRED carrying will_do (the domain and the total estimate) plus a single-use confirm_token (valid 10 minutes) — repeat the SAME call with confirm_token to start; a client with the elicitation capability is asked live on the SSE stream instead. A launch on a domain the org already owns needs no confirmation and skips the purchase. A refusal before the job is created (the confirm, or the combined-estimate 402) spends nothing. A failed step halts its dependents and the job rests in needs_attention — fix the cause named in the step's error, then resume with launch_status resume:true; completed steps are never repeated or re-charged. A job still running when the wait ends keeps running server-side — poll launch_status. |
| launch_status | destructive · reaches outside | Launch status. Check a launch job started by launch_site, or resume one that rests in needs_attention. Without resume, this only reads the job: overall status plus every step with its own status, result and error code (the codes are the underlying primitives' own). With resume:true the launch re-runs from its first incomplete step AFTER you fix the cause of the failure — completed steps are not repeated and not re-charged, but re-run steps charge as they run. A resume that would run the domain_register step for a domain the org still does not own is a purchase, so launch_site's confirmation applies (CONFIRM_REQUIRED + confirm_token, or the live elicitation question); a resume of non-purchase steps needs no confirmation. A resume whose cause is knowably unfixed is refused with LAUNCH_STEP_BLOCKED naming the fix. |
| upload | write | Upload file. Stage a file for upload WITHOUT sending its bytes through the tool call — the MCP-aligned way to move large content. Returns upload_url (a single-use PUT target, no auth, expires in 300s) and upload_id. Do one HTTP PUT of the file bytes to upload_url (set Content-Type), then commit it to a stored asset with execute_route POST /storage/orgs/{org_id}/uploads/{upload_id}/commit (returns the asset's url). Use this instead of base64 for anything large — base64 inside a tool call inflates ~33% and hits body-size caps. Up to 25MB per file. |
| storage_list | read | List storage assets. List the org's stored assets, newest first, keyset-paged. |
| send_email | write · reaches outside | Send email. Send an email from an org mailbox. from must be a mailbox on a domain that belongs to this org, with sending activated. Supply html and/or text, or a template_id. Pass idempotency_key to make retries safe — a repeated key replays the first response instead of sending again. |
| create_mailbox | write · reaches outside | Create mailbox. Create a mailbox on an org domain. Sending is activated in the same call by default, so affordability for both is checked before either is charged. The domain needs email infrastructure first — a DOMAIN_NOT_READY refusal names POST /domain/orgs/{org_id}/{domain}/email-infra as the fix. |
| activate_sending | write · reaches outside | Activate sending. Enable outbound sending for a mailbox (its domain must belong to this org). Sets up the account's sending credential if needed, then enables the mailbox and grants its initial quota. Use this when a mailbox was created without activate_sending. |
| warmup_start | write · reaches outside | Start warmup. Start deliverability warmup for a mailbox (its domain must belong to this org). Sending must already be activated. |
| warmup_stats | read | Warmup stats. Get warmup throughput / inbox-placement stats for a mailbox (its domain must belong to this org). Requires warmup to be active — a mailbox that never started warmup has no stats and says so. |
| Payments | ||
| payment_list | read | List payments. List the org's payment charges, newest first. Read-only. Each carries amount, currency, status (pending | succeeded | refunded), and timestamps. The org must have connected Stripe (POST /payments/orgs/{org_id}/connect); charge creation and refunds are not on the tool surface yet — use execute_route for those. |
| payment_status | read | Payment status. Get one payment charge by id: amount, currency, status and timestamps. Read-only. |
| Data and workflows | ||
| kv_get | read | Read KV key. Read one key from an org KV namespace. |
| kv_set | destructive | Write KV key. Write a key in an org KV namespace, or delete it with delete:true. The namespace is created on first write. Optional etag does a compare-and-swap: the write applies only if the stored etag matches. Pass value as the JSON itself — value: {"text": "hi"} is correct; value: "{\\"text\\": \\"hi\\"}" is wrong (that is the JSON as text). A string value is refused unless value_is_string is true, which stores a string VALUE deliberately. |
| crm_search | read | Search CRM contacts. Search the org's CRM contacts. All filters are optional; results are newest-engagement-first, with total and has_more for paging. |
| crm_add_contact | write | Add CRM contact. Create or upsert a CRM contact by email. An existing email returns the contact unchanged. |
| workflow_wire | write · reaches outside | Wire webhook to actions. Wire a webhook to actions in one call: makes sure an inbound webhook endpoint exists (pass endpoint_id to reuse one, or a new one named endpoint_name is created), creates a workflow whose steps run on every delivery, and enables it. Step types include email, slack and http. Returns the endpoint's ingest_url (POST deliveries to it) and the workflow id. To auto-ingest each delivery as a CRM contact, set crm_email_path to the dot-path of the email in the payload (e.g. email, or contact.email) — it applies only when this call creates the endpoint. |
| Compute and code | ||
| deploy_function | write · reaches outside | Deploy function. Create an edge function and return its metadata plus the scoped API key (shown ONCE). The bundle must be a single JS file whose default export is an object with a fetch handler: export default { fetch(request, env) { return new Response("ok") } } — a bundle without a fetch handler is refused. The JS bundle is a separate upload: either POST the file to /function/orgs/{org_id}/functions/{id}/bundle directly (multipart field 'bundle'), for example: curl -H "Authorization: Bearer $MYAPI_KEY" -F bundle=@worker.js https://api.myapihq.com/function/orgs/{org_id}/functions/{id}/bundle — or stage the file with the begin/commit flow: POST /storage/orgs/{org_id}/uploads/begin returns a short-lived PUT URL, then POST .../uploads/{upload_id}/commit. The bundle call returns the live invocation_url; poll readiness with function_status. |
| function_status | read | Function status. One function's state: deployment status, invocation URL, trigger. |
| redeploy_function | destructive · reaches outside | Redeploy function. Deploy or REDEPLOY a function's code — upload a new JS bundle to an existing function. This is how you ship a code change: the function id and invocation URL stay the same, env is preserved, and the scoped key is rotated. Give the bundle as bundle_base64 (base64 of the single JS file) for a small bundle, or bundle_ref (an upload_id from the `upload` tool) for a large one — one is required. Two-step confirm: because this ships code to a live function, the first call returns CONFIRM_REQUIRED with a single-use confirm_token; repeat the same call with it to deploy. Returns status=provisioning; poll function_status until ready. |
| deploy_container | destructive · reaches outside | Deploy container. Deploy a container from an already-built image. Creates the container when the name is new, then deploys the image; an existing name deploys onto that container. To deploy from SOURCE instead of a built image: call container_source_upload for the container to get a direct-PUT upload_url + source_ref, PUT the gzipped build-context tar to it, then deploy with source_ref on POST .../containers/{id}/deploy (via execute_route). The bytes never pass through a tool call, so the context can be large. Poll the build with container_status. |
| container_status | read | Container status. One container's state: serving revision, build status, URL, env names. Poll this after deploy_container. |
| container_source_upload | write | Upload container source. Open a direct-PUT slot to upload a container's build context (a gzipped tar), so you can deploy from SOURCE without sending the bytes through a tool call — the same begin→PUT→ref shape as the `upload` tool, but staged where the builder reads it, so a large context does not proxy through the API. Returns upload_url (a single-use PUT target, expires in 2h) and source_ref. PUT the .tar.gz to upload_url with Content-Type: application/gzip, then deploy with source_ref on POST /container/orgs/{org_id}/containers/{id}/deploy (via execute_route). |
| container_run | write · reaches outside | Run job now. Run a type=job container NOW, instead of waiting for its cron schedule. This is what makes an event-driven job start on request rather than on the next tick: a service that takes a request can trigger the job that handles it in the same breath. Returns the started execution's name; the run proceeds asynchronously — poll container_runs for its status. 422 if the container is not a job; 409 if it has not been deployed yet. |
| container_runs | read | List job runs. List a job container's recent executions (run history) with exit counts and timing, newest first — how you verify a job you triggered actually ran and how it ended. 422 if the container is not a job. |
| container_logs | read | Container logs. Read a container's recent runtime logs. Polling shape: each call returns the newest lines — call it again for fresh output; there is no stream. Build output is on GET /container/orgs/{org_id}/containers/{id}/build-logs via execute_route. |
| git_repo | destructive | Git repository. Manage git repositories. action: create (needs name), list, get (needs name), or delete (needs name; two-step confirm — the first call returns CONFIRM_REQUIRED with a single-use confirm_token, repeat with it to delete). get/create return a clone block with the clone/push URL and how to authenticate it. |
| git_commit | destructive | Git commit. Atomic multi-file commit — write code with no clone/push. changes is an array of {path, content_base64} (or content for text, content_ref for a large file staged via the upload tool, or delete:true). base is the expected current branch tip SHA for optimistic concurrency (409 on a stale base); empty base means the branch must not yet exist. The field is `changes`, NOT `files`. |
| git_read | read | Git read. Read a repo's contents at a ref. With path: return that file's bytes (base64). Without path: list the tree at the ref. |
| git_history | read | Git history. Review history. action: log (commits on a ref, newest first), show (one commit by sha), or diff (between base and head). |
| git_branches | destructive | Git branches. Manage refs and merge. action: list (branches + tags), create_branch (name + from), delete_branch (name), create_tag (name + ref), or merge (target + source, fast-forward only). |
| git_clone_url | read | Git clone URL. Return the smart-HTTP clone/push URL for a repo and how to authenticate it — for a human or CI using a real git client (clone/push with full history, which the JSON tools cannot do). Authenticate with any MyAPI api-key that holds the `git` grant as the HTTP Basic password. |
| Intelligence | ||
| llm_task | read | LLM task. Run an objective language task over an input: classify (with labels, optional multi), extract (with schema), summarize (optional style), or draft (kind, optional prompt). The model behind it is chosen by the platform; tier is a routing hint. |
| generate_image | write · reaches outside | Generate image. Generate an AI image from a prompt. Async: this returns a job_id at once — poll image_status until status is done, which carries the image URL. Cost is per image at the model's catalog rate. |
| image_status | read | Image job status. Poll an image-generation job started by generate_image. status is pending, running, done or failed; done carries the image URL. |
| Feedback | ||
| feedback_list | read | List feedback. List feedback submitted to the org's widgets, newest first. total counts every match; has_more flags a truncated page. |
| feedback_resolve | write | Resolve feedback. Claim a piece of feedback as fixed and wait for the reporter to confirm. This is a CLAIM, not a final close: the item moves to resolved_claimed and the reporter confirms or reopens it. Pass an optional reply, shown to the reporter on the thread. |
| feedback_comment | write | Comment on feedback. Post a message to a feedback item's thread WITHOUT changing its state — progress the reporter sees between the report and the fix (e.g. "working on this"). For a note that accompanies a fix, use feedback_resolve's reply instead. |
| feedback_test | read | Get feedback test. Get the generated test for a feedback item — a spec written from the item's interaction trace whose assertions are that the captured console errors and failed requests no longer happen. Only meaningful for an item whose testable flag is true; one with no captured failure says so and fails loudly rather than asserting nothing. |
| Outcomes and goals | ||
| outcome_create | write | Plan an outcome. Sabaki: say what you want in plain words; get back an agreeable spec — 1-6 claims about what will be TRUE afterwards (each naming how it will be proven), disclosures for anything that spends money, messages people, or changes a live site, undo notes, and the derived step plan — or 1-3 questions when the request is ambiguous (answer with outcome_agree answers). NOTHING EXECUTES from this call: agreement is a separate explicit step (outcome_agree), which is what starts the work. Planning is metered at catalog LLM rates and charged per call. |
| outcome_status | destructive · reaches outside | Outcome status. Read one Sabaki outcome (request, status, spec, plan, per-step execution status), or list the org's outcomes when outcome_id is omitted. With resume:true, a needs_attention or paused outcome re-runs from its first unfinished step AFTER you fix the cause named in the failed step's error — completed steps are never repeated, but re-run steps take their effects and charges again. |
| outcome_agree | destructive · reaches outside | Agree to outcome. Agree to an outcome's spec — WHICH STARTS THE WORK — or steer it. Plain agree approves every disclosed step (money, messages, live-site changes included: the disclosure sentences you read ARE what you approve) and the plan runs step by step; watch it with outcome_status. Pass answers to answer the planner's open questions, or message to ask for the spec to be different — both replan without executing and charge like a plan. |
| goal_status | read | Goal status. Sabaki goals: what the user wants true about the WORLD ("first paying customer"), tracked over real events and never promised. Lists the org's goals with progress, or reads one with its timeline of counted events when goal_id is given. Goals are created by planning a goal-shaped request with outcome_create (the spec's single claim is "you'll be told when it happens", plus proposed outcomes that would serve the goal). |
Spend: a connection's monthly cap, five dollars unless you change it, and the account balance behind it. Every paid call is charged against the balance at the published rate and attributed to the connection that made it. Rate: calls are rate-limited per key; a refusal says how long to wait. Planning tools that call a model can take a minute to answer.
The server processes what your agent sends it only to carry out the call, stores what the call creates in your account (pages, contacts, mailboxes, keys, deployments), and keeps operational logs of calls without their content. We do not train models on your data and we do not sell it. The privacy policy names the infrastructure that processes data on our behalf, and the terms say what you are responsible for when an agent acts as you.
Write to simon@myapihq.com. Include the request id from any refusal; every response carries one.