---
title: "Record explicit founder-confirmed completion. prepared_result confirms the exact reviewed attempt; independent_work records work the founder performed separately, including manual tasks with no public URL. With no published_url, the completion takes the address the move already holds (a planned page on the founder's own site, the page a site edit changed, the thread a reply went into) and ships with it. A change to the founder's own site with no address sent and none held, or one sent with planned_url, is recorded as prepared (status 'prepared', lifecycle_status 'taken_on'), not shipped. A planned_url is the AI saying the change is merged and deploying: AfterLaunch checks that page, marks the move shipped once the text is live, and after two days of checks ships it as not verified. Nothing is refused for want of an address. planned_url may be given with the prepared result or on a later call: a prepared result saved with no link takes it, the same link again changes nothing, and only a different saved link is refused. Every 200 carries message, one line for a connected AI to relay, in the same words the MCP screen leads with. This endpoint records an attestation and never publishes. A prepared asset URL is not a published URL. Scope 'act'; free."
method: POST
path: "/api/v1/moves/{id}/ship"
---

# Record explicit founder-confirmed completion. prepared_result confirms the exact reviewed attempt; independent_work records work the founder performed separately, including manual tasks with no public URL. With no published_url, the completion takes the address the move already holds (a planned page on the founder's own site, the page a site edit changed, the thread a reply went into) and ships with it. A change to the founder's own site with no address sent and none held, or one sent with planned_url, is recorded as prepared (status 'prepared', lifecycle_status 'taken_on'), not shipped. A planned_url is the AI saying the change is merged and deploying: AfterLaunch checks that page, marks the move shipped once the text is live, and after two days of checks ships it as not verified. Nothing is refused for want of an address. planned_url may be given with the prepared result or on a later call: a prepared result saved with no link takes it, the same link again changes nothing, and only a different saved link is refused. Every 200 carries message, one line for a connected AI to relay, in the same words the MCP screen leads with. This endpoint records an attestation and never publishes. A prepared asset URL is not a published URL. Scope 'act'; free.

`POST /api/v1/moves/{id}/ship`

## Request

- Base URL: `https://afterlaunch.io`
- URL: `https://afterlaunch.io/api/v1/moves/{id}/ship`
- Auth: HTTP bearer

## Path parameters

- `id` string, uuid, required

## Request body

- object
  - `completion_kind` 'prepared_result' | 'independent_work', required
  - `job_id` string, uuid, nullable, required
  - `attempt_id` string, uuid, nullable, required
  - `expected_move_state` 'pending' | 'taken_on' | 'shipped' | 'skipped' | 'archived' | 'expired' | 'null', nullable: Required with expected_move_updated_at for independent_work.
  - `expected_move_updated_at` string, date-time, nullable: Required with expected_move_state for independent_work.
  - `expected_legacy_state` string, nullable: get_move: prepared_result.legacy_state ?? state.
  - `expected_legacy_updated_at` string, date-time, nullable
  - `founder_confirmed` true, required
  - `published_url` string, nullable: Actual public URL when one exists. Required for a change to the founder's own site to count as shipped.
  - `planned_url` string, nullable: The page a merged site change lives at, while it deploys. Must be on the founder's own site. Recorded with the prepared result, including one saved earlier with no link or with a pull request; never counted as publication: AfterLaunch checks the page and ships the move once the text is live.
  - `note` string, nullable
  - `final_text` string, nullable: Optional. Only the words the founder actually posted, exactly as they went out; never your rewrite or the draft. Used only to learn how they write, for a post or reply they published; it marks nothing published. Omit it if unknown.

## Response `200`

Shipped, or prepared when a change to the founder's own site arrived with no published_url (idempotent on repeat).

- object
  - `data` object, required
  - `meta` object, required
    - `enrollment_id` string, uuid, required
    - `generated_at` string, date-time, required

## Other responses

- `401`: Missing, invalid or revoked API key.
- `403`: The key does not carry the scope this endpoint requires.
- `404`: Not found.
- `409`: Already skipped or otherwise resolved, a stale attempt, or a planned_url that differs from the link the prepared result already carries.
- `429`: Per-key rate limit exceeded. Honour Retry-After.

---

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