---
title: "Choose what to do with an SEO opportunity"
method: POST
path: "/sites/{site}/seo-opportunities/{opportunity_id}/choice"
tags: ["Analytics"]
---

# Choose what to do with an SEO opportunity

`POST /sites/{site}/seo-opportunities/{opportunity_id}/choice`

## Request

- Base URL: `https://api.onelence.com/v1`
- URL: `https://api.onelence.com/v1/sites/{site}/seo-opportunities/{opportunity_id}/choice`
- Auth: one of:
  - OAuth 2 (authorization code, authorization URL `https://api.onelence.com/oauth/authorize`, token URL `https://api.onelence.com/oauth/token`, scopes: `workspace:write`)
  - HTTP bearer

Plans an SEO opportunity (plan_to_do, optionally with a plan: the change, URLs and the metric to watch), reports it as already done (already_did, with what was changed, where and when), or closes it (will_not_do, with a reason), as on the SEO page. It goes to SEO Work in OneLence; nothing changes on the site or in Search Console, and it cannot be undone from here. Pass the candidate_fingerprint and the window the opportunity was read with. Some opportunities need a plan for every choice, as on the SEO page; without one the choice is refused with param plan. Owners and admins only.

## Path parameters

- `site` string, required
- `opportunity_id` string, required

## Query parameters

- `dry_run` boolean

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `candidate_fingerprint` string, required: candidate_fingerprint from the same read; a changed opportunity is refused.
  - `choice` 'plan_to_do' | 'already_did' | 'will_not_do', required
  - `plan` object: The planned change. Optional with plan_to_do (without it, OneLence plans the suggested next step), but some opportunities need it for every choice.
    - `intended_change` string, required: What will be changed.
    - `affected_urls` string[], required
    - `query_scope` string[]: The search queries it targets.
    - `expected_metric` 'clicks' | 'impressions' | 'ctr' | 'position', required: The metric to watch after the change.
    - `window_days` union, required: How long to watch it.
      - 7
      - 28
  - `application` object: Required with already_did.
    - `description` string, required: What was changed.
    - `affected_urls` string[], required
    - `query_scope` string[]: The search queries it targets.
    - `applied_at` string, date-time, required: When the change went live (ISO 8601).
    - `before_value` string
    - `after_value` string
    - `external_reference` string: A link to the change, such as a commit or CMS revision.
  - `reason` string: Why, for will_not_do.
  - `start` string: Window start: a date (YYYY-MM-DD) or ISO 8601 date-time. Defaults to 30 days before end.
  - `end` string: Window end, inclusive for a date. Defaults to now.

## Response `200`

Success.

- object
  - `object` 'seo_choice_receipt', required
  - `opportunity_id` string, required
  - `choice` 'plan_to_do' | 'already_did' | 'will_not_do', required
  - `work_item` object, nullable, required
    - `id` string, required
    - `status` string, nullable, required
  - `replayed` boolean, required

## Other responses

- `400`: Invalid input; `error.param` names the field.
- `401`: Missing, expired or revoked token. WWW-Authenticate points to the resource metadata.
- `402`: subscription_required or upgrade_required; the error carries billing_url.
- `403`: insufficient_scope or admin_required.
- `404`: Unknown endpoint, site, source or record.
- `409`: A request with this Idempotency-Key is still running.
- `422`: This Idempotency-Key was already used for a different request.
- `429`: Rate limited. Retry after Retry-After seconds.
- `500`: OneLence could not complete the request.

---

[API](https://skmtc.dev/onelence/apis/onelence-api.md) · [All operations](https://skmtc.dev/onelence/apis/onelence-api/llms.txt) · [OpenAPI document](https://skmtc.dev/onelence/apis/onelence-api/revisions/971c72fe9a42?raw)
