# Media & Images · PostLake Docs > Markdown version of https://docs.postlake.dev/media . The canonical page for humans. > PostLake is the social media API for AI agents: https://postlake.dev/llms.txt Upload media once to get an id, then attach it to a post. Each network has its own limits. A media set that isn't valid for one target fails just that target. ## Upload Two ways, whichever suits your client. POST the raw bytes with the correct `Content-Type`: ``` curl -X POST https://api.postlake.dev/v1/media \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: image/jpeg" \ --data-binary @photo.jpg ``` Or send it as a form file, which is what most HTTP libraries do by default: ``` curl -X POST https://api.postlake.dev/v1/media \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "file=@photo.jpg" ``` Either way you get back a `MediaAsset`. For images it includes the pixel dimensions: ``` { "id": "med_abc", "url": "https://…", "contentType": "image/jpeg", "size": 208134, "width": 1080, "height": 1920 } ``` ### From a local MCP agent Call `upload_media` without `url`, passing the file's `contentType` and `sizeBytes`. It returns a five-minute signed PUT target and a preallocated `med_…` id. The agent PUTs the local bytes with the returned headers, then uses that id in `create_post`. For several slides, call `upload_media_batch`. The file does not need public hosting and its bytes do not pass through MCP JSON or base64. See the [MCP local-file workflow](https://postlake.dev/mcp#local-media). `POST /v1/media/batch` takes either JSON `{ "items": [{ "contentType": "image/jpeg", "sizeBytes": 123 }] }` (signed five-minute PUT targets) or multipart with multiple file parts. Max 12 items. Use this for a carousel instead of one request per slide. ## Reuse and retention Successfully uploaded PostLake assets have a minimum 90-day retention period from upload while the account remains open. This applies to free, PAYG and subscription accounts; it does not depend on a paid plan, credit balance or recent activity. Assets referenced by scheduled posts remain protected until the post completes, fails, is rejected or is cancelled, plus 30 days. Every reused reference must be respected, and the later of that protection and the original 90-day minimum applies. There is currently no automatic expiry, so the minimum date is not a deletion date. Account deletion, a verified erasure request, and necessary legal or security removal are exceptions. Cancelling, rejecting or deleting a post does not delete its media. - `GET /v1/media/policy` returns the versioned policy. - `GET /v1/media/{id}` returns account-scoped metadata and `retention.minimumUntil`. - Upload responses include retention terms. SDK methods are `media.policy()` and `media.get(id)`. - The five-minute expiry applies only to the signed upload URL, not the uploaded asset. - Keep durable originals and your campaign-to-media mapping. Reuse existing IDs while available; repeated uploads do not promise deduplication. Future cleanup must preserve both the minimum period and scheduled-post protection. Storage deployment checks reject automatic object-deletion rules that could bypass this policy. Posts can carry `campaign` and `assetMetadata`; those describe the post, not ownership of the uploaded asset. **Public source URLs:** anyone with an uploaded file or preview URL can access it. A private YouTube publication does not make the source upload private. These URLs are not suitable for confidential documents or secrets. External URLs have no PostLake retention protection. **Storage purpose and erasure:** PostLake is a publishing service, not a backup archive or unrelated CDN. No current automatic expiry does not mean unlimited permanent storage. Use Uploads in the dashboard or the guarded API below to erase individual files; support can help with verified erasure requests. Account erasure removes original files and previews. Channel disconnection and subscription cancellation do not erase media. Future routine expiry changes require notice and must preserve protection already granted. See [retention terms](https://postlake.dev/terms#media-retention), [privacy](https://postlake.dev/privacy#retention) and [acceptable use](https://postlake.dev/acceptable-use). ## Choose the right removal action | Action | What changes | What stays | | --- | --- | --- | | Discard a personal draft | Removes the saved draft. Nothing is sent. | Uploaded files and other posts. | | Reject an approval request | Records rejection and prevents that publication. | The request, decision and uploads remain on record. | | Cancel a schedule | Stops a future publication that has not started. | Uploaded files, other schedules and previously published posts. | | Remove a published post | Requests network removal where supported. Unsupported or failed destinations stay online. | Uploads; spent publishing credits are not refunded. | | Delete an upload | Erases PostLake's original file and stored previews. | Published social posts and their PostLake records. Their local previews will disappear. | | Disconnect a channel | Removes PostLake's access to that channel. | Social posts, uploads and saved schedules. Schedules may need reconnection. | ### Delete an uploaded file safely - Open [Uploads](https://app.postlake.dev/app/media) and choose Review deletion. The review lists affected posts before you confirm. - Replace or remove the file from drafts and pending publications first, or cancel schedules and reject approval requests that no longer need it. An upload shared by another pending post stays protected. - Confirm Permanently delete upload. Published social copies stay online. Copies downloaded by other people cannot be recalled. API clients first call `GET /v1/media/{id}/deletion`, then `DELETE /v1/media/{id}` with `{ "snapshot": "the preview snapshot" }`. A stale review, pending reference or concurrent publication returns `409`, with no successful erasure claimed. Review again before retrying. Storage failures retain a deletion-in-progress manifest so cleanup can be retried; completed requests return a repeatable receipt. A deleted ID cannot be uploaded to again. `GET /v1/media?limit=50` lists account-owned files with `items` and `next`. Pass `before=next` for the next page. The maximum page size is 100; ordering is descending media ID, not upload time. Completed deletions are excluded. At most 200 references are shown per erasure review; files used by more saved posts require support-assisted erasure. This limit bounds database work, not the number of posts you may schedule. MCP agents use `manage_media` with `action=list`, then `action=preview_delete` and an upload `id`. Only after the owner confirms erasure should the agent use `action=delete` with that snapshot. SDK source provides `media.list()`, `media.deletionPreview(id)` and `media.delete(id, snapshot)`. Check your installed SDK version; REST and MCP do not depend on an SDK update. ### Remove a post from social networks In Post details choose Review network removal. The preview identifies each destination and links to posts that must be removed manually. Instagram and TikTok posts must be removed in their apps; connecting Instagram through Facebook does not enable published-post deletion. Facebook image Stories are also not removable through this API. Other destinations depend on the connected account, permissions and the network accepting removal. `GET /v1/posts/{id}/deletion` previews support and consequences. Apply `DELETE /v1/posts/{id}` with its `snapshot`. `200` means the local action completed or all network removals were accepted. `207` reports destinations that remain online; inspect every target's `deleted`, `verified` and `reason`. Acceptance is not the same as confirmed absence. Accepted destinations are remembered on partial results and are not removed again on retry. Do not infer success from the post disappearing from one network. For cancellation-only integrations, use `POST /v1/posts/{id}/cancel`, which cannot retract published content. **Supported:** JPEG, PNG, WebP and GIF images; MP4, MOV and WebM video. Video-only networks (YouTube, TikTok) require a video asset. ## Pixel limits Some networks reject an image for its dimensions, and several only do so *after* accepting the upload. TikTok is the worst case: it takes the post, processes it in the background, and fails a minute later with `picture_size_check_failed`, which names neither the limit nor the offending image. So we check before publishing. An image outside a network's range fails validation immediately, with the limit and the actual size in the message: ``` { "error": { "type": "invalid_input", "message": "TikTok images must be at most 1080x1920. This one is 2160x3840" } } ``` Current limits are on the [platforms page](https://postlake.dev/platforms), and in `get_platform_capabilities` as `maxPx`. TikTok photos must be between 540x960 and 1080x1920. Where we cannot read an image's header we do not guess, and the check is skipped rather than failing the post. ## Attach. Globally or per platform Put ids in `media` to attach to every account, or use `mediaOverrides` to give each platform its own set (a square image for Instagram, a video for TikTok). The `url` from the upload response works anywhere an id does, so you can pass back whichever field you kept. ``` { "text": "Launch day", "media": ["med_abc"], "mediaOverrides": { "tiktok": ["med_video"] }, "accounts": ["acc_ig", "acc_tt"] } ``` ## Per-platform media limits | Platform | Media | | --- | --- | | **Bluesky** | Up to 4 images, or 1 video | | **Threads** | Image carousel, or video | | **Instagram** | JPEG or PNG images, or video (Reels and Stories). PostLake converts PNG to JPEG for Instagram at create/validate, with a warning. The original PNG stays available for other networks. | | **TikTok** | JPEG/WebP photos (max 1080×1920) or video. PNG is converted to JPEG at create/validate, with a warning. | | **YouTube** | Video only | | **X, Facebook** | Images and video | | **LinkedIn** | Images. Video is not accepted on a personal member profile. | | **Pinterest** | Image or video (needs a `boardId`) | These are the practical rules today; call `GET /v1/platforms/{platform}` for the live, authoritative limits (max count, size, aspect) so you, or an agent, can validate before posting. ## Alt text Provide accessibility alt text per media item through `platformOptions` / media alt overrides. If a media set is invalid for a target, that target fails with a clear `error` and the others still publish, see [Errors](https://postlake.dev/errors).