# PATCH /v1/projects/:projectId/recommendations/:recommendationId (/docs/api/reference/recommendations/update-recommendation)



<Endpoint method="PATCH" path="/v1/projects/{projectId}/recommendations/{recommendationId}" auth="Bearer" scope="metrics:read" phase="1" />

Flip a recommendation's status. Use this to clear a row out of your default `status=open` view (`dismissed`), record that an agent has handled it (`acted_on`), or just mark it as seen (`acknowledged`).

The endpoint is idempotent — re-PATCHing to the same status returns the same row without an additional state change. Status transition timestamps (`acknowledged_at`, `dismissed_at`, `acted_on_at`) are stamped on the first transition into each terminal state and preserved across later changes.

<Parameters
  title="Path"
  rows="[
  { name: 'projectId', type: 'string (UUID)', required: true, description: 'Project the recommendation belongs to.' },
  { name: 'recommendationId', type: 'string', required: true, description: 'Wire id from the list endpoint (`rec_<uuid>`).' },
]"
/>

<Parameters
  title="Body"
  rows="[
  { name: 'status', type: 'string', required: true, description: 'Target status.', enum: ['open', 'acknowledged', 'dismissed', 'acted_on'] },
  { name: 'note', type: 'string', description: 'Optional free-text reason (≤1024 chars). Persisted alongside the row for audit.' },
]"
/>

## Example request [#example-request]

```bash
curl -X PATCH \
  "https://api.layers.com/v1/projects/prj_254a4ce1.../recommendations/rec_5e4d3c2b..." \
  -H "Authorization: Bearer lp_..." \
  -H "Content-Type: application/json" \
  -d '{"status":"dismissed","note":"Covered by manual creative refresh"}'
```

## Response [#response]

<Response status="200" description="OK">
  ```json
  {
    "recommendationId": "rec_5e4d3c2b...",
    "status": "dismissed",
    "updatedAt": "2026-04-26T22:30:00Z"
  }
  ```
</Response>

## Notes [#notes]

* The optimizer pipeline that generates recommendations refreshes `confidence`, `rationale`, and `evidence` on subsequent runs but **never** overwrites a partner-flipped status. Once you mark something `dismissed`, it stays dismissed even if the underlying signal persists.
* A `dismissed` recommendation is hidden from the default `status=open` filter on the list endpoint. Pass `status=dismissed` to retrieve it.
* Re-opening a dismissed row (`status=open`) clears `dismissed_at` semantically (the row goes back to the default view) but keeps the audit trail in `note` and the previous timestamp columns.

## See also [#see-also]

* [`GET /v1/projects/:projectId/recommendations`](/docs/api/reference/recommendations/list-recommendations) — list endpoint with cursor pagination + `status` filter
