---
title: "Create Upload Url"
method: POST
path: "/v1/attachments/upload-url"
tags: ["attachments"]
---

# Create Upload Url

`POST /v1/attachments/upload-url`

## Request

- Base URL: `https://api.heirmos.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.heirmos.com/v1/attachments/upload-url`
- Auth: HTTP bearer

Mint a one-shot upload URL (Phase 25 — the MCP side channel).

An AI chat host cannot hand this server the bytes of an image the user
pasted: MCP has no binary primitive and base64 in a tool argument would cost
~1.4M tokens for a 4 MiB file. So the model asks for this URL and uploads
with ``curl -X PUT`` from its own sandbox — the bytes never pass through the
context window.

Same 20/min bucket as the multipart upload: each ticket ultimately costs one
storage object and one vision call.

## Response `201`

Successful Response

- AttachmentUploadTicket: POST /v1/attachments/upload-url — a one-shot upload address (Phase 25). The plaintext token appears here and nowhere else (only its sha256 is stored), embedded in ``upload_url`` so the caller has a single string to hand to ``curl -X PUT``. ``max_bytes`` / ``accepted_mime_types`` ride along because the consumer is an LLM that would otherwise have to guess, and a rejected upload costs a burnt token.
  - `upload_url` string, required
  - `expires_at` string, date-time, required
  - `max_bytes` integer, required
  - `accepted_mime_types` string[], required

---

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