Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/postlake-dev:postlake-dev-media-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: PostLake Media API
version: 1.0.0
description: Unified social media API. One API key, 10 platforms, normalised responses. Built for agents and developers.
contact:
url: https://postlake.dev
servers:
- url: https://api.postlake.dev
security:
- bearerAuth: []
tags:
- name: Media
description: Upload media for posts
paths:
/v1/media/policy:
get:
tags:
- Media
summary: Read uploaded-media retention policy
description: Applies to PostLake uploads on every plan while the account remains open, not external URLs. Minimum dates are not expiry dates. Source URLs are public; cancelling a post does not delete media. This is publishing storage, not a backup service. See https://postlake.dev/terms#media-retention.
responses:
'200':
description: Versioned minimum retention, scheduled protection and exceptions
content:
application/json:
schema:
type: object
properties:
version:
type: string
minimumDays:
type: integer
scheduledProtection:
type: string
automaticExpiry:
type: boolean
exceptions:
type: array
items:
type: string
scope:
type: string
accountRequirement:
type: string
publicUrls:
type: boolean
postRemovalDeletesMedia:
type: boolean
backupService:
type: boolean
required:
- version
- minimumDays
- scheduledProtection
- automaticExpiry
- exceptions
operationId: getV1MediaPolicy
x-operation-id-source: derived
/v1/media/{id}:
delete:
tags:
- Media
summary: Erase an uploaded file and its previews
description: Owner-scoped, irreversible erasure. First GET /v1/media/{id}/deletion, then send its snapshot. Blocks drafts, approval requests, queued/scheduled/processing targets, concurrent publication and more than 200 references. Replace/remove their media or cancel/reject those posts first. Terminal social posts remain online, but PostLake previews disappear. No publishing-credit refund. Storage failures retain a retryable deletion receipt. This overrides the minimum retention only at the owner's instruction. Does not erase external URLs or copies held independently by social networks.
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
snapshot:
type: string
required:
- snapshot
responses:
'200':
description: Original and stored previews removed; repeated completion returns the same receipt
content:
application/json:
schema:
type: object
properties:
id:
type: string
deleted:
type: boolean
deletesSocialPosts:
type: boolean
cancelsSchedules:
type: boolean
refundsPublishingCredits:
type: boolean
'400':
description: Snapshot is missing or invalid
'404':
description: Upload not found in this workspace
'409':
description: Referenced by pending work, concurrently publishing, stale snapshot or over 200 references
'500':
description: Storage cleanup incomplete; review and retry, not successful erasure
operationId: deleteV1MediaById
x-operation-id-source: derived
get:
tags:
- Media
summary: Read an uploaded asset and its retention terms
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Account-scoped media metadata
content:
application/json:
schema:
$ref: '#/components/schemas/MediaAsset'
'404':
description: Media not found in this account
operationId: getV1MediaById
x-operation-id-source: derived
/v1/media/{id}/deletion:
get:
tags:
- Media
summary: Preview upload erasure and affected posts
description: 'No side effects. Up to 200 affected posts, including draft/options/cover/thumbnail references; truncated=true requires support-assisted erasure. canDelete is a preview, not a lock: apply rechecks references and in-flight publication. state can be active, deleting or deleted. No external social post is deleted.'
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: snapshot, state, canDelete, references, truncated, warning and effects
content:
application/json:
schema:
$ref: '#/components/schemas/MediaDeletionPreview'
'404':
description: Upload not found in this workspace
operationId: getV1MediaByIdDeletion
x-operation-id-source: derived
/media/upload:
put:
tags:
- Media
summary: Complete an MCP local-file upload
description: 'Upload raw file bytes to the short-lived target returned by the MCP upload_media tool when called without a URL. Send the returned upload token as `Authorization: Bearer …` and the exact returned Content-Type. This endpoint does not accept a PostLake API key and is not called until upload_media has prepared a media id and target.'
requestBody:
required: true
content:
image/jpeg:
schema:
type: string
format: binary
image/png:
schema:
type: string
format: binary
image/webp:
schema:
type: string
format: binary
image/gif:
schema:
type: string
format: binary
video/mp4:
schema:
type: string
format: binary
video/quicktime:
schema:
type: string
format: binary
video/webm:
schema:
type: string
format: binary
responses:
'201':
description: Uploaded; returns the MediaAsset whose id is ready for create_post
content:
application/json:
schema:
$ref: '#/components/schemas/MediaAsset'
'400':
description: Content type, byte signature, exact size, or media limits did not match the prepared target
'401':
description: Upload token is missing, invalid, or expired
'409':
description: The upload target has already been used
operationId: putMediaUpload
x-operation-id-source: derived
/v1/media:
get:
tags:
- Media
summary: List uploaded files
description: Owner-scoped cursor pagination in descending media-ID order, not upload-time order. Deleted files are excluded; deleting files remain visible for retry. No post-history scan.
parameters:
- name: before
in: query
schema:
type: string
description: next from the previous response
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 50
responses:
'200':
description: items and next (null at end)
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/MediaAsset'
next:
type: string
nullable: true
operationId: getV1Media
x-operation-id-source: derived
post:
tags:
- Media
summary: Upload media
description: Upload media, either as raw binary with Content-Type set, or as multipart/form-data with a file part. For images the response includes the pixel dimensions, which are checked against each network's limits at publish time.
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
image/jpeg:
schema:
type: string
format: binary
image/png:
schema:
type: string
format: binary
image/gif:
schema:
type: string
format: binary
video/mp4:
schema:
type: string
format: binary
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
required:
- file
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/MediaAsset'
'400':
description: Empty body, missing Content-Type, no file part, or an unsupported media type
'401':
$ref: '#/components/responses/Unauthorized'
operationId: postV1Media
x-operation-id-source: derived
/v1/media/batch:
post:
tags:
- Media
summary: Upload or prepare several media items
description: 'Carousel helper. JSON `{ items: [{ contentType, sizeBytes }] }` returns signed five-minute PUT targets (same as MCP local upload). Multipart with multiple file parts uploads the bytes and returns MediaAsset records. Max 12 items.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 12
items:
type: object
required:
- contentType
properties:
contentType:
type: string
sizeBytes:
type: integer
minimum: 1
multipart/form-data:
schema:
type: object
additionalProperties:
type: string
format: binary
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
oneOf:
- $ref: '#/components/schemas/MediaAsset'
- type: object
'400':
description: Empty items, too many files, or an unsupported media type
'401':
$ref: '#/components/responses/Unauthorized'
operationId: postV1MediaBatch
x-operation-id-source: derived
components:
schemas:
ErrorResponse:
type: object
properties:
error:
$ref: '#/components/schemas/NormalisedError'
required:
- error
NormalisedError:
type: object
description: '`type` is the coarse category you route on and is deliberately small, so it cannot say WHICH input was wrong. `code`, `fix`, `docs` and `param` are what turn a rejection into something a caller can act on rather than guess at. They are optional only in the sense that not every error has all four.'
properties:
type:
type: string
description: Coarse category to route on, e.g. rate_limited, auth_expired, platform_rejected.
message:
type: string
platform:
oneOf:
- $ref: '#/components/schemas/Platform'
- type: 'null'
retryable:
type: boolean
code:
type: string
description: Stable, granular handle to branch on, e.g. text_too_long. Also the anchor in the error reference.
fix:
type: string
description: The next action, in plain words. Safe to show a person as-is.
docs:
type: string
format: uri
description: Where the rule is written down, so it is learned once rather than rediscovered.
param:
type: string
description: The request field at fault, so a form can mark the right input.
required:
- type
- message
- retryable
MediaAsset:
type: object
properties:
deletionState:
type: string
enum:
- deleting
description: Cleanup is incomplete and can be retried. This upload cannot be used in new posts.
retention:
type: object
description: Minimum 90 days from upload on every plan while the account is open. Scheduled references remain protected until terminal state plus 30 days if later. No automatic expiry currently. Account deletion, verified erasure requests and legal/security removal are exceptions. Source URLs are public, not private storage.
properties:
version:
type: string
minimumDays:
type: integer
minimumUntil:
type: string
format: date-time
scheduledProtection:
type: string
automaticExpiry:
type: boolean
exceptions:
type: array
items:
type: string
scope:
type: string
accountRequirement:
type: string
publicUrls:
type: boolean
postRemovalDeletesMedia:
type: boolean
backupService:
type: boolean
id:
type: string
url:
type: string
format: uri
contentType:
type: string
size:
type: integer
createdAt:
type: string
format: date-time
width:
type: integer
description: Pixel width. Images only, and absent when the header could not be read.
height:
type: integer
description: Pixel height. Images only, and absent when the header could not be read.
required:
- id
- url
- contentType
- size
- createdAt
Platform:
type: string
enum:
- bluesky
- threads
- x
- linkedin
- instagram
- tiktok
- facebook
- youtube
- pinterest
MediaDeletionPreview:
type: object
required:
- id
- state
- canDelete
- truncated
- references
- snapshot
- effects
- warning
properties:
id:
type: string
state:
type: string
enum:
- active
- deleting
- deleted
canDelete:
type: boolean
truncated:
type: boolean
snapshot:
type: string
warning:
type: string
references:
type: array
maxItems: 200
items:
type: object
properties:
id:
type: string
state:
type: string
text:
type: string
maxLength: 120
blocking:
type: boolean
required:
- id
- state
- text
- blocking
effects:
type: object
properties:
deletesSource:
type: boolean
enum:
- true
deletesPreviews:
type: boolean
enum:
- true
deletesSocialPosts:
type: boolean
enum:
- false
cancelsSchedules:
type: boolean
enum:
- false
refundsPublishingCredits:
type: boolean
enum:
- false
required:
- deletesSource
- deletesPreviews
- deletesSocialPosts
- cancelsSchedules
- refundsPublishingCredits
responses:
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
type: unauthorized
message: missing or invalid api key
retryable: false