---
title: "Read a message that arrived and prepare the answer"
method: POST
path: "/api/v1/handling"
tags: ["Dardaris"]
---

# Read a message that arrived and prepare the answer

`POST /api/v1/handling`

## Request

- Base URL: `http://localhost:5180`
- URL: `http://localhost:5180/api/v1/handling`
- Auth: API key in cookie `better-auth.session_token`

Runs the whole thing over one message: works out what it is about, files it against the lease, unit or building it names, does what it needs, and writes the reply.

What it does is decided by an agent reading the message with the tools the sender is allowed: it may read a deed or a lease that arrived, file a document they sent in, look up the records, make or propose a change, plan a task, or hand the message to you. A message that needs you goes on your list, and its reply waits for you.

A document that arrived with the message is read when its pages come with the request, as `page` parts of a multipart form beside the file itself. Drawing a PDF needs a renderer and there is none here, so the caller draws it: a browser with pdf.js, the command line with poppler. Without the pages the file is filed and the step says it was not read.

The reply is written on the conversation and never sent: nothing here can send from your address, so the most a run does is file the answer. It is filed rather than left waiting only where the master switch is on, your settings say so, the guardrails resolve to something other than "ask me first", and nothing about the message says a person should answer it. Any one of those leaves it waiting, and the step names which.

## Request body

- object
  - `messageId` string: The message to handle. Leave it out and the newest one on `threadId` is taken.
  - `threadId` string: The conversation to handle. Required when no `messageId` is given.

## Response `200`

What the run did, and what it left behind.

- object
  - `ok` unknown, required
  - `data` object, required
    - `threadId` string, required: Stable record id, e.g. `lse_012`.
    - `messageId` string, nullable, required: Stable record id, e.g. `lse_012`.
    - `runId` string, nullable, required: Stable record id, e.g. `lse_012`.
    - `status` 'running' | 'awaiting_approval' | 'completed' | 'failed' | 'skipped' | 'cancelled', nullable, required
    - `startedAt` string, nullable, required: ISO 8601 timestamp.
    - `summary` string, nullable, required: One line, in Dardaris’s own voice.
    - `intent` string, nullable, required: What the message was read as. The same vocabulary the Messages room displays.
    - `confidence` number, nullable, required: 0 to 1, as the classifier rated its own reading.
    - `sentiment` 'positive' | 'neutral' | 'frustrated' | 'angry', nullable, required
    - `escalationRisk` 'none' | 'low' | 'medium' | 'high', nullable, required: High is what stops a reply going out on its own, whatever the settings say.
    - `about` object, required: The records the conversation is filed against. Resolved through buildingLabel(), so an owner alias is honoured.
      - `leaseId` string: Stable record id, e.g. `lse_012`.
      - `leaseReference` string
      - `unitId` string: Stable record id, e.g. `lse_012`.
      - `unitLabel` string
      - `buildingId` string: Stable record id, e.g. `lse_012`.
      - `buildingLabel` string
    - `steps` object[], required: Every step of the run, in the order it ran.
      - `actionId` string, required
      - `kind` string, required: `classify_message`, `read_document`, `draft_reply`, `create_task`, `send_message` and the rest.
      - `label` string, required
      - `status` 'pending' | 'awaiting_approval' | 'done' | 'skipped' | 'failed', required
      - `at` string: ISO 8601 timestamp.
      - `produced` object[]
        - `kind` string, required
        - `id` string, required: Stable record id, e.g. `lse_012`.
        - `label` string, required
      - `detail` string: What the step did, in the owner’s words. This is what makes a run checkable.
      - `skipReason` string: Why nothing happened, where nothing did.
      - `links` object[], required: Where each record the step made can be opened. A record with no page of its own carries no `to`.
        - `label` string, required
        - `to` string
    - `draft` object, nullable, required: The reply, written and waiting to be read. Null once it is filed on the thread or discarded.
      - `id` string, required: Stable record id, e.g. `lse_012`.
      - `subject` string, required
      - `body` string, required
      - `sentAt` string, required: ISO 8601 timestamp.
    - `filed` boolean, required: True where the run sent its own reply, or filed it on the thread where no mailbox here could send it, rather than leaving it for you.
  - `meta` object, required
    - `requestId` string, required: Echoed in the x-request-id header. Quote it in a bug report.

## Other responses

- `400`: Neither a message nor a conversation was named, or the pages were over the ceiling.
- `401`: No session. Sign in first.
- `404`: No message or conversation with that id belongs to you.
- `429`: Over the reading budget.

---

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