Upload Instagram Cover
Upload a custom cover image for an Instagram Reel. Publora hosts the image and returns a public URL you set as platformSettings.instagram.coverUrl. This is the file-upload alternative to hosting the JPEG yourself — see Instagram → Platform-Specific Settings for the coverUrl field.
The uploaded image is stored as a JPEG regardless of input format (Instagram accepts only JPEG for Reel covers); PNG and WebP are transcoded server-side, with transparency flattened onto a white background.
Endpoint
POST https://api.publora.com/api/v1/upload-instagram-coverHeaders
| Header | Required | Description |
|---|---|---|
x-publora-key |
Yes | Your API key |
x-publora-user-id |
No | Managed user ID (workspace only) |
Content-Type |
Yes | multipart/form-data |
Request Body
Sent as multipart/form-data:
| Field | Type | Required | Description |
|---|---|---|---|
cover |
file | Yes | The cover image. JPEG, PNG, or WebP, 8 MB max. PNG/WebP are converted to JPEG. |
postGroupId |
string | Yes | The post group this cover belongs to. Must be an editable post (draft or scheduled) that you own. |
The target post group must be in draft or scheduled status and not currently publishing. A cover cannot be uploaded for a post that is already published, failed, or mid-publish.
Response
{
"success": true,
"cover": {
"mediaId": "665f8a1b2c3d4e5f6a7b8c9d",
"url": "https://media.publora.com/images/665f...-reel-cover.jpg"
},
"message": "Set platformSettings.instagram.coverUrl to cover.url via /update-post to use this image as the Reels cover."
}| Field | Description |
|---|---|
success |
true when the cover was uploaded and stored. |
cover.mediaId |
The unique ID of the created cover media record. |
cover.url |
The public JPEG URL. Set this as platformSettings.instagram.coverUrl via update-post. |
message |
Reminder of the next step. |
Two-step flow: uploading the cover does not attach it to the post by itself. After a successful upload, call
PUT /update-post/{postGroupId}withplatformSettings.instagram.coverUrlset to the returnedcover.url. Deleting that media (or clearingcoverUrl) reverts the Reel to the automatic/frame-based cover.
Usage
cURL
# 1. Upload the cover image
COVER_RESPONSE=$(curl -s -X POST https://api.publora.com/api/v1/upload-instagram-cover \
-H "x-publora-key: $PUBLORA_API_KEY" \
-F "cover=@./reel-cover.png" \
-F "postGroupId=507f1f77bcf86cd799439011")
COVER_URL=$(echo "$COVER_RESPONSE" | jq -r '.cover.url')
# 2. Attach it to the Reel
curl -X PUT https://api.publora.com/api/v1/update-post/507f1f77bcf86cd799439011 \
-H "x-publora-key: $PUBLORA_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"platformSettings\": {
\"instagram\": { \"coverUrl\": \"$COVER_URL\" }
}
}"JavaScript (fetch)
// 1. Upload the cover image
const form = new FormData();
form.append('cover', coverFile); // a File/Blob (JPEG, PNG, or WebP, <= 8 MB)
form.append('postGroupId', '507f1f77bcf86cd799439011');
const uploadRes = await fetch(
'https://api.publora.com/api/v1/upload-instagram-cover',
{
method: 'POST',
headers: { 'x-publora-key': process.env.PUBLORA_API_KEY },
body: form, // do NOT set Content-Type — fetch sets the multipart boundary
}
);
const { cover } = await uploadRes.json();
// 2. Attach it to the Reel
await fetch(
'https://api.publora.com/api/v1/update-post/507f1f77bcf86cd799439011',
{
method: 'PUT',
headers: {
'x-publora-key': process.env.PUBLORA_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
platformSettings: { instagram: { coverUrl: cover.url } },
}),
}
);Python (requests)
import requests
BASE_URL = "https://api.publora.com/api/v1"
headers = {"x-publora-key": PUBLORA_API_KEY}
post_group_id = "507f1f77bcf86cd799439011"
# 1. Upload the cover image
with open("reel-cover.png", "rb") as f:
upload = requests.post(
f"{BASE_URL}/upload-instagram-cover",
headers=headers,
files={"cover": ("reel-cover.png", f, "image/png")},
data={"postGroupId": post_group_id},
)
cover_url = upload.json()["cover"]["url"]
# 2. Attach it to the Reel
requests.put(
f"{BASE_URL}/update-post/{post_group_id}",
headers={**headers, "Content-Type": "application/json"},
json={"platformSettings": {"instagram": {"coverUrl": cover_url}}},
)Errors
| Status | Error | Cause |
|---|---|---|
400 |
postGroupId is required |
The postGroupId field was missing. |
400 |
Invalid postGroupId |
The postGroupId is not a valid ID. |
400 |
cover file is required |
No cover file part was sent. |
400 |
Instagram covers must be JPEG, PNG, or WebP images |
Unsupported file type. |
400 |
Instagram covers must be 8 MB or smaller |
The uploaded file exceeds 8 MB. |
400 |
Instagram cover exceeds 8 MB after JPEG conversion; use a smaller image |
A dense PNG/WebP expanded past 8 MB when converted to JPEG. |
400 |
Cannot upload Instagram cover for a non-editable post |
The post is published or failed. |
404 |
Post group not found |
No such post group for this account. |
409 |
Post group is currently being published; cannot upload Instagram cover. Retry once publishing completes. |
The scheduler is mid-publish. |
Notes
- Reels only. A cover applies to videos published as Reels (
videoType: "REELS", the default). It is ignored for Stories and image posts. - Precedence. A cover set via
coverUrltakes precedence over frame-based cover selection (videoTimestamp). - Cleanup. Replacing or clearing the cover, or deleting the post, removes the stored cover file automatically.