PublishQPublishQ

Create media upload

POST
/media/uploads

Upload a file of up to 4 GB (500 MB on the Free plan) straight to storage:

  1. Call this endpoint with filename, contentType and fileSize. You get back an id and an uploadUrl.
  2. PUT the file to uploadUrl with the same Content-Type header. Storage answers 200, or 403 if the file is not exactly fileSize bytes.
  3. Optional: call Complete media upload to add the file to your media library now.
  4. Put the id in mediaIds when you create or update a post.

Authorization

ApiKeyAuth
AuthorizationBearer <token>

PublishQ API key sent as Authorization: Bearer pq_live_....

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://publishq.com/api/v1/media/uploads" \  -H "Content-Type: application/json" \  -d '{    "filename": "launch-video.mp4",    "contentType": "video/mp4",    "fileSize": 262144000  }'
{
  "id": "f6370ca1-1f47-4f68-be72-c1206913b326",
  "uploadUrl": "https://s3.us-east-1.amazonaws.com/...?X-Amz-Signature=...",
  "expiresAt": "2026-10-21T15:36:39.000Z"
}
{
  "error": {
    "title": "Bad Request",
    "status": 400,
    "code": "validation_failed",
    "message": "Request validation failed",
    "instance": "/api/v1/media",
    "details": {
      "errors": [
        {
          "path": "mediaTypes.0",
          "message": "Invalid option: expected one of \"IMAGE\"|\"VIDEO\"",
          "code": "invalid_value"
        }
      ]
    }
  }
}

{
  "error": {
    "title": "Unauthorized",
    "status": 401,
    "code": "missing_auth",
    "message": "Missing Authorization header",
    "instance": "/api/v1/posts"
  }
}

{
  "error": {
    "title": "Forbidden",
    "status": 403,
    "code": "insufficient_scope",
    "message": "The API key does not have the required scope: posts:write",
    "instance": "/api/v1/posts",
    "details": {
      "property1": {},
      "property2": {}
    }
  }
}
{
  "error": {
    "title": "Forbidden",
    "status": 403,
    "code": "insufficient_scope",
    "message": "Missing required scope: media:write",
    "instance": "/api/v1/media/uploads"
  }
}
{
  "error": {
    "title": "Payload Too Large",
    "status": 413,
    "code": "file_too_large",
    "message": "File size too large. Free accounts can upload files up to 500 MB. Upgrade to upload files up to 4 GB.",
    "instance": "/api/v1/media"
  }
}
{
  "error": {
    "title": "Unsupported Media Type",
    "status": 415,
    "code": "unsupported_file_type",
    "message": "Unsupported file type: the file content is audio/mpeg, even though it is labelled video/mp4. Renaming a file does not change its format. Supported types: image/jpeg, image/png, image/gif, image/webp, video/mp4, video/webm, video/quicktime, video/x-msvideo.",
    "instance": "/api/v1/media"
  }
}
{
  "error": {
    "title": "Too Many Requests",
    "status": 429,
    "code": "rate_limit_exceeded",
    "message": "Too Many Requests",
    "instance": "/api/v1/media/uploads",
    "details": {
      "retryAfter": 60
    }
  }
}