API reference
Media
Upload a file once, then attach it to any number of posts by its id.
Upload an image
POST/api/public/v1/media
Send the image as multipart/form-data. Postzora checks the file’s real type and reads its size, so the composer’s per-network checks work on it.
Form fields
filefileRequired- A JPG, PNG, WebP or GIF, up to 16 MB.
alt_textstring- A description for people using screen readers, up to 1,000 characters. Networks that support alt text get it.
The media object
idinteger- Use it in
media_idswhen you create a post. kindstringimageorvideo.mime_type, sizestring, integer- The file type, and its size in bytes.
width, height, durationinteger or null- Pixels, and seconds for videos.
alt_textstring or null- The description you gave it.
curl -X POST https://api.postzora.com/api/public/v1/media \
-H "Authorization: Bearer $POSTZORA_API_KEY" \
-F "[email protected]" \
-F "alt_text=A calendar with a month of posts"import { readFile } from 'node:fs/promises'
const form = new FormData()
form.append('file', new Blob([await readFile('cover.png')]), 'cover.png')
form.append('alt_text', 'A calendar with a month of posts')
const response = await fetch('https://api.postzora.com/api/public/v1/media', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTZORA_API_KEY}`,
},
body: form,
})
const { data } = await response.json()import os
import requests
response = requests.post(
"https://api.postzora.com/api/public/v1/media",
headers={"Authorization": f"Bearer {os.environ['POSTZORA_API_KEY']}"},
files={"file": open("cover.png", "rb")},
data={"alt_text": "A calendar with a month of posts"},
)
data = response.json()["data"]{
"data": {
"id": 42,
"name": "cover.png",
"mime_type": "image/png",
"kind": "image",
"size": 284113,
"width": 1600,
"height": 900,
"duration": null,
"alt_text": "A calendar with a month of posts",
"url": "/api/v1/media/42/file",
"created_at": "2026-10-16T08:58:41.000000Z"
}
}Upload from a link
POST/api/public/v1/media/from-url
Postzora downloads the file from a public link and adds it to the library. Use it for videos, and for images that are already online. The link must open the file itself, without signing in, and the download has to finish within 20 seconds.
Body
urlstringRequired- A public
httporhttpslink to a JPG, PNG, WebP or GIF up to 16 MB, or an MP4, MOV or WebM up to 512 MB. Postzora checks the file’s real type, whatever the link or its server says. namestring- The file name to show in the library. Defaults to the last part of the link.
alt_textstring- A description for people using screen readers, up to 1,000 characters.
localhost or 10.0.0.0/8, are refused, and so are redirects that lead to them.curl -X POST https://api.postzora.com/api/public/v1/media/from-url \
-H "Authorization: Bearer $POSTZORA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/launch.mp4",
"alt_text": "Our launch video"
}'const response = await fetch('https://api.postzora.com/api/public/v1/media/from-url', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTZORA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://example.com/launch.mp4',
alt_text: 'Our launch video',
}),
})
const { data } = await response.json()import os
import requests
response = requests.post(
"https://api.postzora.com/api/public/v1/media/from-url",
headers={"Authorization": f"Bearer {os.environ['POSTZORA_API_KEY']}"},
json={
"url": "https://example.com/launch.mp4",
"alt_text": "Our launch video",
},
)
data = response.json()["data"]{
"data": {
"id": 42,
"name": "cover.png",
"mime_type": "image/png",
"kind": "image",
"size": 284113,
"width": 1600,
"height": 900,
"duration": null,
"alt_text": "A calendar with a month of posts",
"url": "/api/v1/media/42/file",
"created_at": "2026-10-16T08:58:41.000000Z"
}
}Upload with links
POST/api/public/v1/media/upload-links
For large files and scripts: open an upload with your key, then send the file in chunks to the links it returns. The links need no key and expire after 6 hours, so a script or AI assistant can use them on their own.
Body
namestringRequired- The file name.
mime_typestringRequiredimage/jpeg,image/png,image/webp,image/gif,video/mp4,video/quicktimeorvideo/webm.sizeintegerRequired- The exact size in bytes. Images up to 16 MB, videos up to 512 MB.
The answer
chunk_size, total_chunksinteger- Split the file into chunks of
chunk_sizebytes; the last one may be smaller. chunk_urlstringPUTeach chunk here as the raw body, with{index}replaced by 0, 1, 2 and so on. Sending a chunk again replaces it.complete_urlstringPOSThere when every chunk is in, optionally withalt_text. The answer is the new media object.expires_atstring- When the links stop working.
curl -X POST https://api.postzora.com/api/public/v1/media/upload-links \
-H "Authorization: Bearer $POSTZORA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "launch.mp4",
"mime_type": "video/mp4",
"size": 48211904
}'const response = await fetch('https://api.postzora.com/api/public/v1/media/upload-links', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTZORA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: 'launch.mp4', mime_type: 'video/mp4', size: 48211904 }),
})
const { data } = await response.json()import os
import requests
response = requests.post(
"https://api.postzora.com/api/public/v1/media/upload-links",
headers={"Authorization": f"Bearer {os.environ['POSTZORA_API_KEY']}"},
json={
"name": "launch.mp4",
"mime_type": "video/mp4",
"size": 48211904,
},
)
data = response.json()["data"]List media
GET/api/public/v1/media
Returns the media library, newest first, 30 files per page. Follow links.next until it’s null to read it all.
Query parameters
pageinteger- The page to return, starting at 1.
curl -G https://api.postzora.com/api/public/v1/media \
-H "Authorization: Bearer $POSTZORA_API_KEY" \
--data-urlencode "page=1"const response = await fetch(`https://api.postzora.com/api/public/v1/media?${new URLSearchParams({ page: '1' })}`, {
headers: {
Authorization: `Bearer ${process.env.POSTZORA_API_KEY}`,
},
})
const { data } = await response.json()import os
import requests
response = requests.get(
"https://api.postzora.com/api/public/v1/media",
headers={"Authorization": f"Bearer {os.environ['POSTZORA_API_KEY']}"},
params={"page": "1"},
)
data = response.json()["data"]{
"data": [
{
"id": 42,
"name": "cover.png",
"mime_type": "image/png",
"kind": "image",
"size": 284113,
"width": 1600,
"height": 900,
"duration": null,
"alt_text": "A calendar with a month of posts",
"url": "/api/v1/media/42/file",
"created_at": "2026-10-16T08:58:41.000000Z"
}
],
"links": {
"first": "https://api.postzora.com/api/public/v1/media?page=1",
"last": "https://api.postzora.com/api/public/v1/media?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 30,
"total": 1
}
}Questions about the API? Email [email protected].