REST API: tools, tasks and accounts
Agent Planners' REST API lets your own system list, describe and call the same platform tools as the MCP server, start and follow tasks, and list connected accounts with plain HTTP and JSON. Authenticate with an API key or an OAuth access token; every call keeps the workspace's scopes, approvals, guardrails, credits and audit trail.
What it is
Base URL: https://www.agentplanners.com/api/v1. Every request sends Authorization: Bearer with an API key (ap_live_…) or an OAuth access token (apo_at_…); every answer is JSON. Any origin may call it with a bearer credential (it never uses cookies), so a browser app can call it directly — with a public OAuth app and the person's own token, never with an API key in the page.
The tool endpoints are the MCP server's tools in plain HTTP: the same tool names (family__tool, for example google_ads__mutate_campaign), the same scopes and platform choice, the same approval queue, guardrails, credits and audit trail. A machine-readable description is at https://www.agentplanners.com/api/v1/openapi.json (OpenAPI 3.1, public).
Which credential
- Your own system in your own workspace: an API key from API & MCP (New key), or a private OAuth app when people should sign in.
- A product that serves many Agent Planners customers: a published OAuth app. Each customer's admin connects it from their own workspace and chooses its permissions and platforms; your server calls this API with that customer's access token. See Publish an app to other workspaces.
- An OAuth token is bound to the resource it was requested for: ask for resource=https://www.agentplanners.com/api/v1 (this API) or the origin https://www.agentplanners.com (this API and the MCP server). A token requested without resource is for the MCP server only and is refused here.
- Access tokens last 1 hour; refresh tokens rotate at every refresh and expire after 30 days without use; a connection ends after 365 days. The OAuth guide has the whole flow.
Endpoints
| Request | Needs | What it does |
|---|---|---|
| GET /api/v1/me | Any valid key or token | What this credential may do: workspace, scopes, platforms, platform tools, whether writes wait for a person, rate limits. Call it first. |
| GET /api/v1/tools | A tools scope | The tools this credential may call. q ranks them by what you want to do; family, kind=read|write, limit and offset filter and page; schema=1 adds each JSON Schema. Free. |
| GET /api/v1/tools/{name} | A tools scope | One tool's documentation, JSON Schema, annotations, and whether this credential may call it — and why not. Free. |
| POST /api/v1/tools/{name} | tools:read for a read, tools:write for a write | Runs the tool. The body is its arguments (or { arguments: {…} }); the Idempotency-Key header becomes its idempotencyKey. |
| GET /api/v1/requests/{id} | A tools scope | The decision on a write that waited for a person: pending_approval, approved, executed, failed, rejected or expired, and the platform's answer once it ran. |
| GET /api/v1/accounts | accounts:read or any tools scope | The connected accounts (platform, id, name, status). The id is the accountId a tool takes. |
| GET /api/v1/tasks | tasks:read | The workspace's tasks, newest first (limit, skip and status filter them). |
| POST /api/v1/tasks | tasks:write | Starts a task from a goal; it runs on the workspace's credits under its approval rules. |
| GET /api/v1/tasks/{taskId} | tasks:read | A task's status, plan and report. |
Find and call a tool
Search by intent instead of guessing a name, read the schema, then call. A search lists only the tools this credential may call: the workspace's connected platforms, the platforms and platform tools the person allowed, and writes only with tools:write.
BASE=https://www.agentplanners.com/api/v1
TOKEN=apo_at_... # or an API key, ap_live_...
# What this credential may do (free)
curl "$BASE/me" -H "Authorization: Bearer $TOKEN"
# The account to work on: its id is the tool's accountId
curl "$BASE/accounts" -H "Authorization: Bearer $TOKEN"
# Find a tool by what you want to do (free)
curl "$BASE/tools?q=update+campaign+tracking+template&kind=write" -H "Authorization: Bearer $TOKEN"
# {"ok":true,"query":"update campaign tracking template","tools":[{"name":"google_ads__mutate_campaign","kind":"write","required":[...],...}]}
# Its documentation and JSON Schema (free)
curl "$BASE/tools/google_ads__mutate_campaign" -H "Authorization: Bearer $TOKEN"
# Run it
curl -X POST "$BASE/tools/google_ads__mutate_campaign" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: utm-suffix-campaign-111222333-v1" \
-d '{"accountId":"<id from /accounts>","campaignResourceName":"customers/1234567890/campaigns/111222333","finalUrlSuffix":"utm_source=google&utm_medium=cpc"}'
# 200 {"ok":true,"result":{...}} it ran
# 202 {"ok":true,"queued":true,"requestId":"rwq_3f9a1c2b4d5e","statusUrl":"/api/v1/requests/rwq_3f9a1c2b4d5e"} it waits for a person
# After a 202: poll the decision
curl "$BASE/requests/rwq_3f9a1c2b4d5e" -H "Authorization: Bearer $TOKEN"
# {"ok":true,"result":{"requestId":"rwq_3f9a1c2b4d5e","status":"executed","providerStatus":200,...}}Writes: applied at once, or waiting for a person
- A write answers 200 when it ran and 202 when it waits for an admin or editor in the workspace to approve it on API & MCP → Write approvals. A 202 means nothing has changed on the platform yet.
- Which one depends on the connection: an OAuth connection waits for approval unless the workspace admin who approved it chose to apply ordinary changes at once; an API key follows the Tool writes setting it was created with. GET /api/v1/me says which.
- Deletes, activations, code for a website and other changes a platform marks as a person's decision always wait for a person, whatever the setting. The workspace's guardrails (change caps, spend caps, protected names) apply to every write.
- Poll GET /api/v1/requests/{id} every few seconds, or when your user next opens the page, until the status is executed, failed, rejected or expired. An unanswered request expires.
- Send an Idempotency-Key header (up to 128 characters) with every write: retrying with the same key answers with the first result instead of writing twice.
Status codes
| Status | Meaning |
|---|---|
| 200 | The tool ran; the body is { ok: true, result }. A notices array, when present, carries extra lines such as low credits. |
| 202 | A write is queued for a person: { ok: true, queued: true, requestId, statusUrl }. Poll the statusUrl (GET /api/v1/requests/{id}). |
| 400 | The body is not valid JSON or not an object of arguments. |
| 401 | The key or token is missing, expired or revoked, or was issued for the MCP server only; WWW-Authenticate names the metadata. |
| 402 | Not enough credits for this call; the error says how many it needs and how many are left. |
| 403 | Not allowed for this credential: a missing scope, the plan, or the platforms or platform tools the person allowed. |
| 404 | No such tool, or no such request in this workspace. |
| 409 | No connected account for the tool's platform in this workspace. |
| 413 | The body is larger than 1 MB. |
| 422 | The tool ran and answered with an error, or refused the arguments; error says why. |
| 429 | Rate limited; retry after the Retry-After header's seconds when it is sent. |
| 503 | Something the answer depends on could not be read (it fails closed); retry with the same Idempotency-Key. |
Example: a link-management app keeps UTM parameters current
A UTM / link-management product that serves many Agent Planners customers publishes one OAuth app. Each customer's admin connects it from their own workspace with tools:read and tools:write and the platforms it should touch. The app then searches GET /api/v1/tools?q=tracking+template for that customer and calls the tool for each platform the customer connected:
- Google Ads: google_ads__mutate_campaign — trackingUrlTemplate, finalUrlSuffix and urlCustomParameters on a campaign.
- Microsoft Advertising: bing_ads__update_campaign — trackingUrlTemplate, finalUrlSuffix and urlCustomParameters.
- Meta: meta_ads__create_creative with urlTags (UTM) on a new creative — no tool edits an existing Meta creative.
- Pinterest: pinterest_ads__apply_utm_params. Reddit: reddit_ads__update_ad_click_url. Snapchat: snapchat_ads__update_creative_url. Display & Video 360: dv360__update_creative_urls.
- Klaviyo: klaviyo__update_tracking_settings — the account's UTM defaults for campaigns and flows.
- Each change waits for a person in the customer's workspace unless their admin chose otherwise: show it as pending in your product until GET /api/v1/requests/{id} says executed.
Tasks and accounts
Instead of calling tools one by one, hand Agent Planners a goal: POST /api/v1/tasks starts a task that plans, reads the data and proposes changes under the workspace's approvals, and GET /api/v1/tasks/{taskId} returns its status and report.
curl -X POST "$BASE/tasks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"goal":"Summarize the last 7 days of Google Ads performance"}'
# {"taskId":"task_ab12","status":"planning","url":"..."}
curl "$BASE/tasks/task_ab12" -H "Authorization: Bearer $TOKEN"Frequently asked questions
- Is the REST API the same as the MCP server?
- For tools, yes: GET /api/v1/tools, GET and POST /api/v1/tools/{name} and GET /api/v1/requests/{id} run the MCP server's own tool calls, with the same names, scopes, approvals, guardrails, credits and audit trail. MCP suits AI hosts such as Claude, ChatGPT and Codex; REST suits a backend or a web app.
- Do I need an API key?
- No. Your own scripts can use an API key; a product other workspaces connect uses OAuth — each customer approves it in their own workspace and your server receives their access token. Request it with resource=https://www.agentplanners.com/api/v1.
- Why did my write answer 202?
- It waits for a person in the workspace to approve it. Poll GET /api/v1/requests/{id} for the decision; nothing changes on the platform before it is approved.
- What does a call cost?
- Listing and describing tools is free. A tool call is billed in credits to the workspace it runs in, the same as over MCP; 402 means the workspace needs to top up.