---
title: "Create an update (story)"
method: POST
path: "/v1/admin/updates"
tags: ["Admin"]
---

# Create an update (story)

`POST /v1/admin/updates`

## Request

- Base URL: `http://api.technooptimist.io`
- URL: `http://api.technooptimist.io/v1/admin/updates`
- Auth: HTTP bearer

Idempotent when `externalKey` is given: replaying the same key returns the existing update with `created: false` (200) instead of 201. Emits `update.created` on the stream.

## Headers

- `x-routine-name` string: Name of the routine making the write; recorded as `routine:<name>` in the audit log.

## Request body

- object
  - `company` string, required
  - `program` string
  - `occurredAt` union, required
    - string, date-time
    - string
  - `headline` string, required
  - `body` string
  - `points` string[]
  - `kind` 'test' | 'hardware' | 'software' | 'manufacturing' | 'regulatory' | 'funding' | 'hiring' | 'commercial' | 'research' | 'partnership' | 'people' | 'other', required
  - `importance` 'major' | 'minor', required
  - `rank` integer
  - `sourceType` 'x' | 'blog' | 'filing' | 'press' | 'livestream' | 'paper' | 'job' | 'regulator' | 'interview' | 'other', required
  - `sourceUrl` string, uri
  - `alsoFrontiers` string[]
  - `verified` boolean
  - `externalKey` string

## Response `200`

Already existed (same externalKey)

- CreateUpdateResult
  - `id` string, uuid, required
  - `created` boolean, required: false when an update with the same externalKey already existed (idempotent replay).
  - `update` object, nullable, required
    - `id` string, uuid, required
    - `occurredAt` string, date-time, required
    - `precision` 'day' | 'month' | 'quarter' | 'year', required
    - `headline` string, required
    - `kind` 'test' | 'hardware' | 'software' | 'manufacturing' | 'regulatory' | 'funding' | 'hiring' | 'commercial' | 'research' | 'partnership' | 'people' | 'other', required
    - `importance` 'major' | 'minor', required
    - `rank` integer, required
    - `sourceType` 'x' | 'blog' | 'filing' | 'press' | 'livestream' | 'paper' | 'job' | 'regulator' | 'interview' | 'other', required
    - `sourceUrl` string, uri, nullable, required: Link to the original story (article, press release, filing, video). Null when unknown.
    - `summary` string, nullable, required: The story in our words: 2–4 sentences on what happened and why it matters, written from the source. Null when not written yet.
    - `company` object, required
      - `slug` string, required
      - `name` string, required
    - `program` object, nullable, required
      - `slug` string, required
      - `name` string, required
      - `frontier` string, required
      - `path` string, required: Canonical site path. Programs live under their frontier.
    - `frontiers` string[], required
    - `createdAt` string, date-time, required
    - `points` string[], required: 2–5 bullets of the key facts (numbers, dates, who, what changes), from the source. Empty when not written yet.

## Other responses

- `201`: Created
- `401`: Missing or invalid credentials
- `403`: Credential lacks the required scope
- `404`: Not found
- `409`: Conflict
- `422`: Validation failed

---

[API](https://skmtc.dev/technooptimist/apis/the-techno-optimist-api.md) · [All operations](https://skmtc.dev/technooptimist/apis/the-techno-optimist-api/llms.txt) · [OpenAPI document](https://skmtc.dev/technooptimist/apis/the-techno-optimist-api/revisions/b7bcde6a0f30?raw)
