---
title: "One case with its timeline"
method: GET
path: "/projects/{project_id}/policy-cases/{case_id}"
tags: ["Policy"]
---

# One case with its timeline

`GET /projects/{project_id}/policy-cases/{case_id}`

## Request

- Base URL: `https://adslighthouse.com/api/v1`
- URL: `https://adslighthouse.com/api/v1/projects/{project_id}/policy-cases/{case_id}`
- Auth: HTTP bearer

Returns one case: rule, advertiser, affiliate ID, status, owner, first and last seen, match and reopen counts, and the timeline of every status change, owner change and note, oldest first. The case records that saved ads matched an internal rule; it is not a confirmed policy finding. Use list_policy_case_evidence to review the matching ads. A match is a lead to review: an observation shows an ad was displayed for a search at a moment, not proof of a violation, spend or a purchased keyword.

## Path parameters

- `project_id` string, required: The project: its id, its brand domain (for example nike.example) or its exact project or brand name. Unknown or ambiguous references return not_found; call list_projects then.
- `case_id` string, required: The case id from list_policy_cases.

## Response `200`

One case with its timeline

- object
  - `id` string, required
  - `rule_id` string, nullable, required: null when the rule was deleted; rule_name is kept.
  - `rule_name` string, required
  - `rule_type` 'forbidden_terms' | 'brand_term' | 'direct_linking' | 'promo_code' | 'position_limit' | 'affiliate_id', required
  - `advertiser_domain` string, required
  - `affiliate_id` string, nullable, required
  - `status` 'open' | 'investigating' | 'contacted' | 'resolved' | 'dismissed', required
  - `owner_user_id` string, nullable, required
  - `owner_email` string, nullable, required
  - `first_seen_at` string, required
  - `last_seen_at` string, required
  - `match_count` integer, required: Every finding recorded on the case.
  - `reopen_count` integer, required: Times a new match reopened it after it was resolved.
  - `timeline` object[], required
    - `id` string, required
    - `kind` 'opened' | 'reopened' | 'status' | 'owner' | 'note' | 'complaint_filed' | 'complaint_outcome' | 'outreach_sent', required: complaint_filed, complaint_outcome and outreach_sent record work a person did outside the app (docs/case-actions.md).
    - `text` string, required: The event as the case page shows it.
    - `details` object, nullable, required: For case actions (complaints filed, their outcomes, messages sent); null otherwise.
      - `complaint_id` string
      - `platform` string
      - `filed_on` string
      - `reference` string, nullable
      - `outcome` string
      - `outcome_on` string
      - `template_name` string
      - `recipient` string, nullable
      - `sent_on` string
      - `subject` string
    - `actor_email` string, nullable, required: null for events recorded automatically by a new match.
    - `from_status` 'open' | 'investigating' | 'contacted' | 'resolved' | 'dismissed', nullable, required
    - `to_status` 'open' | 'investigating' | 'contacted' | 'resolved' | 'dismissed', nullable, required
    - `owner_email` string, nullable, required
    - `note` string, nullable, required
    - `created_at` string, required
  - `request_id` string

## Other responses

- `400`: Invalid parameters, cursor or body.
- `401`: Missing, invalid, expired or revoked credential.
- `403`: The credential lacks the write scope, the plan does not include the API, or the allowance is used up.
- `404`: Unknown project, keyword or run in this account.
- `409`: The idempotency key was already used for a different request.
- `429`: Rate limit reached. Retry after the Retry-After seconds.
- `503`: The requested service or file is temporarily unavailable.

---

[API](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api.md) · [All operations](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api/llms.txt) · [OpenAPI document](https://skmtc.dev/adslighthouse/apis/ads-lighthouse-api/revisions/e1a4a40b11a9?raw)
