---
title: "Submit a highlight to the moderation queue"
method: POST
path: "/api/ingest/highlights/pending"
tags: ["highlights"]
---

# Submit a highlight to the moderation queue

`POST /api/ingest/highlights/pending`

## Request

- Base URL: `https://www.immersivecommons.com`
- URL: `https://www.immersivecommons.com/api/ingest/highlights/pending`
- Auth: HTTP bearer

agt_ token required (scope `events:submit_recap`). Adds a HighlightStory to the pending moderation queue; an operator approves it. ASYNC-JOB: returns 202 Accepted with `status: pending`, a `job_id` (= the story `id`), a `poll_url`, and a `Location` response header — all pointing at `GET /api/ingest/highlights/pending?id=<job_id>`, which returns `status: pending` while queued or `status: gone` once it leaves the queue (approved → active, rejected, or expired). IDEMPOTENT: re-submitting the same story `id` refreshes the pending record without bumping the rate counter; an `Idempotency-Key` additionally replays the 202 (with the same `Location`). Rate: 3/token/UTC day.

## Headers

- `Idempotency-Key` string

## Request body

- HighlightPendingRequest: A HighlightStory, or an object wrapping one under `story`. Validated by lib/highlights-pending.ts.
  - `id` string: Stable id — re-submitting the same id refreshes the pending record (dedupe).
  - `story` object: Optional wrapper; the story fields may also be sent at the top level.

## Response `202`

Accepted into the pending queue. Poll the `Location` header (or `poll_url`) for the job's status.

- HighlightPendingResponse
  - `ok` boolean, required
  - `id` string, required
  - `job_id` string: Async-job handle (= `id`) to poll this submission with. Mirrors the `Location` header + `poll_url`.
  - `status` 'pending', required
  - `poll_url` string: Status-poll URL: GET /api/ingest/highlights/pending?id=<job_id> → { status: pending | gone }. Same URL as the `Location` response header.
  - `rate` RateInfo: Per-token rate-limit snapshot returned by write endpoints.
    - `current` integer
    - `remaining` integer
    - `limit` integer
  - `expires_at` string, date-time

## Other responses

- `400`: Invalid JSON or story validation error.
- `401`: Missing/invalid token.
- `413`: Body too large.
- `429`: Per-token daily rate limit exceeded.
- `500`: Enqueue failed.

---

[API](https://skmtc.dev/immersivecommons/apis/immersive-commons-agent-rest-api.md) · [All operations](https://skmtc.dev/immersivecommons/apis/immersive-commons-agent-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/immersivecommons/apis/immersive-commons-agent-rest-api/revisions/be67c1f67c27?raw)
