PostNitro Carousel Generator
Create social media carousel posts via the PostNitro.ai Embed API. Two workflows:
- AI Generation — provide a topic, article, or text and let AI create the carousel
- Content Import — provide your own slide content with full control, including infographics
Prerequisites
Set the following environment variables:
POSTNITRO_API_KEY— Obtained from PostNitro.ai account settings under "Embed".POSTNITRO_TEMPLATE_ID— ID of a carousel template from the user's PostNitro account.POSTNITRO_BRAND_ID— ID of a brand profile from the user's PostNitro account.POSTNITRO_PRESET_ID— (Required for AI generation) An AI preset ID from the user's PostNitro account.
If the user doesn't have these, direct them to https://postnitro.ai to sign up (free plan: 5 credits/month).
API Overview
Base URL: https://embed-api.postnitro.ai
Authentication: All requests require the header embed-api-key: $POSTNITRO_API_KEY.
Content-Type: application/json (for POST requests).
Async Workflow
All carousel creation is asynchronous:
- Initiate —
POST /post/initiate/generateorPOST /post/initiate/import→ returnsembedPostId - Poll Status —
GET /post/status/{embedPostId}→ poll untilstatusis"COMPLETED" - Get Output —
GET /post/output/{embedPostId}→ download the finished carousel
Endpoint 1: AI-Powered Generation
POST /post/initiate/generate
Use when the user provides a topic, article URL, or text and wants AI to generate carousel content.
Request Body
| Field | Type | Required | Description | Allowed Values |
|---|---|---|---|---|
postType |
string | Yes | Type of post | "CAROUSEL" |
requestorId |
string | No | Custom tracking identifier | Any string |
templateId |
string | Yes | Template ID | Valid template ID |
brandId |
string | Yes | Brand configuration ID | Valid brand ID |
presetId |
string | Yes | AI configuration preset ID | Valid preset ID |
responseType |
string | No | Output format (default: "PDF") |
"PDF", "PNG" |
aiGeneration |
object | Yes | AI generation config | See below |
aiGeneration Object
| Field | Type | Required | Description | Allowed Values |
|---|---|---|---|---|
type |
string | Yes | Type of AI generation | "text", "article", "x" |
context |
string | Yes | For "text": the text content. For "article": an article URL. For "x": an X post/thread URL. |
Any string |
instructions |
string | No | Additional style/tone instructions | Any string |
aiGeneration.type values:
"text"— Generate from user-provided text content"article"— Generate from an article URL (pass the URL ascontext)"x"— Generate from an X (Twitter) post or thread URL
Example (from text)
curl -X POST 'https://embed-api.postnitro.ai/post/initiate/generate' \
-H 'Content-Type: application/json' \
-H "embed-api-key: $POSTNITRO_API_KEY" \
-d '{
"postType": "CAROUSEL",
"requestorId": "user123",
"templateId": "'"$POSTNITRO_TEMPLATE_ID"'",
"brandId": "'"$POSTNITRO_BRAND_ID"'",
"presetId": "'"$POSTNITRO_PRESET_ID"'",
"responseType": "PNG",
"aiGeneration": {
"type": "text",
"context": "Digital marketing tips for small businesses: 1. Focus on local SEO 2. Use social proof 3. Start email marketing early",
"instructions": "Focus on actionable tips that can be implemented immediately"
}
}'
Example (from article URL)
curl -X POST 'https://embed-api.postnitro.ai/post/initiate/generate' \
-H 'Content-Type: application/json' \
-H "embed-api-key: $POSTNITRO_API_KEY" \
-d '{
"postType": "CAROUSEL",
"requestorId": "user123",
"templateId": "'"$POSTNITRO_TEMPLATE_ID"'",
"brandId": "'"$POSTNITRO_BRAND_ID"'",
"presetId": "'"$POSTNITRO_PRESET_ID"'",
"responseType": "PNG",
"aiGeneration": {
"type": "article",
"context": "https://example.com/blog/digital-marketing-tips",
"instructions": "Focus on actionable tips for small businesses"
}
}'
Response
{
"success": true,
"message": "CAROUSEL generation initiated",
"data": {
"embedPostId": "post123",
"status": "PENDING"
}
}
Credit cost: 2 credits per slide.
Endpoint 2: Content Import
POST /post/initiate/import
Use when the user provides their own slide content.
Request Body
| Field | Type | Required | Description | Allowed Values |
|---|---|---|---|---|
postType |
string | Yes | Type of post | "CAROUSEL" |
requestorId |
string | No | Custom tracking identifier | Any string |
templateId |
string | Yes | Template ID | Valid template ID |
brandId |
string | Yes | Brand configuration ID | Valid brand ID |
responseType |
string | No | Output format (default: "PDF") |
"PDF", "PNG" |
slides |
array | Yes | Array of slide objects | See below |
Slide Structure
| Field | Type | Required | Description | Allowed Values |
|---|---|---|---|---|
type |
string | Yes | Slide type | "starting_slide", "body_slide", "ending_slide" |
heading |
string | Yes | Main heading text | Any string |
sub_heading |
string | No | Subtitle text | Any string |
description |
string | No | Description text | Any string |
image |
string | No | Foreground image URL | Valid URL |
background_image |
string | No | Background image URL | Valid URL |
cta_button |
string | No | Call-to-action button text | Any string |
layoutType |
string | No | Slide layout type | "default", "infographics" |
layoutConfig |
object | No | Infographics configuration | See below |
Slide Rules
- Exactly 1
starting_slide(required) - At least 1
body_slide(required) - Exactly 1
ending_slide(required)
Infographics Layout
Set layoutType to "infographic" on a body_slide to replace the image area with structured data.
layoutConfig object:
| Field | Type | Required | Description | Allowed Values |
|---|---|---|---|---|
columnCount |
number | Yes | Number of columns | 1, 2, 3 |
columnDisplay |
string | Yes | Layout mode | "cycle", "grid" |
displayCounterAs |
string | Yes | Counter display | "none", "counter" |
hasHeader |
boolean | Yes | Show column headers | true, false |
columnData |
array | No | Column content | See below |
columnData items:
| Field | Type | Required | Description |
|---|---|---|---|
header |
string | Yes | Column header text |
content |
array | Yes | Array of {"title": "...", "description": "..."} objects |
Infographics notes:
layoutType: "infographic"replaces the slide image with the infographic- Column count must not exceed 3
- Cyclical display (
"cycle") only uses data from the first column - Grid display (
"grid") uses data from all columns
Example (Default Slides)
curl -X POST 'https://embed-api.postnitro.ai/post/initiate/import' \
-H 'Content-Type: application/json' \
-H "embed-api-key: $POSTNITRO_API_KEY" \
-d '{
"postType": "CAROUSEL",
"templateId": "'"$POSTNITRO_TEMPLATE_ID"'",
"brandId": "'"$POSTNITRO_BRAND_ID"'",
"responseType": "PNG",
"slides": [
{
"type": "starting_slide",
"sub_heading": "My Awesome Subtitle",
"heading": "Welcome to the Carousel!",
"description": "This is how you start with a bang.",
"cta_button": "Swipe to learn more"
},
{
"type": "body_slide",
"heading": "Section 1: The Core Idea",
"description": "Explain your first key point here."
},
{
"type": "body_slide",
"heading": "Section 2: Deeper Dive",
"description": "More details for the second point."
},
{
"type": "ending_slide",
"heading": "Get Started Today!",
"sub_heading": "Ready to Act?",
"description": "A final encouraging message.",
"cta_button": "Visit Our Website"
}
]
}'
Example (With Infographics)
curl -X POST 'https://embed-api.postnitro.ai/post/initiate/import' \
-H 'Content-Type: application/json' \
-H "embed-api-key: $POSTNITRO_API_KEY" \
-d '{
"postType": "CAROUSEL",
"templateId": "'"$POSTNITRO_TEMPLATE_ID"'",
"brandId": "'"$POSTNITRO_BRAND_ID"'",
"responseType": "PNG",
"slides": [
{
"type": "starting_slide",
"heading": "PostNitro Infographics",
"sub_heading": "Import API Feature",
"description": "Create stunning visual carousels with structured data."
},
{
"type": "body_slide",
"heading": "Grid Layout",
"description": "Display data in an organized grid format.",
"layoutType": "infographic",
"layoutConfig": {
"columnCount": 2,
"columnDisplay": "grid",
"displayCounterAs": "counter",
"hasHeader": true,
"columnData": [
{
"header": "Features",
"content": [
{"title": "Grid Display", "description": "Organized columns for comparison."},
{"title": "Counter Support", "description": "Numbered items for sequence."}
]
},
{
"header": "Options",
"content": [
{"title": "Column Headers", "description": "Enable/disable per column."},
{"title": "Flexible Columns", "description": "Choose 1, 2, or 3 columns."}
]
}
]
}
},
{
"type": "ending_slide",
"heading": "Try PostNitro Infographics",
"sub_heading": "Start Creating Today",
"cta_button": "Get Your API Key"
}
]
}'
Response
{
"success": true,
"message": "CAROUSEL generation initiated",
"data": {
"embedPostId": "post123",
"status": "PENDING"
}
}
Credit cost: 1 credit per slide.
Endpoint 3: Check Post Status
GET /post/status/{embedPostId}
No request body. Pass embedPostId as a path parameter.
Headers: embed-api-key: $POSTNITRO_API_KEY (required)
curl -X GET "https://embed-api.postnitro.ai/post/status/$EMBED_POST_ID" \
-H "embed-api-key: $POSTNITRO_API_KEY"
Response
{
"success": true,
"data": {
"embedPostId": "post123",
"embedPost": {
"id": "post123",
"postType": "CAROUSEL",
"status": "COMPLETED",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:35:00Z"
},
"logs": [
{
"id": "log1",
"embedPostId": "post123",
"step": "INITIATED",
"status": "SUCCESS",
"message": "Post generation initiated",
"timestamp": "2024-01-15T10:30:00Z"
},
{
"id": "log2",
"embedPostId": "post123",
"step": "PROCESSING",
"status": "SUCCESS",
"message": "Content generated successfully",
"timestamp": "2024-01-15T10:32:00Z"
},
{
"id": "log3",
"embedPostId": "post123",
"step": "COMPLETED",
"status": "SUCCESS",
"message": "Post generation completed",
"timestamp": "2024-01-15T10:35:00Z"
}
]
}
}
Poll every 3–5 seconds. Check data.embedPost.status for completion. The logs array provides step-by-step progress.
Endpoint 4: Get Output
GET /post/output/{embedPostId}
No request body. Pass embedPostId as a path parameter.
Headers: embed-api-key: $POSTNITRO_API_KEY (required)
curl -X GET "https://embed-api.postnitro.ai/post/output/$EMBED_POST_ID" \
-H "embed-api-key: $POSTNITRO_API_KEY"
Response (PNG)
{
"success": true,
"data": {
"embedPost": {
"id": "post123",
"postType": "CAROUSEL",
"responseType": "PNG",
"status": "COMPLETED",
"credits": 4,
"createdAt": "2026-02-19T21:11:50.115Z",
"updatedAt": "2026-02-19T21:12:08.333Z"
},
"result": {
"id": "result123",
"name": "Welcome to the Carousel!",
"size": {
"id": "4:5",
"dimensions": { "width": 1080, "height": 1350 }
},
"type": "png",
"mimeType": "image/png",
"data": [
"https://...supabase.co/.../slide_0.png",
"https://...supabase.co/.../slide_1.png"
]
}
}
}
Response (PDF)
{
"success": true,
"data": {
"embedPost": {
"id": "post123",
"postType": "CAROUSEL",
"responseType": "PDF",
"status": "COMPLETED",
"credits": 10,
"createdAt": "2026-02-19T21:11:50.115Z",
"updatedAt": "2026-02-19T21:12:08.333Z"
},
"result": {
"id": "result123",
"name": "Welcome to the Carousel!",
"size": {
"id": "4:5",
"dimensions": { "width": 1080, "height": 1350 }
},
"type": "pdf",
"mimeType": "application/pdf",
"data": "https://...supabase.co/.../output.pdf"
}
}
}
Result Object
| Field | Type | Description |
|---|---|---|
id |
string | Unique result identifier |
name |
string | Design name (from template or "Untitled") |
size |
object | { "id": "4:5", "dimensions": { "width": 1080, "height": 1350 } } |
type |
string | File type ("png" or "pdf") |
mimeType |
string | MIME type ("image/png" or "application/pdf") |
data |
string or array | PNG: Array of URLs (one per slide). PDF: Single URL. |
Download the URLs directly to save the carousel files.
Step-by-Step Usage
AI-Generated Carousel
- Confirm
POSTNITRO_API_KEY,POSTNITRO_TEMPLATE_ID,POSTNITRO_BRAND_ID, andPOSTNITRO_PRESET_IDare set. - Ask the user for their generation type (
text,article, orx), the corresponding content (text, article URL, or X post URL), and any style instructions. - Send the generate request to
POST /post/initiate/generate. - Extract
embedPostIdfrom the response. - Poll
GET /post/status/{embedPostId}every 3–5 seconds untilstatusis"COMPLETED". - Call
GET /post/output/{embedPostId}to get the result. Download the URL(s) fromdatato save files.
Custom Content Carousel
- Confirm
POSTNITRO_API_KEY,POSTNITRO_TEMPLATE_ID, andPOSTNITRO_BRAND_IDare set. - Gather slide content from the user. Structure as: 1
starting_slide→ 1+body_slide→ 1ending_slide. - For data-heavy slides, use
layoutType: "infographic"with alayoutConfigobject. - Send the import request to
POST /post/initiate/import. - Follow the same poll → output flow.
Content Strategy Tips
- LinkedIn: Professional tone, actionable insights, 6–10 slides, clear CTA.
- Instagram: Visual-first, concise text, 5–8 slides, storytelling arc.
- TikTok: Trendy, punchy, 4–7 slides, hook on slide 1.
- X (Twitter): Data-driven, 3–6 slides, provocative opening.
Error Handling
- If the API returns an authentication error, verify
POSTNITRO_API_KEYis correct and the account is active. - If credits are exhausted, inform the user. Free plan: 5 credits/month. Paid plan: 250+ credits/month ($10/month base).
- If the status poll indicates failure, retry the initiation once before reporting the error.
- All endpoints are rate-limited per API key — space requests appropriately.
- Default
responseTypeis"PDF". Always specify"PNG"explicitly if individual slide images are needed.
Links
- Documentation: https://postnitro.ai/docs/embed/api
- Get API Key: https://postnitro.ai/app/embed
- Postman Collection: https://www.postman.com/postnitro/postnitro-embed-apis/overview
- Support: support@postnitro.ai