Skip to main content
Use the Actions API to submit a governed proposal and follow its stored outcome from your application. The five read endpoints inspect Plainrouter records without calling Meta or changing ads. Proposal submission creates a Plainrouter batch; it does not execute a provider change during the request.

Before you start

  • Create a Write Workspace key for the intended workspace, with an active grant covering propose-actions. This grant is required for Actions reads too; a normal Read key is insufficient. Older Admin keys still need the applicable grant and current role.
  • Connect an active Meta ad account owned by that workspace. Confirm its scope with get_account_state.
  • Obtain the workspace’s integer ID and Plainrouter’s internal integer account_id. The latter is different from Meta’s external account ID. The examples use workspace 42 and account 91; replace both.
  • Load the key into PLAINROUTER_WORKSPACE_KEY through your secret manager. A Signals Server secret, Management key, OAuth management credential, or browser session cannot replace it.
Use this base URL for all paths below:
Send Authorization: Bearer <workspace-key> and Accept: application/json. For POST requests, also send Content-Type: application/json.

Select the account

Supply account_id as a query parameter on GET requests and in the JSON body on POST. You may omit it when there is only one eligible active account. Multiple eligible accounts require an explicit selection. An older account-bound key accepts only its bound account. The workspace in the URL must match the key’s workspace. See account selection.

Endpoints

{actionBatch} and {action} are the ULIDs returned by Plainrouter, not Meta object IDs. All successful reads return HTTP 200.

List and inspect actions

The response has a data array and meta.current_page, meta.last_page, meta.per_page, and meta.total. Continue through the returned pages; there is no configurable per_page parameter. Each action contains id, batch_id, workspace_id, type, target_entity_type, target_entity_id, target_entity_name, params, rationale, status, policy_decision, and policy_reasons. Read responses use these flat target fields; proposal input uses a nested target_entity object. To inspect a returned action, request /actions/{action}?account_id=91. The response contains one action under data. To inspect its batch, request /action-batches/{actionBatch}?account_id=91; data contains the batch’s id, workspace and platform-account IDs, status, policy result and reasons, rationale, idempotency key, and actions array. Confirm the scope and read both batch and action statuses.

Read the current policy

The data object includes id, workspace_id, execution_mode, max_spend_delta_percent, hard_account_daily_cap_minor, protected_entities, quiet_hours_start, quiet_hours_end, protect_learning_phase, outcome_check_after_hours, and anomaly_threshold_percent. If no policy has been saved, the read returns effective defaults with id: null; it does not create a policy. This is the current policy, not the frozen mode or policy evidence from an earlier proposal. Review policy and safety before interpreting execution permissions.

Retrieve a decision receipt

Request /actions/{action}/decision-receipt?account_id=91 with the same headers. The response contains these top-level fields, without a data wrapper: A receipt may not exist yet, and a receipt can describe failure. Check its terminal status and verification evidence before reporting success. This endpoint exposes one scoped receipt, not the complete workspace audit export. See receipt interpretation and integrity limits.

Submit a governed proposal

POST uses the same proposal input as MCP: actions (1–25 objects), rationale, idempotency_key, evidence (1–3 declarations), target_source: "human_supplied", and account_id when required. Each action needs its typed parameters, selected target, and rationale. An array of action-name strings is not a valid proposal. Prepare proposal.json using the documented action shapes and evidence rules. For creative work, follow the paused-variant walkthrough. Do not invent target IDs, asset IDs, or evidence. Submission also requires actions.propose; upload and creative-duplication proposals require creative.write.
A new batch returns 201; an idempotent repeat returns 200 with the existing result. Preserve the original idempotency key for the same intent after a timeout. The response includes batch and action IDs, scope, policy reasons, approval requirements, status, and inbox_url; approval_queue_url remains a compatibility alias. Send the reviewer to Inbox and use the reads above to follow the result. These routes do not approve or reject proposals, edit policy, manage keys, or bypass human review. Suggest only approval ends without execution. A successful proposal response is not proof of a provider change or Landed status. The public MCP server card publishes the shared proposal schema. A schema-accepted action type alone does not establish that its execution workflow is available.

Troubleshoot a request

The equivalent five MCP read tools use the same scoped records and output shapes. MCP tool errors follow the MCP protocol rather than this HTTP status table.