Docs
APIAPI referenceCommand center

Decisions

Ask a studio member to pick one of your options, then poll the decision until it is answered.

View as Markdown

Deprecated (2026-09-27). MMA's Decisions screen now leads with MMA's own recommendations: optimizer changes waiting for approval and broken measurement signals, each with its fix. Decisions your agent files appear in a secondary From your agents section below them. These endpoints keep working with no change in behavior, and no removal date is set. Do not build new integrations on them.

POST/v1/decisions
Phase 1stable
Auth
Bearer
Scope
decisions:write
GET/v1/decisions/:decisionId
Phase 1stable
Auth
Bearer
Scope
decisions:read
POST/v1/decisions/:decisionId/withdraw
Phase 1stable
Auth
Bearer
Scope
decisions:write

A decision is a question your agent needs a person to answer: raise a budget, ship an experiment's winner, pause a campaign. It appears in MMA with your recommendation and cost, and each of your options is one answer button. A studio member picks one, with an optional note, and your agent reads the pick back by polling: chosenOption is the option exactly as you sent it.

Request a decision

A key limited to some apps must name the app with projectId or experimentId when it files an ask. Filing for another app returns 403 FORBIDDEN_SCOPE. Reading or withdrawing a decision on another app returns 404 NOT_FOUND.

Body
  • title
    stringrequired
    Short name shown in MMA.
  • ask
    stringrequired
    The question, in plain words.
  • projectId
    stringoptional
    The project the ask is about. Omit for a studio-wide ask.
  • experimentId
    stringoptional
    The experiment the ask is about. It must belong to `projectId` when both are sent.
  • recommendation
    stringoptional
    What you recommend and why.
  • options
    arrayoptional
    The answers offered, 1 to 10 unique strings of up to 100 characters. Each is one button in MMA, and the one picked comes back verbatim as `chosenOption`. Defaults to `["approve", "deny"]`.
  • costUsd
    numberoptional
    What approving costs, in US dollars, to the cent.
  • dueAt
    stringoptional
    When you need the answer, ISO-8601 UTC.
  • requestedByLabel
    stringoptional
    Who asks, e.g. the agent or session name.

Send an Idempotency-Key header.

curl -X POST "https://api.layers.com/v1/decisions" \
  -H "Authorization: Bearer lp_..." \
  -H "Idempotency-Key: catch-master-budget-2026-09-26" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
    "title": "Raise Meta daily budget to $400",
    "ask": "D7 ROAS held at 1.4 for 5 days at $250 a day. Raise the daily budget to $400?",
    "recommendation": "Approve. The last two raises kept CPI within 8%.",
    "costUsd": 1050,
    "requestedByLabel": "catch-master-growth-agent"
  }'
201Created
{
  "decision": {
    "id": "dec_7a2e9c41-0b6d-4f3e-8c15-9d4b2a6e1f07",
    "projectId": "prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
    "experimentId": null,
    "title": "Raise Meta daily budget to $400",
    "ask": "D7 ROAS held at 1.4 for 5 days at $250 a day. Raise the daily budget to $400?",
    "recommendation": "Approve. The last two raises kept CPI within 8%.",
    "options": ["approve", "deny"],
    "costUsd": 1050,
    "dueAt": null,
    "status": "pending",
    "chosenOption": null,
    "decisionNote": null,
    "decidedAt": null,
    "requestedByLabel": "catch-master-growth-agent",
    "createdAt": "2026-09-26T14:05:00Z",
    "updatedAt": "2026-09-26T14:05:00Z"
  }
}

Poll a decision

curl "https://api.layers.com/v1/decisions/dec_7a2e9c41-0b6d-4f3e-8c15-9d4b2a6e1f07" \
  -H "Authorization: Bearer lp_..."
statusMeaningYour next action
pendingWaiting for a studio member.Poll again; a few minutes apart is enough.
approvedThe member picked approve. chosenOption is "approve".Act on it. Stop polling.
deniedThe member picked deny. chosenOption is "deny".Drop the ask. Stop polling.
answeredThe member picked one of your other options. chosenOption is that option, verbatim.Act on the option picked. Stop polling.
withdrawnYou withdrew it. chosenOption is null.Stop polling.

In every answered status decisionNote carries the member's reason when they gave one. Read chosenOption to learn the answer; it works the same for the default pair and for your own options.

Offer your own options

Send options when approve or deny is not the question. Each string is a button in MMA and the value you read back, so write them as the action you will take.

{
  "projectId": "prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
  "title": "Paywall test: arm B is ahead",
  "ask": "Arm B leads trial starts by 4.2 points, interval 1.1 to 7.3. What next?",
  "options": ["ship B", "extend a week", "stop the test"]
}

A member who picks "extend a week" closes the decision with status: "answered" and chosenOption: "extend a week". Options that include approve or deny keep their verdict: picking approve from ["approve", "approve at half budget", "deny"] returns status: "approved".

Withdraw a decision

POST /v1/decisions/:decisionId/withdraw takes the ask back while it is pending. A decision that is already answered returns 409 CONFLICT.

Errors

StatusCodeWhen
404NOT_FOUNDThe decision, project or experiment is not in your organization.
409CONFLICTWithdrawing a decision that is already answered or withdrawn.
422VALIDATIONA malformed field, an extra field, an experiment on a different project, or a malformed id.

On this page