postlake-dev Media API

Upload media for posts

Operations 8

GET /v1/media/policy Read uploaded-media retention policy #
DELETE /v1/media/{id} Erase an uploaded file and its previews #
GET /v1/media/{id} Read an uploaded asset and its retention terms #
GET /v1/media/{id}/deletion Preview upload erasure and affected posts #
PUT /media/upload Complete an MCP local-file upload #
GET /v1/media List uploaded files #
POST /v1/media Upload media #
POST /v1/media/batch Upload or prepare several media items #

Work with this as data

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 Specification

postlake-dev-media-api-openapi.yml Raw ↑
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