---
title: "Read Shared Goal Detail"
method: GET
path: "/goals/shared/{share_id}/detail"
tags: ["goals"]
---

# Read Shared Goal Detail

`GET /goals/shared/{share_id}/detail`

## Request

- Base URL: `https://api.imperfect.co` (the document declares no server; this is the origin it was published from)
- URL: `https://api.imperfect.co/goals/shared/{share_id}/detail`
- Auth: HTTP bearer

The owner's read of a goal, reached by the id in the goal page's address.

wonderland goals.md gives a published goal one page, at
``/g/{share_id}/{slug}``, and every reader gets the whole goal on it
(#3057). What the athlete standing on their own page gets beyond that is
the handle to act on it: the goal id every write takes and whether an app
holds it. That address carries no goal id on purpose, so without this the
owner had no way to ask for one (looking-glass#939).

**The same answer as** ``GET /goals/{goal_id}``, byte for byte, behind the
same owner predicate. Nothing here is wider than that read: the share id
only finds the row, and ``_readable_goal_or_404`` decides who may see it.

**One 404 for every negative**: an invented share id, a goal taken down, and
a published goal this caller does not own. A status that told them apart
would say whether a link belongs to the person holding it. No session at
all is the boundary's own 401, exactly as on the goal id read.

## Path parameters

- `share_id` string, required

## Headers

- `x-device-timezone` string, nullable
- `x-device-hint` string, nullable
- `x-client-platform` string, nullable

## Response `200`

Successful Response

- GoalDetailResponse: The owner's goal, in one read (#1984). The same sections as the public page (:class:`GoalPageSections`), plus what only the owner may act on: the goal id every write takes, the conversation's status, where the page is live, and whether an app account holds it. The public read is not a narrower page, it is the same page without the handle. ``share_id``/``slug``/``published_at`` are ``StoredGoal.live_share`` read-only — all three together or none, the same guarantee that property already holds, not a fourth spelling of it. Settling publishes the goal (#3057), so they are set from the settle on; a goal whose page was taken down reads ``null``.
  - `name` string, required
  - `line` string, nullable
  - `locale` string, required
  - `kind` 'destination' | 'practice', required
  - `sport` string, nullable
  - `set_at` string, date-time, required
  - `target` GoalDate, required: A dated commitment at its honest resolution. ``precision`` is the band: the date is normalized to the first day of its period (month and season → the 1st of that month, quarter → the quarter's first month), so a coarse band can never license a specific day the source hasn't published — the same normalization the plan rim applies to its events. A season keeps its own start month rather than the quarter holding it (#2945). Seasons do not line up with calendar quarters, and which months one covers depends on the athlete's hemisphere: spring is March in Mexico and September in Chile. The model writes the month it means, so the band runs three months from there; folding it into a quarter kept January and February for a spring and dropped April and May.
    - `date` string, date, required
    - `precision` 'day' | 'month' | 'quarter' | 'season'
  - `anchor_kind` 'event' | 'route', nullable
  - `anchor` GoalAnchorPayload: The event a goal is pinned to, resolved into what a client draws. Additive and optional: a goal that anchors nowhere — most of them — carries ``null`` here and the page looks exactly as it did before this existed. This is the whole reason the coach never writes a URL. The reply is plain chat text that ships to any channel as-is, so a link in it would be a link the model chose and nothing validated; here the host resolves the id the conversation anchored to and hands over the official name, date, place and site. The surface renders the card, and the coach's words stay words. ``website_url`` points at the organizer's own site rather than an imperfect.co event page: the athlete is being handed the place where they actually register. It resolves server-side, so retargeting it later is one line here and no change to any client.
    - `kind` 'event' | 'route', required
    - `id` string, required
    - `name` string, required
    - `date` string, date, nullable
    - `date_month` string, date, nullable
    - `city` string, nullable
    - `country` string, nullable
    - `website_url` string, nullable
    - `short_link` string, nullable
    - `distance` string, nullable
    - `distance_km` number, nullable
  - `factors` object[]
  - `events` GoalEvent[]
    - `name` string, required: The event, the way the athlete named it.
    - `when` GoalDate: A dated commitment at its honest resolution. ``precision`` is the band: the date is normalized to the first day of its period (month and season → the 1st of that month, quarter → the quarter's first month), so a coarse band can never license a specific day the source hasn't published — the same normalization the plan rim applies to its events. A season keeps its own start month rather than the quarter holding it (#2945). Seasons do not line up with calendar quarters, and which months one covers depends on the athlete's hemisphere: spring is March in Mexico and September in Chile. The model writes the month it means, so the band runs three months from there; folding it into a quarter kept January and February for a spring and dropped April and May.
      - `date` string, date, required
      - `precision` 'day' | 'month' | 'quarter' | 'season'
    - `id` string, nullable
    - `role` 'main' | 'rehearsal' | 'training', nullable
  - `page` GoalPage: The prose sections of one settled goal's page. Every field is optional in the sense that matters: a section the document does not carry is absent rather than filled, because a slot is minting pressure (#1850) and this projection has no athlete left in the loop to correct an invention. The page reads fine short. **The field descriptions are the spec the model works from.** They are what the projection prompt deliberately does not restate — one place says what a section is, and it is the type the answer has to satisfy.
    - `why` string, nullable: Why this goal matters: the passage that carries their reason, not the loudest one in it. In the athlete's own words: a passage copied exactly as the document has it, and only where those exact words read as clean writing, with no pause marks, fillers, cut-off words or words said twice. Begin it with a capital letter even when the passage starts mid-sentence; that is the only change allowed. Otherwise leave it empty. The passage also has to stand on its own under the goal's title, for a reader who never heard the conversation. A word like it or this for the goal or the training is fine. It fails only when it points back at something the page does not show: it counts itself as one of several reasons whose others are missing, or it continues, answers or contradicts a remark the reader never heard. Then select a contiguous passage that does not lean on it, or leave why empty.
    - `why_summary` string, nullable: Why this goal matters, when why has no clean quote. Only when the athlete said it but no clean passage of theirs exists: what they meant, in one plain sentence in the page's own voice, the way the rest of the page describes them, starting with a capital letter. Never I or you, never a name, never in quotation marks, and nothing they did not say. Lead with the reason, the feeling or the lesson rather than the person: no pronoun for the athlete, and never they, the athlete or the couple. A sentence that seems to need one is reworded, never dropped, so the slot fills whenever the athlete said it. No gendered pronoun for anyone, and in every language keep the athlete one person, in the singular; a verb agreeing with them is not a pronoun.
    - `journey` string, nullable: One plain line on where the athlete is coming from and what this goal is the next step of: the races behind them, the step up ahead, where they are today.
    - `sport` string, nullable: The athlete's own word for the sport this goal is in, whenever the document makes it plain; when its events span several sports, each of them in their words, listed the way they would list them. Nothing only when the document genuinely does not say.
    - `week` GoalWeekCommitment[]: Everything the week keeps, one entry each: the week this goal asks for, with its training amounts and build; availability; and regular or occasional activities, including those outside the goal's own sport. Preserve the difference between time available, planned training and activities already done. Keep occasional activities occasional, with no new days or frequencies.
      - `name` string, required: The commitment, in two or three words.
      - `detail` string, required: What it is, as the document states it.
    - `life` string[]: One short line each for the life the work has to fit: the days and hours actually available, the travel, the sleep, the dates already fixed, whatever the athlete called non-negotiable. Their constraints, never advice, and always in the page's own words: where the document carries a constraint as something the athlete said, say what it means, keeping their numbers at the coarseness they gave them, rather than reproduce the saying.
    - `history` GoalComingFrom: What this goal is built on: the race behind them, or where they start. An athlete with a race behind them is coming from that race and what it taught. A first-timer is coming from a starting point instead — the longest they have run in one go, what their weeks already hold — and their document states it just as plainly (#2013). A card only a past race could fill left theirs blank, on the one section of the page that shows the athlete it meets them where their journey starts. **The quotes are optional, and that is what makes both shapes fit.** ``felt`` and ``lesson`` are each a slot: a clean exact quote, gate-checked against the document, else a summary beside it, else nothing (#2866). Nobody quotes how their current mileage felt, so a starting point stands on ``event`` alone, held to the document by the grounding judge like every other sentence the model writes. Bench round 1 (#1984) had already shown that requiring both quotes drops a real card whose body quoted the athlete once; requiring one drops every first-timer's.
      - `event` string, required: The race or attempt, named as the document names it — or, when the document tells of none, the athlete's starting point in the same handful of words: the longest they have gone in one go, what their weeks already hold. The thing itself, never a sentence introducing it.
      - `felt` string, nullable: How it felt. In the athlete's own words: a passage copied exactly as the document has it, and only where those exact words read as clean writing, with no pause marks, fillers, cut-off words or words said twice. Begin it with a capital letter even when the passage starts mid-sentence; that is the only change allowed. Otherwise leave it empty.
      - `felt_summary` string, nullable: How it felt, when felt has no clean quote. Only when the athlete said it but no clean passage of theirs exists: what they meant, in one plain sentence in the page's own voice, the way the rest of the page describes them, starting with a capital letter. Never I or you, never a name, never in quotation marks, and nothing they did not say. Lead with the reason, the feeling or the lesson rather than the person: no pronoun for the athlete, and never they, the athlete or the couple. A sentence that seems to need one is reworded, never dropped, so the slot fills whenever the athlete said it. No gendered pronoun for anyone, and in every language keep the athlete one person, in the singular; a verb agreeing with them is not a pronoun.
      - `lesson` string, nullable: What it taught. In the athlete's own words: a passage copied exactly as the document has it, and only where those exact words read as clean writing, with no pause marks, fillers, cut-off words or words said twice. Begin it with a capital letter even when the passage starts mid-sentence; that is the only change allowed. Otherwise leave it empty.
      - `lesson_summary` string, nullable: What it taught, when lesson has no clean quote. Only when the athlete said it but no clean passage of theirs exists: what they meant, in one plain sentence in the page's own voice, the way the rest of the page describes them, starting with a capital letter. Never I or you, never a name, never in quotation marks, and nothing they did not say. Lead with the reason, the feeling or the lesson rather than the person: no pronoun for the athlete, and never they, the athlete or the couple. A sentence that seems to need one is reworded, never dropped, so the slot fills whenever the athlete said it. No gendered pronoun for anyone, and in every language keep the athlete one person, in the singular; a verb agreeing with them is not a pronoun.
    - `honest_subtitle` string, nullable: One line on what keeps this goal honest: where the coach's read differs from the athlete's target, or what the goal is being held to. Lead with the goal or the choice, in the page's own voice: never I or you, no gendered pronoun, and never the athlete named as a person.
    - `factor_lines` GoalFactorLines[]: One entry for each factor on the rim that has a position, so each of its two bars can carry a short line.
      - `name` string, required: The factor's name, exactly as the rim writes it.
      - `asks_line` string, nullable: What the goal asks on this factor, in a few words beside its bar: this factor's own asks as one figure, said the way the athlete would say it, in the document's language and the athlete's units, a pace or a clock time in minutes and seconds. Never a range, a second number or anything else the document says about it. Nothing when the factor has no asks.
      - `standing_line` string, nullable: Where the athlete is today on this factor, said the same way: this factor's own standing as one figure and nothing more. For a factor read off the body, its position and never the readings behind it. Nothing when the factor has no standing.
  - `page_expected_until` string, date-time, nullable
  - `checkpoints` GoalCheckpointPayload[]
    - `name` string, nullable: One or two of the athlete's own words for this checkpoint.
    - `measure` string, required: The sentence the athlete reads: what has to be observably true.
    - `by` GoalDate, required: A dated commitment at its honest resolution. ``precision`` is the band: the date is normalized to the first day of its period (month and season → the 1st of that month, quarter → the quarter's first month), so a coarse band can never license a specific day the source hasn't published — the same normalization the plan rim applies to its events. A season keeps its own start month rather than the quarter holding it (#2945). Seasons do not line up with calendar quarters, and which months one covers depends on the athlete's hemisphere: spring is March in Mexico and September in Chile. The model writes the month it means, so the band runs three months from there; folding it into a quarter kept January and February for a spring and dropped April and May.
      - `date` string, date, required
      - `precision` 'day' | 'month' | 'quarter' | 'season'
    - `on_miss` string, required: The sentence the athlete reads: what the goal reverts to, stated openly.
    - `anchor` GoalAnchorPayload: The event a goal is pinned to, resolved into what a client draws. Additive and optional: a goal that anchors nowhere — most of them — carries ``null`` here and the page looks exactly as it did before this existed. This is the whole reason the coach never writes a URL. The reply is plain chat text that ships to any channel as-is, so a link in it would be a link the model chose and nothing validated; here the host resolves the id the conversation anchored to and hands over the official name, date, place and site. The surface renders the card, and the coach's words stay words. ``website_url`` points at the organizer's own site rather than an imperfect.co event page: the athlete is being handed the place where they actually register. It resolves server-side, so retargeting it later is one line here and no change to any client.
      - `kind` 'event' | 'route', required
      - `id` string, required
      - `name` string, required
      - `date` string, date, nullable
      - `date_month` string, date, nullable
      - `city` string, nullable
      - `country` string, nullable
      - `website_url` string, nullable
      - `short_link` string, nullable
      - `distance` string, nullable
      - `distance_km` number, nullable
  - `alternatives` GoalCandidate[]
    - `name` string, required
    - `demands` string, required: One honest line on what this framing asks.
    - `label` string, nullable
    - `tags` string[]
    - `target` GoalDate: A dated commitment at its honest resolution. ``precision`` is the band: the date is normalized to the first day of its period (month and season → the 1st of that month, quarter → the quarter's first month), so a coarse band can never license a specific day the source hasn't published — the same normalization the plan rim applies to its events. A season keeps its own start month rather than the quarter holding it (#2945). Seasons do not line up with calendar quarters, and which months one covers depends on the athlete's hemisphere: spring is March in Mexico and September in Chile. The model writes the month it means, so the band runs three months from there; folding it into a quarter kept January and February for a spring and dropped April and May.
      - `date` string, date, required
      - `precision` 'day' | 'month' | 'quarter' | 'season'
    - `recommended` boolean
    - `chosen` boolean
  - `offered_goals` GoalCandidate[], nullable
    - `name` string, required
    - `demands` string, required: One honest line on what this framing asks.
    - `label` string, nullable
    - `tags` string[]
    - `target` GoalDate: A dated commitment at its honest resolution. ``precision`` is the band: the date is normalized to the first day of its period (month and season → the 1st of that month, quarter → the quarter's first month), so a coarse band can never license a specific day the source hasn't published — the same normalization the plan rim applies to its events. A season keeps its own start month rather than the quarter holding it (#2945). Seasons do not line up with calendar quarters, and which months one covers depends on the athlete's hemisphere: spring is March in Mexico and September in Chile. The model writes the month it means, so the band runs three months from there; folding it into a quarter kept January and February for a spring and dropped April and May.
      - `date` string, date, required
      - `precision` 'day' | 'month' | 'quarter' | 'season'
    - `recommended` boolean
    - `chosen` boolean
  - `fallbacks` GoalFallbackPayload[]
    - `when` string, required: The athlete's named obstacle.
    - `then` string, required: The athlete's own replacement.
    - `athlete_quote` string, nullable
  - `revisions` GoalShareRevision[]
    - `published_at` string, date-time, required
    - `name` string, required
    - `target_date` string, date, required
    - `target_precision` 'day' | 'month' | 'quarter' | 'season', required
  - `goal_id` string, required
  - `status` 'exploring' | 'proposing' | 'settled', required
  - `share_id` string, nullable
  - `slug` string, nullable
  - `published_at` string, date-time, nullable
  - `claimed_at` string, date-time, nullable

## Other responses

- `422`: Validation Error

## Changes

- **2026-10-27** `c009be4558a1`: 1 warning, 1 info
  - removed the optional property `events/items/first` from the response with the `200` status
  - added the optional property `events/items/role` to the response with the `200` status
- **2026-10-21** `c98bfec83142`: 1 info
  - added the optional property `offered_goals` to the response with the `200` status
- **2026-10-15** `c746f5978073`: 1 info
  - added the optional property `events` to the response with the `200` status
- **2026-10-06** `2022ce4f3c48`: 2 info
  - added the optional property `anchor/anyOf[subschema #1: GoalAnchorPayload]/date_month` to the response with the `200` status
  - added the optional property `checkpoints/items/anchor/anyOf[subschema #1: GoalAnchorPayload]/date_month` to the response with the `200` status
- **2026-10-05** `60efb6aabb43`: 3 breaking
  - the response property `fallbacks/items/athlete_quote` became optional for the status `200`
  - response property `fallbacks/items/athlete_quote` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
  - the `fallbacks/items/athlete_quote` response property's minLength was decreased from `1` to `0` for the response status `200`

[Operation history](https://skmtc.dev/imperfect/apis/imperfect-api/changes/goals/shared/:share_id/detail/get.md)

---

[API](https://skmtc.dev/imperfect/apis/imperfect-api.md) - [All operations](https://skmtc.dev/imperfect/apis/imperfect-api/llms.txt) - [OpenAPI document](https://skmtc.dev/imperfect/apis/imperfect-api/revisions/33a8821ec7f8?raw)
