Social Posting
Connect social accounts, manage settings, and publish or schedule posts with the Swiftia API
Social Posting
Use these endpoints to connect social accounts to an organization, read and update social settings, list posts, and create, edit, or remove posts. All routes are under /api/organizations/social-posts. A plan with social posting enabled is required, and the organization’s social feature must be allowed when the API enforces it.
Overview
- Settings: Default platforms, time zone, queue rules, and related limits.
- Profile & connect: See which accounts are linked, start OAuth with
connect, or disconnect byaccountId. - Queue: Read the next available slot times for scheduled posting.
- Posts: List existing posts; publish creates a new post; edit and remove update or cancel by
postIdor providerjobId.
Note: When you authenticate with an API key, the key is bound to an organization, so you can omit organizationId in the query and body. If the organization cannot be determined, the API returns 400 with {"error":"organizationId is required when not using API key"}. For all other Authentication methods, include organizationId in query or body when calling these endpoints, unless the authentication guide for your method says otherwise.
Headers (typical):
Authorization: Bearer YOUR_API_KEYFor POST and PUT requests, also send:
Content-Type: application/jsonRequest format and error handling are covered in Authentication and Error handling. API key calls are subject to Rate limiting.
Endpoints
Get social settings
Get current social settings for the organization (defaults, queue, limits, feature flags).
Endpoint: GET /api/organizations/social-posts/settings
Query parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.
Response:
{
"isEnabled": true,
"approveApiPosts": false,
"defaultTimezone": "America/New_York",
"defaultPlatforms": ["youtube", "facebook"],
"queueSlots": [
{ "dayOfWeek": 1, "time": "10:00" }
],
"maxPostsPerSlot": 1,
"maxShortsOfSameVideo": 0,
"maxShortsPerWeek": 0,
"minimumVideoDurationSeconds": 0,
"processOnlyPlaylistId": null
}dayOfWeek is 0 (Sunday) through 6 (Saturday). time is HH:mm (24h). If no settings row exists yet, the API returns a default-shaped object with the same fields.
Update social settings
Update social settings. All body fields are optional; send only what you want to change.
Endpoint: PUT /api/organizations/social-posts/settings
Request body (with API key — organizationId optional):
{
"isEnabled": true,
"approveApiPosts": true,
"defaultTimezone": "America/New_York",
"defaultPlatforms": ["youtube", "facebook"],
"queueSlots": [
{ "dayOfWeek": 1, "time": "10:00" }
],
"maxPostsPerSlot": 1,
"maxShortsOfSameVideo": 0,
"maxShortsPerWeek": 10,
"minimumVideoDurationSeconds": 30,
"processOnlyPlaylistId": null
}Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.isEnabled(boolean, optional): Whether social posting is enabled for the organization.approveApiPosts(boolean, optional): Whether API-created posts require approval.defaultTimezone(string, optional): IANA time zone.defaultPlatforms(array of strings, optional): Default destination networks (e.g.youtube,facebook,instagram,linkedin,tiktok,x).queueSlots(array, optional): Each item hasdayOfWeek(0–6) andtime(HH:mm).maxPostsPerSlot(number, optional): Max posts per queue slot (1–100).maxShortsOfSameVideo(number, optional).maxShortsPerWeek(number, optional).minimumVideoDurationSeconds(number, optional).processOnlyPlaylistId(string or null, optional).
Response: Same shape as Get social settings (updated document).
Get connection profile
Returns whether a social profile is connected, the provider profile id, and linked accounts.
Endpoint: GET /api/organizations/social-posts/profile
Query parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.
Response (disconnected):
{
"connected": false,
"profileId": null,
"connectedAccounts": [],
"accountLinks": []
}Response (with connections):
{
"connected": true,
"profileId": "profile_id",
"connectedAccounts": ["facebook", "youtube"],
"accountLinks": [
{ "accountId": "acc_1", "platform": "facebook" }
]
}Connect a social account (OAuth)
Start linking a platform. The response includes a URL to open in the user’s browser.
Endpoint: POST /api/organizations/social-posts/connect
Request body (with API key — organizationId optional):
{
"platform": "facebook",
"redirectUrl": "https://your-app.com/social-callback"
}Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.platform(string, required): Network to connect (e.g.youtube,tiktok,instagram,facebook,linkedin,x).redirectUrl(string, optional): OAuth redirect URL.
Response:
{
"access_url": "https://...",
"platform": "facebook",
"profileId": "profile_id"
}Disconnect a social account
Unlink a connected account using the accountId from accountLinks on the profile response.
Endpoint: POST /api/organizations/social-posts/disconnect-account
Request body:
{
"accountId": "acc_1"
}Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.accountId(string, required): Account id to disconnect.
Response:
{ "ok": true }Get next queue slots
Returns the resolved time zone and the next one or more slot timestamps (ISO 8601 strings) according to the organization’s queue settings.
Endpoint: GET /api/organizations/social-posts/next-slot
Query parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.timezone(string, optional): IANA time zone; falls back to organization default when omitted.
Response:
{
"timezone": "America/New_York",
"nextSlot": "2026-05-01T14:00:00.000Z",
"nextSlots": [
"2026-05-01T14:00:00.000Z",
"2026-05-02T14:00:00.000Z"
]
}List social posts
Returns the organization’s posts, most recent first.
Endpoint: GET /api/organizations/social-posts/posts
Query parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.
Response:
{
"posts": [
{
"id": "post_id",
"status": "scheduled",
"title": null,
"caption": "Hello",
"platforms": ["facebook"],
"createdAt": "2026-04-27T12:00:00.000Z",
"scheduledFor": "2026-05-01T15:00:00.000Z",
"providerJobId": "job_id",
"previewUrl": "https://...",
"thumbnailUrl": "https://...",
"providerError": null,
"providerPlatforms": [],
"providerLastEvent": null,
"isPublishedOnPlatform": false
}
]
}Response fields (per post):
id(string): Internal post id.status(string): Post status in the app.title(string | null): Optional title.caption(string): Caption text.platforms(array of strings): Target networks.createdAt(string | null): ISO 8601.scheduledFor(string | null): ISO 8601 when scheduled.providerJobId(string | null): Provider job id, if any.previewUrl/thumbnailUrl(string | null): Media preview helpers.providerError(string | null): Last error message, if any.providerPlatforms(array): Provider-reported platform details when present.providerLastEvent(string | null): Last provider event name, if any.isPublishedOnPlatform(boolean): Whether the post is treated as live on a platform for display purposes.
Publish a post
Create and submit a post (draft, immediately, on a schedule, in the next queue slot, or using defaults for platforms when omitted).
Endpoint: POST /api/organizations/social-posts/publish
Request body (with API key — organizationId optional, example):
{
"postType": "video",
"caption": "Check this out",
"videoUrl": "https://cdn.example.com/clip.mp4",
"platforms": ["youtube", "facebook"],
"publishMode": "publish_now",
"timezone": "America/New_York"
}Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.postType(string, required):video|photo|text|document. Forvideoyou must setvideoUrl. Forphotoyou must setphotoUrls(at least one URL, max 20). Fordocumentyou must setdocumentUrl. Fortextyou must set a non-emptycaption.caption(string, required): Post caption (and main text for text posts).platforms(array of strings, optional): If omitted, organization default platforms may be used. Values must be supported network keys.publishMode(string, optional):draft|publish_now|schedule|next_slot. Fordraftandschedule,scheduledAtis required (non-empty string) per server validation.scheduledAt(string, optional): When scheduling or saving as draft (format per API validation).timezone(string, optional): IANA time zone for scheduling.videoUrl(string, optional): HTTPS URL; required forpostType: "video".photoUrls(array of strings, optional): Image URLs; required forpostType: "photo".documentUrl(string, optional): Required forpostType: "document".platformFields(object, optional): String key/value map of per-network options. All values are strings (including booleans encoded as"true"/"false"where applicable). See Platform fields for accepted keys.
Response:
{
"socialPost": {
"id": "post_id",
"status": "scheduled",
"providerJobId": "job_id",
"scheduledFor": "2026-05-01T15:00:00.000Z"
},
"providerPostId": "job_id"
}Error responses (non-exhaustive): 400 validation, 403 when the feature or plan disallows the action, 502 when submission to the provider fails.
Platform fields
Optional platformFields keys (each value is a string):
- YouTube:
youtubeTitle,youtubeVisibility,youtubeMadeForKids,youtubeContainsSyntheticMedia,youtubeCategoryId,youtubePlaylistId,youtubeFirstComment - Instagram:
instagramContentType,instagramShareToFeed,instagramCollaborators,instagramUserTags,instagramTrialGraduationStrategy,instagramThumbOffset,instagramThumbnail,instagramAudioName,instagramFirstComment - Facebook:
facebookDraft,facebookContentType,facebookTitle,facebookFirstComment,facebookPageId,facebookGeoCountries - LinkedIn:
linkedinDocumentTitle,linkedinOrganizationUrn,linkedinFirstComment,linkedinDisableLinkPreview,linkedinGeoCountries - X (Twitter):
xReplyToTweetId,xReplySettings,xThreadItems,xPollOptions,xPollDurationMinutes,xLongVideo,xGeoCountries - TikTok:
tiktokPrivacyLevel,tiktokAllowComment,tiktokAllowDuet,tiktokAllowStitch,tiktokContentPreviewConfirmed,tiktokExpressConsentGiven,tiktokVideoCoverTimestampMs,tiktokVideoCoverImageUrl,tiktokMediaType,tiktokPhotoCoverIndex,tiktokDescription,tiktokAutoAddMusic,tiktokVideoMadeWithAi,tiktokDraft,tiktokCommercialContentType
Invalid or inconsistent combinations for the selected postType and platforms can return 400.
Edit a post
Update scheduling or draft state, or caption (caption updates may be limited to certain networks).
Endpoint: POST /api/organizations/social-posts/edit
Request body (with API key — organizationId optional):
{
"postId": "post_id",
"mode": "schedule",
"scheduledAt": "2026-05-01T15:00:00.000Z"
}Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.postId(string, optional): Internal id (one ofpostIdorjobIdis required).jobId(string, optional): Provider job id (alias for lookup).mode(string, optional):draftorschedule. Whenschedule,scheduledAtis required.scheduledAt(string, optional): ISO 8601 datetime when usingmode: "schedule".caption(string, optional): New caption (supported only for some platforms).
Response:
{
"post": {
"id": "post_id",
"status": "scheduled",
"scheduledFor": "2026-05-01T15:00:00.000Z"
}
}Remove a post
Cancels a scheduled post with the provider when applicable and updates local status.
Endpoint: POST /api/organizations/social-posts/remove
Request body:
{ "postId": "post_id" }or
{ "jobId": "job_id" }Request parameters:
organizationId(string, optional with API key, otherwise required per Authentication): Target organization. Omit when using an API key.postId(string, optional): Internal id.jobId(string, optional): Provider job id. One ofpostIdorjobIdis required.
Response:
{
"post": {
"id": "post_id",
"status": "cancelled",
"scheduledFor": null
}
}Example: publish with an API key
curl --request POST \
--url https://app.swiftia.io/api/organizations/social-posts/publish \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"postType": "text",
"caption": "Hello from the API",
"platforms": ["facebook"],
"publishMode": "publish_now"
}'Example: publish with organizationId in the body
Use this shape when your credentials do not imply an organization and you must pass organizationId (see Authentication):
curl --request POST \
--url "https://app.swiftia.io/api/organizations/social-posts/publish" \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"organizationId": "YOUR_ORG_ID",
"postType": "text",
"caption": "Hello from the API",
"platforms": ["facebook"],
"publishMode": "publish_now"
}'