A content slot is the core unit of the Content Engine — it's a piece of content tied to one or more platform accounts and a scheduled time.
Basic structure
| Field | Required | Description |
|---|---|---|
caption |
Yes | The post text |
contentType |
Yes | text, image, link (video not yet supported) |
scheduledAt |
Yes | ISO 8601 datetime in UTC when the post should fire |
timezone |
Yes | IANA timezone name (e.g., Asia/Kolkata) — for display in the calendar |
targets |
Yes | Array of at least one { connectionId, platformCaption? } |
mediaIds |
No | Array of media IDs from the Media Service |
mediaAltText |
No | Object mapping mediaId → alt text string (required for Twitter accessibility) |
campaignId |
No | Associate this slot with a campaign |
labelIds |
No | Array of label IDs to tag this slot |
status |
No | draft (default) or scheduled (skips the approval step) |
Platform captions
Each target can have its own caption override via platformCaption. If not provided, all platforms use the slot's main caption.
{
"caption": "Check out our new feature — link in bio!",
"targets": [
{
"connectionId": "conn_twitter_01",
"platformCaption": "Check out our new feature! 🚀 https://vlozi.app/features/new"
},
{
"connectionId": "conn_instagram_01"
}
]
}In this example, Twitter uses the custom caption (with link and emoji); Instagram uses the main caption.
Scheduling time
scheduledAt must be a future timestamp. The engine validates this at create time.
The timezone field is used for calendar display only — it does not affect when the post fires. Publishing always uses the UTC scheduledAt time.
Creating via the dashboard
Content Engine → Calendar → + New post
Select your platform accounts, write your caption, attach media, pick a time, then choose Save as draft or Schedule directly.
Creating via the API
POST /content/slots
Authorization: Bearer <token>
Content-Type: application/json
{
"caption": "Exciting news — our API is live!",
"contentType": "text",
"scheduledAt": "2026-07-15T09:00:00Z",
"timezone": "Asia/Kolkata",
"targets": [
{ "connectionId": "conn_twitter_abc123" },
{ "connectionId": "conn_linkedin_xyz789" }
],
"status": "scheduled"
}Response:
{
"slotId": "slot_01j...",
"status": "scheduled",
"scheduledAt": "2026-07-15T09:00:00Z",
"targets": [
{ "targetId": "tgt_01j...", "connectionId": "conn_twitter_abc123", "publishStatus": "pending" },
{ "targetId": "tgt_01j...", "connectionId": "conn_linkedin_xyz789", "publishStatus": "pending" }
]
}Attaching media
Media must first be uploaded to the Vlozi Media Service. The Content Engine does not accept raw file uploads directly.
- Upload your image via the Media Service and receive a
mediaId - Pass the
mediaIdin themediaIdsarray when creating the slot - Optionally set alt text via
mediaAltText: { "<mediaId>": "Description of the image" }
At publish time, the engine resolves the actual media URL from the Media Service and uploads it to the platform.
Twitter: Accepts up to 4 images per tweet. Alt text is set via Twitter's media metadata API.
LinkedIn / Facebook / Instagram: Accepts images; video not yet supported.
Slot states
A slot moves through a state machine from creation to publication:
draft ──► pending_review ──[approve]──► approved ──► scheduled ──► publishing ──► published
│
└──[reject]──► draft
│
└──[fail]──► failed| State | Meaning |
|---|---|
draft |
Created but not yet submitted for review or scheduled |
pending_review |
Submitted for approval, waiting on a reviewer |
approved |
Approved; auto-transitions to scheduled |
scheduled |
Durable Object alarm armed at scheduledAt |
publishing |
Alarm fired; currently being processed by the queue |
published |
All targets published successfully |
failed |
All targets failed after retries |
You can skip the approval step entirely by creating a slot with status: "scheduled" directly. This requires the content:slots.write permission.
Editing and rescheduling
You can edit a slot only when it is in draft or failed status. Scheduled slots must be rescheduled via the dedicated endpoint — this updates scheduledAt and re-arms the Durable Object alarm.
POST /content/slots/:slotId/reschedule
Content-Type: application/json
{ "scheduledAt": "2026-07-16T09:00:00Z" }Deleting a slot
Only draft and scheduled slots can be deleted. Deleting a scheduled slot cancels its Durable Object alarm before the row is removed. Published slots are permanent (but can be individually deleted on the platform side).