---
title: "Write a handoff row from a PreCompact or SessionEnd hook"
method: POST
path: "/api/agent/hooks/snapshot"
tags: ["Agent"]
---

# Write a handoff row from a PreCompact or SessionEnd hook

`POST /api/agent/hooks/snapshot`

## Request

- Base URL: `http://localhost:38200`
- URL: `http://localhost:38200/api/agent/hooks/snapshot`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `token`

T858. Same transport as the session-start hook. The server parses the config, honours `enabled` and `capture_scope`, assembles the handoff body from the supplied git facts, and upserts it on `external_id` through the same bulk-upsert path `agent_handoff_save` uses — so a re-run for the same Claude Code session UPDATES its row rather than forking a second one. Always answers `204`; the hook prints nothing.

T837 adds the optional `synthesis_*` fields. They carry a summary the CLIENT already finished, on its own machine, from its own transcript: the raw transcript never reaches this endpoint and the server runs no model on this path. With at least one decision the row is written with `metadata.wrap_kind = "synthesis"` and its `description` is the `Decisions:` line boot serves as the tldr; with none it is the mechanical safety net, marked `synthesis_status: "degraded"` with the client's reason. A degraded snapshot never overwrites a `synthesis` or `seed` row already stored under the same `external_id`.

## Response `204`

Handled. A row was written, or the repo is disabled / capture_scope is off, or a better handoff for this session was preserved.

## Other responses

- `400`: Request body/query failed Zod validation.
- `401`: Missing or invalid credentials.

---

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