# Upload Chat Image

```
POST 
/v1/chats/upload-image
```

Phase 95 SA1 — chat textarea image upload (PHASE95/PLAN.md contract).

Accepts a single image (PNG / JPEG / WebP / GIF, max 10 MB) from the chat textarea drag-and-drop or paperclip path (SA2). Persists to object storage under `account/<account_id>/chat-images/<uuid>.<ext>` and returns a 1-hour presigned GET URL the frontend can attach to the next user message via `images: [{ url, objectPath }]`.

We do server-side PUT rather than the 2-step presigned-PUT flow used by `/v1/upload/<folder>` for two reasons:

1. Chat UX wants a single round-trip (drop → upload → attach) — the 2-step flow needs a second fetch from the browser to S3 which adds a round-trip and surfaces CORS pain.
2. We validate mimetype + size on the server so the LLM provider (Anthropic / OpenAI) never sees malformed payloads. Presigned PUT skips that gate.

The returned URL is intentionally short-lived (3600s). For long-running chats we re-presign via `object_service.get_presigned_url(object_path)` on render — the `object_path` round-trip is the source of truth, not the URL itself.

## Request[​](#request "Lien direct vers request")

## Responses[​](#responses "Lien direct vers Responses")

* 201
* 404
* 422

Successful Response

Not found

Validation Error
