Posts
Upload media via signed URL
Receive an MCP-issued one-shot signed URL upload. Normally invoked by the request-media-upload-tool flow, not called directly.
POST
This endpoint is the destination of a signed POST URL issued by the MCPDocumentation Index
Fetch the complete documentation index at: https://docs.trypost.it/llms.txt
Use this file to discover all available pages before exploring further.
request-media-upload-tool. It exists to let AI agents and their clients upload local files to your workspace without provisioning a Personal Access Token — the signed URL itself is the auth.
You normally don’t call this endpoint directly. The flow is:
- AI agent calls
request-media-upload-tool→ receivesupload_url+upload_token - The agent (or the user) POSTs the file to
upload_url - AI agent calls
attach-media-from-upload-toolwith the sameupload_tokento attach the resulting Media to a post
POST /posts/{post}/media — direct upload to a specific post, no signed URL.
Path parameter
The single-use UUID baked into the signed URL by
request-media-upload-tool. Must be a valid UUID; non-UUID values 404.Query parameters (added by the signed URL)
These are added to the URL by Laravel’sURL::temporarySignedRoute and are covered by the HMAC signature — never set them yourself.
The workspace this upload belongs to. Tampering with this value invalidates the signature and the endpoint returns
403.Unix timestamp when the URL expires. Default TTL is 15 minutes from issuance (configurable via
MCP_UPLOAD_URL_TTL_MINUTES).HMAC-SHA256 of the URL + query parameters, signed with the app’s
APP_KEY. Verified by Laravel’s signed middleware before the controller runs.Request
Send asmultipart/form-data with a single media field.
The file to upload. Subject to the 50 MB hard cap for the MCP upload flow (configurable via
MCP_UPLOAD_MAX_SIZE_MB), plus the standard per-type MIME whitelist:- Images:
image/jpeg,image/png,image/gif,image/webp - Videos:
video/mp4,video/quicktime(MOV)
Content-Type header), so renaming evil.exe to photo.png doesn’t bypass the whitelist.Authentication
No Bearer token. The signed URL is the credential.- The
signedmiddleware verifies the HMAC againstAPP_KEYand rejects expired URLs with403. - An atomic
Cache::addplus aUNIQUEconstraint onmedia.upload_tokenensure the URL is single-use: the second POST with the sametokenreturns409. - The endpoint is rate-limited to 10 requests per minute per IP as defense in depth against floods of leaked URLs.
Behaviour
- The file is stored on the workspace’s configured filesystem disk (
local,s3,r2, etc.) atmedias/{uuid}.{ext}. The path is generated server-side — client filenames are never used in the path. - PNG and WebP still images are normalized to JPEG (q100) for universal platform compatibility. GIF is preserved (animation kept for X / Bluesky / Mastodon). Videos are stored as-is.
- The resulting
Mediarow is tagged with theupload_tokenso the AI agent can reference it later viaattach-media-from-upload-tool. The Media is created as a workspace asset — not yet attached to any post. - This endpoint is not triggered by the
POST /posts/{post}/mediaflow. It only handles MCP-issued signed URLs.
Response
Echo of the
{token} path parameter, for client convenience.The UUID of the created
Media record. Pass this (or the upload_token) to attach-media-from-upload-tool to attach to a post.image or video.The detected MIME type. Note that PNG/WebP inputs are reported as
image/jpeg due to the normalization step.The filename the client sent (stored as metadata, never used for the storage path).
Status codes
| Code | Meaning |
|---|---|
201 | Upload stored, Media created. |
403 | Signature invalid, expired, or any query parameter was tampered with. |
409 | Token already used (single-use enforcement). |
422 | File missing, too large (> MCP_UPLOAD_MAX_SIZE_MB), or disallowed MIME type. |
429 | Rate limit exceeded (more than 10 POSTs per minute from this IP). |

