Atmee.aiDocs
APIAPI referenceAvatars

Start a file upload

POST
/v1/uploads

Gets a file to the Avatar API ahead of the create or replace that uses it, for clients that cannot send a file in the same request (an MCP tool, a chat assistant). kind is portrait (jpg, png or webp, <= 10 MB), voice (a 10-60 s recording: mp3, wav, m4a, aac, ogg, flac, opus or webm, <= 12 MB) or knowledge (pdf, docx, doc, txt, md, html, csv <= 50 MB; audio or video <= 20 MB). contentType, when given, is the only type the upload accepts.

Send the file one of two ways:

  • PUT it to uploadUrl with uploadHeaders (a Content-Type from allowedTypes when none was declared), at most maxBytes: curl -X PUT -H 'Content-Type: image/png' --data-binary @portrait.png '<uploadUrl>'.
  • Or give a person uploadPageUrl to open: a page that shows what is being uploaded and how it will be used, takes the file (or, for a voice, records one in the browser) and sends it. The link works for 15 minutes (uploadPageExpiresAt) and until the file has arrived.

Poll GET /v1/uploads/{uploadId} until status is uploaded, then pass upload:<uploadId> where POST /v1/avatars (assets) or the JSON form of PUT /v1/avatars/{avatarId}/appearance|voice|knowledge takes a URL. An upload works once and expires an hour after it was created. Requires avatars:write.

Authorization

headerX-Api-Key<token>

Secret embed API key (sk_atmee_...; keys minted before 2026-09 carry sk_live_...), held by the customer's own backend and never sent to a browser. Format: X-Api-Key: sk_atmee_....

Request Body

application/json
  1. body
kind*UploadKind
Value in"portrait""voice""knowledge"
fileName?string

The file's name; a knowledge file is stored and described under it.

Lengthlength <= 255
contentType?string

The file's type, one this kind takes; the upload then accepts only it.

Lengthlength <= 255

Response Body

The upload, waiting for its file.

application/json
  1. response
uploadId*string
Formatuuid
kind*UploadKind
Value in"portrait""voice""knowledge"
status*"pending"
Value in"pending"
uploadUrl*string

The signed target to PUT the file's bytes to, before expiresAt.

Formaturi
uploadHeaders*

Headers the PUT must send. Without a declared contentType, send a Content-Type from allowedTypes.

maxBytes*integer

The most bytes the PUT takes. A knowledge upload declared as audio or video gets the media cap (20 MB), one declared as a document or with no type the document cap (50 MB).

Formatint64
allowedTypes*array<string>
expiresAt*string
Formatdate-time
uploadPageUrl?string

A page a person opens to upload the file (or record a voice). Absent where no page is served.

Formaturi
uploadPageExpiresAt?string
Formatdate-time
Example Request
curl -X POST 'https://api.atmanity.us/v1/uploads' \  -H 'Content-Type: application/json' \  -d '{  "kind": "portrait"}'
Example Response
{  "uploadId": "ef523ba8-509e-47af-8e2c-5fa751596497",  "kind": "portrait",  "status": "pending",  "uploadUrl": "http://example.com",  "uploadHeaders": {    "property1": "string",    "property2": "string"  },  "maxBytes": 0,  "allowedTypes": [    "string"  ],  "expiresAt": "2019-08-24T14:15:22Z",  "uploadPageUrl": "http://example.com",  "uploadPageExpiresAt": "2019-08-24T14:15:22Z"}
Start a file upload — Atmee Docs