Skip to content

Publishing a video

The quickstart ran the whole loop in one pass. This page is the model underneath it: assets, publications, targets, and the states they travel.

Connections come first

You can only publish to a destination you've connected. A connection is a platform account you've authorized socialized.dev to publish to: a YouTube channel, an Instagram account, a Facebook page. A brand holds at most one connection per platform.

Connecting uses OAuth, so it happens in a browser, which is a dashboard step. Connection management, including listing active connections or removing them, is done exclusively in the dashboard and is not available via API keys.

Assets: upload once

The source video is an asset, stored once. Assets are account-scoped, meaning a video uploaded once can be published under any brand in the account.

NOTE

If you are using the socialized.dev CLI (socialized.dev publications create), the CLI automatically handles the multipart asset upload ceremony internally for local file paths, making it a single step.

For direct API integrations, uploads are presigned and multipart: you upload each part directly to a URL the API returns:

  1. POST /assets with filename, contentType, and sizeBytes: returns a plan with one presigned PUT URL per part (parts are 10 MiB).
  2. PUT each part directly to its URL; keep each ETag. Part URLs are signed for host only, so no extra headers are required — a plain PUT with a normal Content-Length (no chunked transfer encoding) is enough. A Content-Type on a part is ignored: the asset's type is the contentType from step 1.
  3. POST /assets/{uploadId}/complete with the { partNumber, etag }[] (ETags may be quoted or unquoted). The asset is recorded and becomes ready.

A cover is uploaded as its own image asset (POST /assets with an image contentType) and referenced by the publication via coverAssetId. Keep it under 2 MB — YouTube's thumbnail API refuses anything larger, and a YouTube target with an over-2MB cover fails validation at publish time rather than posting without its thumbnail. A JPEG at 1080p is typically well under the cap.

An asset only ever reaches ready: there is no half-uploaded state to publish by accident.

Upload, then publish within 48 hours. An asset that isn't attached to a publication — as the video or the cover — within 48 hours of upload is reclaimed automatically: both the stored file and its record are deleted. The clock runs from when you upload, not from last use, so finish the publish inside that window. Once an asset is attached to a publication it persists.

Publications & targets

A publication is one "post once": a title, a description, an optional cover, and a list of targets. Each target is one destination.

sh
curl -s -X POST "$API/brands/$BRAND/publications" \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "videoAssetId": "asset_video_…",
    "coverAssetId": "asset_cover_…",
    "title": "Launch clip",
    "description": "…",
    "targets": [
      { "platform": "youtube" },
      { "platform": "instagram" }
    ]
  }'

Each target carries a per-platform options object (it defaults to {}). Up to 10 targets per call. An override wins over the publication's base title / description; an absent field falls back to the base.

YouTube options:

FieldTypeLimit / valuesDefaultFallback when absent
titlestring1–100 charsbase title
descriptionstringmax 5000 charsbase description
tagsstring[]500 chars total (the joining commas count)none sent
categoryIdstringnone sent
privacyStatusenumpublic | unlisted | privatepublic
madeForKidsbooleanfalse

Instagram options:

FieldTypeLimitFallback when absent
captionstringmax 2200 charsbase description, then base title if it is empty

Facebook options:

FieldTypeLimitFallback when absent
titlestring1–250 charsbase title
descriptionstringmax 4000 charsbase description, then base title if it is empty
format'auto' | 'reel' | 'video''auto'

Reels vs Page videos. Facebook has two publish surfaces. Reels go through /{page-id}/video_reels and must sit in the 3–180s window (Meta raised the old 90s cap to ~3 min mid-2025). Normal Page videos go through /{page-id}/videos, which accepts much longer clips (~4 GB / ~240 min by third-party consensus; the authoritative per-Page answer is GET /{page-id}?fields=video_upload_limits). With format: 'auto' (the default), a clip that fits the Reels window is published as a Reel; everything else — including an unknown duration — lands as a Page video, so a long clip is never rejected when a safe endpoint exists. Explicit reel fails validation outside that window. v1's /videos path is hosted-URL only (file_url body param); there is no byte-push fallback.

TikTok has no connector yet, so its options stay a free-form bag.

The API validates the effective message (the override, or the base it falls back to) against each platform's limits. A field that overflows fails the request with a 422 platform_message_too_long error carrying { platform, field, limit } — this catches a base message too long for a platform even when no override is set (for example a 150-character base title fanned out to YouTube's 100-character cap).

The API validates before it accepts: the video and cover assets must be ready. You do not specify a connection ID; the server automatically resolves the brand's single active connection for each platform. If a platform has no active connection, the request fails with a 422 platform_not_connected error. If you specify the same platform twice in one call, the request fails with a 422 duplicate_platform error.

The lifecycle

Once accepted, the publication runs on its own: each target is sent, transient failures are retried, and every target settles to a final state you can read back. Each target travels:

Target statusMeaning
pendingaccepted, waiting to send
processingbeing sent to the platform
publishedlive; externalUrl is the post
failedthe platform rejected it; error says why
deletedthe live post was deleted on its platform through the API (see below)

The publication aggregates its targets:

Publication statusMeaning
queuedaccepted, nothing sent yet
publishingat least one target is in flight
doneevery target published
partialsome published, some failed
failedevery target failed

Read it back with GET /brands/{brandId}/publications/{id} (the full record, with every target), or list the brand's publications with GET /brands/{brandId}/publications. Or skip polling entirely and subscribe to a webhook.

Add destinations, retry failures

A publication is not frozen once sent:

  • PATCH /brands/{brandId}/publications/{id}: edit the publication details (such as title, description, coverAssetId, or scheduledAt) and optionally add new targets. Already-live posts are left untouched.
  • POST /brands/{brandId}/publications/{id}/targets: an append-only endpoint to send the video to more destinations without editing the message. Already-live posts are left untouched.
  • POST /brands/{brandId}/publications/{id}/targets/{targetId}/retry: re-queue a failed target. Only failed targets are retryable: any other status returns a 409 conflict.

Writes to a removed publication (see below) return 409 publication_removed — a removed record is readable but frozen.

Deleting

Deletion is two separate operations — one for your records, one for the live posts — because platform support is uneven:

  • DELETE /brands/{brandId}/publications/{id} removes the publication from socialized.dev only: it leaves your list (reads by id keep working, with archivedAt set), and every post already live on a platform stays live. Returns 409 publication_in_flight while targets are still publishing.
  • DELETE /brands/{brandId}/publications/{id}/targets/{targetId}/post deletes the target's live post on its platform. Supported for YouTube and Facebook; Instagram's API cannot delete a published reel (422 platform_delete_unsupported). The target settles to deleted (external ids are kept for your records), a publication.target.deletedwebhook fires, and the call is idempotent — deleting an already-deleted target, or a post that was already removed on the platform, succeeds.

The API is the product; the dashboard is its best-known client.