---
title: "Read Goal Conversation"
method: GET
path: "/goals/conversation"
tags: ["goals"]
---

# Read Goal Conversation

`GET /goals/conversation`

This browser's conversation as it stands, so a reload costs no turn.

A safe read on the cookie alone: it changes nothing, and asking the athlete
to re-say what they already said is the one thing a resumable conversation
is supposed to make impossible. An empty answer is the honest one for a
browser that has not spoken — a first open is not an error.

The rim is parsed once and both ``status`` and ``picture`` come off it, so
the two can never describe different documents — the same property the
stream's own pair of frames has.

## Response `200`

Successful Response

- GoalConversationResponse — What a reload needs to redraw the conversation without burning a turn. Every field is empty on a browser that has not spoken yet — a page opening for the first time is not an error, so this answers 200 with nothing rather than 404 with a reason nobody needs. ``goal_id`` appears once the conversation settles, and it is the only way the page can name the artifact it produced; a goal nothing can address is a goal nothing can publish. ``picture`` is the same object the accepted turn streamed, for the latest accepted document — the poll is the only news a page gets while a voice call runs its turns server-side, so the picture has to be readable here and not only on the stream.
  - `status` 'exploring' | 'proposing' | 'settled', nullable
  - `document` string, nullable
  - `replies` string[]
  - `goal_id` string, 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
    - `city` string, nullable
    - `country` string, nullable
    - `website_url` string, nullable
    - `short_link` string, nullable
  - `picture` GoalPicture — The goal's picture as one payload, for the two carriers that send it. The picture draws itself while the conversation runs, so the page needs the factors as *data* rather than as document text nobody outside cheshire should be parsing. One payload serves both carriers — the accepted turn's stream event and the conversation read's ``picture`` — and both derive it from the same accepted document, which is what makes them unable to disagree. **Full state, never a delta.** Every payload carries the complete factor list of its document version, in rim order, so a page that reloads and starts from the conversation read draws the identical picture the stream drew. Motion is the consumer's diff between consecutive payloads, keyed on a factor's ``name``; ``version_id`` is the gate, so the same version seen twice moves nothing. ``factors`` is the rim's own type exactly, the passthrough posture :class:`GoalDetailResponse` takes and for the same reason: a mirrored DTO here would be a second contract to keep in step with the document the coach writes. Empty is normal — the picture forms as the conversation does. Serialized, each factor also carries its served ``span`` (:func:`_served_factor`), so every carrier hands a consumer the axis scale with the positions that live on it.
    - `version_id` string, required
    - `status` 'exploring' | 'proposing' | 'settled', required
    - `factors` object[]

---

[API](https://skmtc.dev/imperfect/apis/imperfect-api.md) · [All operations](https://skmtc.dev/imperfect/apis/imperfect-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/imperfect/imperfect-api/revisions/cc2293a44257/schema)
