Skip to content

Quickstart

You can publish videos using either the socialized.dev CLI (recommended) or direct REST API requests.

The @socialized.dev/cli wraps the multipart upload ceremony and publication dispatch into simple commands.

1. Install and Authenticate

Install the CLI globally and authenticate with your API key from dash.socialized.dev:

sh
npm install -g @socialized.dev/cli

# Log in using your API key
socialized.dev login --key sk_your_api_key

2. Select a Brand

If you have multiple brands, list and set the active brand:

sh
# List available brands
socialized.dev brands list

# Select a brand to use as the default
socialized.dev brands use brand_...

3. Publish

Publish a local video file to one or more platforms (e.g. YouTube and Instagram). The CLI automatically handles the multipart asset upload internally, dispatches the publication, and optionally watches the status until it resolves:

sh
socialized.dev publications create \
  --video ./my-clip.mp4 \
  --cover ./my-cover.jpg \
  --to youtube,instagram \
  --title "My First Dispatch" \
  --description "Posted once, everywhere." \
  --watch

REST API Quickstart (curl)

Publish a video to a connected destination, end to end. Everything here is plain HTTP against https://api.socialized.dev. Set your credentials and retrieve your brand ID:

sh
export SK="sk_your_api_key"          # from dash.socialized.dev → Developer
export API="https://api.socialized.dev/api/v1"

# List your brands and pick one (the id looks like brand_…)
curl -s "$API/brands" -H "Authorization: Bearer $SK"
export BRAND="brand_…"

Every call authenticates with Authorization: Bearer $SK. Brand-scoped resources (like publications) are nested under /brands/$BRAND, while account-scoped resources (like assets) are top-level under /assets.

1. Connect an account (one time, in the dashboard)

Connecting an account uses OAuth, so it happens in a browser, not over curl: open dash.socialized.dev, and connect a YouTube, Instagram, or Facebook account. You no longer need a connection ID to publish: you publish directly by platform name.

2. Start an upload

Tell the API about the file; it returns a presigned plan: one PUT URL per part (one part for a small clip) plus the assetId of the video asset.

sh
curl -s -X POST "$API/assets" \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{ "filename": "clip.mp4", "contentType": "video/mp4", "sizeBytes": 5242880 }' | jq
json
{
  "uploadId": "…",
  "assetId": "asset_video_…",
  "partSize": 10485760,
  "parts": [{ "partNumber": 1, "url": "https://…upload-url…/clip.mp4?partNumber=1&…" }]
}

To set a custom cover, upload an image as its own asset first. Send a POST to $API/assets with an image contentType (e.g. image/jpeg). The API returns a presigned PUT URL to upload the cover to. (You do not host it yourself.)

sh
curl -s -X POST "$API/assets" \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{ "filename": "cover.jpg", "contentType": "image/jpeg", "sizeBytes": 204800 }' | jq
json
{
  "uploadId": "…",
  "assetId": "asset_cover_…",
  "partSize": 10485760,
  "parts": [{ "partNumber": 1, "url": "https://…upload-url…/cover.jpg?partNumber=1&…" }]
}

Upload the cover bytes and complete the cover upload the same way as the video. This gives you a coverAssetId to use when publishing.

3. Upload the bytes

PUT the file to each part's presigned URL. Keep each response's ETag header.

The part URLs are signed for the host header only, so you don't need to replay any headers from the plan: send a plain PUT with the bytes as the body and a normal Content-Length (every HTTP client sets it for you — don't use chunked transfer encoding). A Content-Type on a part is ignored; the stored asset's type is the contentType you gave POST /assets.

sh
curl -s -X PUT --upload-file clip.mp4 "<parts[0].url>" -D - -o /dev/null | grep -i etag
# etag: "abc123…"

Or from Node (any fetch runtime works the same):

js
const res = await fetch(part.url, { method: 'PUT', body: await fs.readFile('clip.mp4') });
const etag = res.headers.get('etag');

4. Complete the upload

Hand back the part numbers + ETags. The asset is recorded and becomes ready. Quoted ("abc123…", as the header arrives) and unquoted (abc123…) ETags are both accepted.

sh
curl -s -X POST "$API/assets/<uploadId>/complete" \
  -H "Authorization: Bearer $SK" -H "Content-Type: application/json" \
  -d '{ "parts": [{ "partNumber": 1, "etag": "abc123…" }] }' | jq
# { "assetId": "asset_video_…", "status": "ready" }

5. Publish

One call fans the video asset out to every target. Send an Idempotency-Key so a retry is safe.

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": "My first dispatch",
    "description": "Posted once, everywhere.",
    "targets": [{ "platform": "youtube" }]
  }' | jq
json
{
  "publicationId": "pub_…",
  "status": "queued",
  "targets": [{ "id": "tgt_…", "platform": "youtube", "status": "pending" }]
}

6. Watch it go live

Poll the publication (or subscribe to a webhook and skip polling). Each target travels pending → processing → published; the publication aggregates to done, partial, or failed.

sh
curl -s "$API/brands/$BRAND/publications/pub_…" -H "Authorization: Bearer $SK" | jq '.publication.status, .publication.targets[] | {platform, status, externalUrl}'

When a target reaches published, its externalUrl is the live post.


That's the whole loop: upload once, publish everywhere, watch it settle. Next: Authentication for keys and brands, Publishing a video for the full model, or the REST API reference for every endpoint.

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