Start a file upload
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:
PUTit touploadUrlwithuploadHeaders(aContent-TypefromallowedTypeswhen none was declared), at mostmaxBytes:curl -X PUT -H 'Content-Type: image/png' --data-binary @portrait.png '<uploadUrl>'.- Or give a person
uploadPageUrlto 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.
X-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_....
application/json- body
kind*UploadKind"portrait""voice""knowledge"fileName?stringThe file's name; a knowledge file is stored and described under it.
length <= 255contentType?stringThe file's type, one this kind takes; the upload then accepts only it.
length <= 255The upload, waiting for its file.
application/json- response
uploadId*stringuuidkind*UploadKind"portrait""voice""knowledge"status*"pending""pending"uploadUrl*stringThe signed target to PUT the file's bytes to, before expiresAt.
uriuploadHeaders*Headers the PUT must send. Without a declared contentType, send a Content-Type from allowedTypes.
maxBytes*integerThe 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).
int64allowedTypes*array<string>expiresAt*stringdate-timeuploadPageUrl?stringA page a person opens to upload the file (or record a voice). Absent where no page is served.
uriuploadPageExpiresAt?stringdate-timecurl -X POST 'https://api.atmanity.us/v1/uploads' \ -H 'Content-Type: application/json' \ -d '{ "kind": "portrait"}'{ "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"}Set the avatar's Explore thumbnail PUT
A custom thumbnail for the avatar's card on Explore, as Creator Studio's share card uploads one: one image (jpg, png or webp, <= 10 MB) as the file part, or, on an instance that keeps uploads, application/json {"image": "<https URL | upload:<uploadId>>"} (a portrait upload from POST /v1/uploads, consumed when the thumbnail is set).
Upload status GET
pending until the file arrives, then uploaded (usable once), consumed once a create or replace used it, or expired an hour after it was created.

