Recipes
Post an Instagram Carousel
Upload images, finalise media processing, create a carousel post, and schedule it.
Post an Instagram carousel (multi-image post) using the full API upload flow: upload each image, finalise processing, create the content item, then schedule a publish run.
Step 1: Upload and finalise each image
For each slide: request an upload URL, upload bytes with PUT, then call PATCH status=ready_for_processing and wait until the media is completed.
JavaScript
const apiKey = "wahlu_live_your_api_key_here";
const headers = {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
};
async function waitForMediaCompleted(brandId, mediaId, timeoutMs = 120000) {
const started = Date.now();
while (Date.now() - started < timeoutMs) {
const mediaRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/media/${mediaId}`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
const { data: media } = await mediaRes.json();
if (media.status === "completed") return media.id;
if (media.status === "failed") {
throw new Error(`Media processing failed for ${mediaId}`);
}
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error(`Timed out waiting for media ${mediaId}`);
}
async function uploadAndFinaliseImage(brandId, filename, fileBuffer) {
// A) Create signed upload URL
const uploadRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/media/upload-url`,
{
method: "POST",
headers,
body: JSON.stringify({
filename,
content_type: "image/jpeg",
size: fileBuffer.length,
source: "upload",
}),
}
);
const { data: upload } = await uploadRes.json();
// B) Upload bytes
await fetch(upload.upload_url, {
method: "PUT",
headers: { "Content-Type": "image/jpeg" },
body: fileBuffer,
});
// C) Finalise upload + queue processing
await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/media/${upload.id}`,
{
method: "PATCH",
headers,
body: JSON.stringify({ status: "ready_for_processing" }),
}
);
// D) Wait until media is completed
return waitForMediaCompleted(brandId, upload.id);
}
const imagePaths = ["slide1.jpg", "slide2.jpg", "slide3.jpg"];
const mediaIds = [];
for (const imagePath of imagePaths) {
const fileBuffer = fs.readFileSync(imagePath);
const mediaId = await uploadAndFinaliseImage(brandId, imagePath, fileBuffer);
mediaIds.push(mediaId);
console.log(`Completed: ${imagePath} → ${mediaId}`);
}Step 2: Create the Instagram carousel content item
Set post_type to "GRID_POST" and pass all the media IDs in the media_ids array. The order of IDs determines the slide order. Instagram treats a grid post with multiple images as a carousel.
JavaScript
const contentItemRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/content-items`,
{
method: "POST",
headers: {
Authorization: "Bearer wahlu_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Product Feature Carousel",
instagram_settings: {
description: "Swipe through our top 3 new features! Which one are you most excited about? #carousel #productupdate",
media_ids: mediaIds,
post_type: "GRID_POST",
},
}),
}
);
const { data: contentItem } = await contentItemRes.json();
console.log(`Carousel content item created: ${contentItem.id}`);Step 3: Schedule it
Schedule the carousel the same way you would any other content item.
JavaScript
// Get the Instagram integration ID
const integrationsRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/integrations`,
{ headers: { Authorization: "Bearer wahlu_live_your_api_key_here" } }
);
const { data: integrations } = await integrationsRes.json();
const instagram = integrations.find(i => i.platform === "instagram");
// Schedule for tomorrow at 12pm UTC
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(12, 0, 0, 0);
const scheduleRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/publish-runs`,
{
method: "POST",
headers: {
Authorization: "Bearer wahlu_live_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
content_item_id: contentItem.id,
scheduled_at: tomorrow.toISOString(),
integration_ids: [instagram.id],
}),
}
);
const { data: publishRun } = await scheduleRes.json();
console.log(`Carousel publish run scheduled for ${publishRun.scheduled_at}`);Step 4: Verify publication status
JavaScript
const pubsRes = await fetch(
`https://api.wahlu.com/v1/brands/${brandId}/publications?limit=20`,
{ headers: { Authorization: "Bearer wahlu_live_your_api_key_here" } }
);
const { data: publications } = await pubsRes.json();
const latestForPost = publications.find((p) => p.post_id === contentItem.id);
console.log(latestForPost?.status, latestForPost?.failure_reason);