Last Updated: 2026-03-15 Base Path:
/content/*(proxied via Gateway) Auth: RS256 JWT (via Gatewayx-user-id,x-tenant-id,x-user-permissionsheaders) ServiceCode:"content"— must be registered inpackages/core-types/src/service.tsbefore implementation
1. Social Connections
GET /content/connections
List all social connections for the current tenant.
Permissions: content:connections.read
Response 200:
{
"data": [
{
"id": "uuid",
"platform": "twitter",
"platformUsername": "@clientbrand",
"platformAccountId": "123456789",
"status": "active",
"tokenExpiresAt": "2026-04-13T00:00:00Z",
"connectedBy": "user-uuid",
"createdAt": "2026-03-01T00:00:00Z"
}
]
}POST /content/connections/:platform/authorize
Initiate OAuth flow for a social platform. Returns the OAuth authorization URL.
Permissions: content:connections.write
Request Body:
{
"callbackUrl": "https://dashboard.logicspike.com/content/callback"
}Response 200:
{
"authorizationUrl": "https://twitter.com/i/oauth2/authorize?client_id=...&state=...",
"state": "random-csrf-token"
}POST /content/connections/:platform/callback
Complete the OAuth flow after user authorization.
Permissions: content:connections.write
Request Body:
{
"code": "oauth-authorization-code",
"state": "random-csrf-token"
}Response 201:
{
"connection": {
"id": "uuid",
"platform": "twitter",
"platformUsername": "@clientbrand",
"status": "active"
}
}DELETE /content/connections/:connectionId
Disconnect a social account. Revokes the OAuth token on the platform side.
Permissions: content:connections.write
Response 204: No content.
2. Campaigns
GET /content/campaigns
List campaigns for the current tenant.
Permissions: content:campaigns.read
Query Params: ?status=active&page=1&limit=20
Response 200:
{
"data": [
{
"id": "uuid",
"name": "Q1 Product Launch",
"color": "#FF6B35",
"startDate": "2026-03-01",
"endDate": "2026-03-31",
"status": "active",
"slotCount": 12
}
],
"meta": { "page": 1, "limit": 20, "total": 3, "totalPages": 1 }
}POST /content/campaigns
Create a new campaign.
Permissions: content:campaigns.write
Request Body:
{
"name": "Q1 Product Launch",
"description": "All content related to the March product launch",
"color": "#FF6B35",
"startDate": "2026-03-01",
"endDate": "2026-03-31"
}Response 201: Created campaign object.
GET /content/campaigns/:campaignId
Get details of a specific campaign including slot count.
Permissions: content:campaigns.read
Response 200: Single campaign object.
PATCH /content/campaigns/:campaignId
Update a campaign.
Permissions: content:campaigns.write
Request Body (partial update):
{
"name": "Q1 Product Launch — Extended",
"endDate": "2026-04-15"
}Response 200: Updated campaign object.
DELETE /content/campaigns/:campaignId
Archive a campaign (soft delete).
Permissions: content:campaigns.write
Response 204: No content.
3. Labels
GET /content/labels
List all labels for the tenant.
Permissions: content:labels.read
POST /content/labels
Create a label.
Permissions: content:labels.write
Request Body:
{
"name": "ProductUpdate",
"color": "#4ECDC4"
}DELETE /content/labels/:labelId
Delete a label (removes from all slots).
Permissions: content:labels.write
PATCH /content/labels/:labelId
Update a label.
Permissions: content:labels.write
Request Body:
{ "name": "ProductLaunch", "color": "#FF6B35" }4. Content Slots (Core)
GET /content/slots
Query content slots — the primary calendar data endpoint.
Permissions: content:slots.read
Query Params:
| Param | Type | Description |
|---|---|---|
from |
ISO DateTime | Start of date range (required) |
to |
ISO DateTime | End of date range (required) |
status |
String | Filter by status (optional) |
campaignId |
UUID | Filter by campaign (optional) |
connectionId |
UUID | Filter by social account (optional) |
labelId |
UUID | Filter by label (optional) |
Response 200:
{
"data": [
{
"id": "uuid",
"caption": "🚀 Our latest product update...",
"mediaIds": ["media-uuid-1"],
"scheduledAt": "2026-03-14T09:00:00Z",
"timezone": "Asia/Kolkata",
"status": "scheduled",
"campaign": { "id": "uuid", "name": "Q1 Launch", "color": "#FF6B35" },
"labels": [{ "id": "uuid", "name": "ProductUpdate", "color": "#4ECDC4" }],
"targets": [
{
"id": "uuid",
"connectionId": "uuid",
"platform": "twitter",
"platformUsername": "@clientbrand",
"publishStatus": "pending",
"platformCaption": null
},
{
"id": "uuid",
"connectionId": "uuid",
"platform": "linkedin",
"platformUsername": "Client Brand",
"publishStatus": "pending",
"platformCaption": "Extended version for LinkedIn..."
}
],
"createdBy": "user-uuid",
"createdAt": "2026-03-13T10:30:00Z"
}
]
}POST /content/slots
Create a new content slot.
Permissions: content:slots.write
Request Body:
{
"caption": "🚀 Our latest product update is here!",
"contentType": "image",
"mediaIds": ["media-uuid-1"],
"scheduledAt": "2026-03-14T09:00:00Z",
"timezone": "Asia/Kolkata",
"campaignId": "campaign-uuid",
"labelIds": ["label-uuid-1"],
"targets": [
{ "connectionId": "twitter-connection-uuid" },
{ "connectionId": "linkedin-connection-uuid", "platformCaption": "Extended for LinkedIn..." }
]
}Validations:
scheduledAtmust be in the future- At least 1 target required
- All referenced
connectionIds must beactive contentTypemust be one of:text,image,video,carousel,story,link- Caption validated per platform rules:
- Twitter/X: max 280 characters
- LinkedIn: max 3,000 characters
- Instagram: max 2,200 characters, media required
- Facebook: max 63,206 characters
Response 201: Created slot with full targets array.
PATCH /content/slots/:slotId
Update a content slot (only allowed in draft or pending_review status).
Permissions: content:slots.write
Request Body (partial update):
{
"caption": "Updated caption text",
"mediaIds": ["new-media-uuid"],
"targets": [
{ "connectionId": "twitter-connection-uuid" },
{ "connectionId": "instagram-connection-uuid" }
]
}Response 200: Updated slot with full targets array.
DELETE /content/slots/:slotId
Delete a content slot (only allowed in draft or scheduled status).
Permissions: content:slots.write
POST /content/slots/:slotId/submit-review
Submit a slot for review — transitions draft → pending_review.
Permissions: content:slots.write
POST /content/slots/:slotId/approve
Approve a slot — transitions pending_review → approved → scheduled.
Permissions: content:slots.approve
Request Body (optional):
{ "note": "Looks great, approved!" }POST /content/slots/:slotId/reject
Reject a slot — transitions pending_review → draft.
Permissions: content:slots.approve
Request Body:
{ "note": "Caption is too long for Twitter. Please shorten." }POST /content/slots/:slotId/reschedule
Change the scheduled time of a slot (drag-and-drop support).
Permissions: content:slots.write
Request Body:
{
"scheduledAt": "2026-03-15T14:00:00Z"
}GET /content/slots/:slotId
Get full details of a specific content slot including targets and publish status.
Permissions: content:slots.read
Response 200: Full slot object with targets, labels, campaign, and publish logs.
POST /content/slots/bulk
Create multiple content slots at once (used by dashboard and MCP agents).
Permissions: content:slots.write
Request Body:
{
"slots": [
{
"caption": "Post 1",
"contentType": "text",
"scheduledAt": "2026-03-14T09:00:00Z",
"timezone": "Asia/Kolkata",
"targets": [{ "connectionId": "twitter-uuid" }]
},
{
"caption": "Post 2",
"contentType": "image",
"mediaIds": ["media-uuid"],
"scheduledAt": "2026-03-15T09:00:00Z",
"timezone": "Asia/Kolkata",
"targets": [{ "connectionId": "linkedin-uuid" }]
}
],
"campaignId": "campaign-uuid"
}Max: 50 slots per request.
Response 201: Array of created slot objects.
5. Recurring Schedules
GET /content/recurring
List recurring schedules.
Permissions: content:recurring.read
POST /content/recurring
Create a recurring content pattern.
Permissions: content:recurring.write
Request Body:
{
"name": "Motivation Monday",
"cronExpression": "0 10 * * 1",
"timezone": "Asia/Kolkata",
"templateCaption": "💡 Motivation Monday: Start your week strong!",
"templateMediaIds": [],
"targetConnectionIds": ["instagram-uuid", "linkedin-uuid"],
"autoSchedule": true
}PATCH /content/recurring/:scheduleId
Update a recurring schedule.
Permissions: content:recurring.write
POST /content/recurring/:scheduleId/pause
Pause slot generation (does not cancel existing slots).
Permissions: content:recurring.write
POST /content/recurring/:scheduleId/resume
Resume a paused schedule.
Permissions: content:recurring.write
DELETE /content/recurring/:scheduleId
Delete a recurring schedule.
Permissions: content:recurring.write
6. Publish Logs
GET /content/slots/:slotId/logs
View the publish audit trail for a specific slot.
Permissions: content:slots.read
Response 200:
{
"data": [
{
"id": "uuid",
"slotTargetId": "target-uuid",
"action": "publish_attempt",
"platform": "twitter",
"createdAt": "2026-03-14T09:00:01Z"
},
{
"id": "uuid",
"slotTargetId": "target-uuid",
"action": "publish_success",
"platform": "twitter",
"externalPostUrl": "https://twitter.com/clientbrand/status/123...",
"createdAt": "2026-03-14T09:00:03Z"
}
]
}7. Error Codes
| Code | HTTP | Description |
|---|---|---|
SLOT_NOT_FOUND |
404 | Content slot doesn't exist |
INVALID_STATUS_TRANSITION |
409 | e.g., trying to approve a draft slot |
CONNECTION_EXPIRED |
422 | Target social connection token is expired |
CONNECTION_NOT_FOUND |
404 | Referenced connection doesn't exist |
SCHEDULE_PAST_TIME |
422 | scheduledAt is in the past |
PLATFORM_VALIDATION_FAILED |
422 | Caption exceeds platform limits |
CAMPAIGN_NOT_FOUND |
404 | Referenced campaign doesn't exist |
INSUFFICIENT_PERMISSIONS |
403 | Missing required PBAC permission |
PUBLISH_LIMIT_REACHED |
429 | Tenant has hit their plan's slot limit |
PARTIALLY_FAILED |
207 | Some SlotTargets succeeded but others failed |
BULK_LIMIT_EXCEEDED |
422 | Too many items in a bulk operation (max 50) |
INVALID_CONTENT_TYPE |
422 | contentType is not valid for the target platform |
MEDIA_REQUIRED |
422 | Platform requires media attachment (e.g., Instagram) |
8. Permissions Map
| Permission String | Grants |
|---|---|
content:connections.read |
View connected social accounts |
content:connections.write |
Connect/disconnect social accounts |
content:campaigns.read |
View campaigns |
content:campaigns.write |
Create/edit/archive campaigns |
content:labels.read |
View labels |
content:labels.write |
Create/delete labels |
content:slots.read |
View content slots and calendar |
content:slots.write |
Create/edit/delete/schedule content slots |
content:slots.approve |
Approve/reject content in review |
content:recurring.read |
View recurring schedules |
content:recurring.write |
Create/edit/delete recurring schedules |