Are Actions Tests still available?
No. Actions Tests and the former/tests and /tests/{ad_test} routes beneath the workspace API base are removed, along with actions.tests.* MCP tools. Published SDKs can retain those methods or generated type names; use the current contract and supported Actions rules, previews, proposals and receipts. A removed Test route is not restored by a new key or grant.
Before you start
- Use a Read or Write Workspace key for record/policy reads with
read-actions; older grants withpropose-actionsremain compatible for reads. Previews and proposals require Write andpropose-actions. Older Read keys without either operation need replacement or fresh authorization. Current workspace role and account scope still apply. - 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 workspace42and account91; replace both. - Load the key into
PLAINROUTER_WORKSPACE_KEYthrough your secret manager. A Signals Server secret, Management key, OAuth management credential, or browser session cannot replace it.
Authorization: Bearer <workspace-key> and Accept: application/json. For POST requests, also send Content-Type: application/json.
Select the account
Supply a positive integeraccount_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 belong to the key’s authorized set. If workspace_id also appears in the query or JSON body, it must match the URL. Calls operate on one workspace; selectors cannot widen access. 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
pending, verified, or execution_uncertain; batch-only values such as completed are invalid. Set limit from 1–100 (default 25); there is no configurable per_page request parameter. page defaults to 1 when omitted and accepts integers from 1 to 10000000000000000 inclusive. Invalid values return HTTP 422 with a page field error. JavaScript callers should use safely representable integers and follow returned cursors rather than constructing huge page numbers. Actions are ordered by action ID descending. Repeat with meta.next_page_arguments, preserving account and status, until meta.next_cursor is null. The response-size budget can return fewer complete rows than requested.
To inspect a returned action, request /actions/{action}?account_id=91 and use the single-action reference. To inspect its batch, request /action-batches/{actionBatch}?account_id=91 and use the batch reference. Confirm the scope and read both batch and action statuses.
Batch action reads also accept limit from 1–100 (default 25). Pass data.next_cursor as integer cursor, keeping the batch and account, until null. Inspect data.total, data.truncated and data.continuation. A partial action page cannot establish that the whole batch completed.
Identify rule and outcome-generated proposals
Readproposer.type before interpreting an action’s evidence. For system proposals, the published OpenAPI schema supports two evidence shapes:
Do not require
original_action_id or outcome on every system proposal. A rule proposal has a different evidence shape; its system proposer does not establish approval, execution or restoration.
Interpret current disposition and recovery
List, single-action, and batch reads include each action’s currentdisposition alongside its historical status and batch_status. The action response reference defines the fields. Use receipt_status for current execution-receipt state and outcome_status for later measurement; measurement is separate from execution verification. An unavailable reason, check time, or recovery value remains unknown, not successful.
Read compensation_reason_code with recovery_disposition using the recovery interpretation. late_restored records later compensation evidence without rewriting the earlier action or batch result. The batch response reference defines restoration_summary; all_receipts_compensated_late means every existing execution receipt in that batch is compensated and at least one has late-restoration evidence. It does not mean every proposed action executed, and it does not turn the batch into a successful original execution.
Keep nullable values as unknown. A historical rollback_incomplete can remain alongside later restoration evidence; read both rather than replacing one with the other.
Read the later outcome payload
When recorded,disposition.outcome_payload contains the later comparison. Read it alongside outcome_status and outcome_checked_at, rather than using an action’s verified status as a performance verdict.
Here, spend and cost use ISO currency minor units, with decimal strings where needed. The cost can contain fractional minor units. These are different from the decimal currency amounts in inventory
metrics.spend and Meta’s budget-unit representation. Preserve precision and use the accompanying currency when displaying them.
Resume compares the target with the rest of the ad account over the same completed days. Budget changes compare the target before and after the provider-write day. See comparison windows, freshness and loss rules. A missing payload or null count is unknown. A lost result can create an inverse proposal governed by Ask/Full; follow its batch and verification separately.
Which conversion definition did the evidence use?
Current counted evidence can includeconversion_definition.version, conversion_definition.events and observed conversion counts. Read those captured choices with the evidence window, rather than substituting today’s workspace settings. Existing outcome checks, approvals and provider verification still apply; changing a conversion definition does not establish a successful advertising change. See frozen conversion definitions.
Configure account rules
Use the generated action-rule endpoints in the sidebar or the MCP account-rule tools to list, create, inspect and update rules. Create a disabled rule, then explicitly enable it. Rule reads accept Read keys; rule writes require Write and their own grants. Actions record reads accept Read keys withread-actions or compatible propose-actions access. A rule-generated budget increase requires human approval even in Full. Published SDK versions should not be assumed to include rule methods; use the published OpenAPI contract for REST or the discovered MCP contract.
Read the current policy
id, workspace_id, execution_mode, 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 decision-receipt reference defines its response. The stored document records the terminal outcome and available verification evidence. document_sha256 is a digest of the canonical document, not the downloaded JSON file’s formatting; chain_entry identifies the receipt’s audit event.
The stored document, digest, and chain reference remain immutable. The separate disposition can reflect later recovery; do not include it when checking document_sha256. 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.
What does receipt_not_available mean?
For a visible action without an execution receipt, the REST endpoint returns HTTP 404 with this error:
404; do not interpret every 404 as receipt_not_available. The MCP receipt tool retains its not_found tool error.
Preview a proposal without submitting it
UsePOST /actions/dry-run to inspect policy decisions and proposed diffs before creating a batch. Use the complete dry-run request schema and the same permissions as submission: a Write Workspace key, an active propose-actions grant, and actions.propose. Upload and creative-duplication previews also require creative.write.
Prepare proposal.json using the dry-run reference and evidence rules. Include rationale, idempotency_key, and valid evidence even though the preview does not save a proposal. Targets must be human-selected; evidence fields must exist in the fresh server-side capture.
200. Use the dry-run response reference and inspect every action’s status. An evaluated item has a policy prediction, not execution availability or success. approval_required and would_auto_execute reflect the combined batch prediction, not approval or execution. diff.before contains state available to policy evaluation; an empty object or array does not mean a known zero or absent provider object. diff.proposed is the normalized action, not a request sent to Meta. A dry_run_unavailable item needs a persisted Action row and has a reason instead of a policy prediction or diff. HTTP 200 alone does not mean every action was evaluated.
The preview can read real account and provider state. It does not create a batch, action, decision receipt, or proposal audit event, queue execution, or write to Meta. It uses the current policy or unsaved defaults when no policy exists.
Repeating a preview evaluates current state again; the required idempotency key does not reserve a proposal or freeze the result. If you choose to submit, use the proposal endpoint below with the intended body. Submission reevaluates the proposal and creates its review record. A dry run cannot enable a closed action workflow or override the workspace approval mode.
Which action types are refused?
New proposals and dry-run previews rejectset_status, adjust_budget, replace_creative, shift_spend, and rollback. HTTP returns 422 with a field error for actions.N.type; MCP returns a tool validation error. The request creates no batch and performs no provider write. Historical stored actions of these types never execute.
Use pause or resume for supported status changes, and increase_budget or decrease_budget for supported daily-budget changes. Review the supported Actions and current request schema before resubmitting. Older generated models can still expose refused names; changing the idempotency key or approving an old record cannot enable them.
Which request values are accepted?
Proposal and dry-runparams objects accept only the fields defined for that action type in the published contract. Unknown keys are rejected, including keys with null values. Do not send a complete stored action response back as a new request.
Pagination types differ: for example, Actions reads use a numeric cursor while rule lists use a string cursor. Copy the returned continuation fields without converting one endpoint’s cursor into another type. Omit optional pagination fields to use defaults;
null is not the same as omission unless the endpoint explicitly allows it.
For HTTP 422, read errors by field path. A proposal parameter refusal includes action_params_invalid in the field message. Remove unknown fields or correct the value before retrying; a new idempotency key cannot make an invalid body valid. MCP exposes the corresponding tool validation error. Full validation and retry rules.
Submit a governed proposal
Use the generated proposal request reference for the typed action input and response fields. A batch contains 1–25 actions and 1–3 evidence declarations. Select targets yourself and include rationale for each action; supplyaccount_id when account selection requires it.
Prepare proposal.json using the proposal reference 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.
201; an idempotent repeat returns 200 with the existing result. A later notification or execution-queue failure does not undo an already saved proposal. Read the returned batch before retrying an uncertain result; do not submit a second intent to force a notification. Preserve the original idempotency key for the same intent after a timeout. Read the proposal response reference for its fields; approval_queue_url remains a compatibility alias for inbox_url.
In Ask mode, send the reviewer to Inbox. Use the reads above to follow the result in either mode. These routes do not approve or reject proposals, edit policy, manage keys, or override the workspace’s approval mode. In Ask, allowed changes wait for human approval; Full can queue admitted unprotected changes automatically. Protected batches, including budget increases and campaign/ad-set resumes, still need a person approval. Historical Suggest only approval ends without execution. A successful proposal response is not proof of a provider change or Landed status. An approved batch can still be blocked before its first Meta write with approver_permission_revoked if the approving person has lost permission. Inspect the reason and receipt; use the re-proposal instructions rather than replaying an old approval.
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.
Which units do budget requests use?
new_daily_budget_minor and policy-result requested_minor use Meta budget units for the account currency. Use whole currency units for CLP, COP, CRC, HUF, IDR, ISK, JPY, KRW, PYG, TWD and VND; use hundredths for other currencies listed by Meta, including BHD and JOD. They are not a universal ISO-minor-unit representation. The published contract defines the current fields.
For example, a EUR daily budget of 12.34 uses integer 1234; a JPY budget of 1234 uses integer 1234. These examples explain encoding, not a spending recommendation. Preserve positive-integer validation and account currency.
Later outcome spend_minor and cost fields instead use ISO currency subunits and may be decimal strings. Spend can be null when daily data is unavailable or the currency has no ISO subunit. Inventory metrics.spend and frozen counted_evidence money use major currency units. Do not reuse one representation as another.
What if the same proposal key returns a conflict?
Reuse the saved idempotency key only for an identical proposal from the same proposing principal. Changing action parameters, target, action order, or proposer returns HTTP409 with a validation-shaped body:
What does counted_evidence represent?
When available, an action read includes the frozen target comparison captured at proposal time: target, capture time, completed account-local window, currency, Meta-reported figures, counted figures and coverage. Meta figures use inline link clicks and attributed website purchases. Counted figures use Plainrouter arrivals and recorded purchases, with purchases available only fromcoverage.purchases.since. Money uses major units of the ad account currency; other counted currencies are excluded. It is display evidence, separate from current policy and later disposition.outcome_payload. Null means unavailable. Read the frozen comparison.
Why is a management target refused?
A submitted batch can contain only one management change per target type and ID acrosspause, resume, increase_budget, and decrease_budget. Repeating it returns HTTP 422 with action_target_repeated in the field message for actions.N.target_entity.id. Remove the conflicting action; changing its name or idempotency key does not make it a different target.
A target held by an outstanding management proposal is also refused. The message identifies the existing batch. Open that batch in Inbox, follow its execution or recovery, and wait for it to settle. If it is still awaiting a decision, an authorized person can review or reject it. Do not create replacement proposals to bypass work already in progress. These constraints also apply to MCP submissions and the Campaigns controls; creation actions sharing a parent destination are a different case.
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.