# Publish to LinkedIn with the API
URL: https://skedcast.com/developers/guides/publish-to-linkedin-api

LinkedIn has a small override surface: visibility, an optional first comment and, for a Company Page, a target audience. Text, media and scheduling use the standard POST /v1/posts body.

## What do you need before you publish?
You need one connected account for the platform. Connect it in the SkedCast console. If a client owns the account, create a connect link with `POST /v1/clients/{id}/connect-invites` and send it to them. They authorize from that page without a SkedCast login.
`GET /v1/accounts` lists the connected accounts with their ids. Pass that id in `targets.accountIds` below.

## How do you schedule a LinkedIn post with the API?
```bash
curl -X POST https://api.skedcast.com/v1/posts \
  -H "Authorization: Bearer sked_live_YOUR_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "<clientId>",
    "content": "Launch day is here 🚀",
    "mediaIds": ["<mediaAssetId>"],
    "targets": { "mode": "selection", "accountIds": ["<linkedinAccountId>"] },
    "schedule": { "type": "at", "scheduledAt": "2030-01-15T15:00:00Z" }
  }'
```

## Which LinkedIn fields can you set?
Put everything platform-specific in one `variants` entry with `"platform": "linkedin"` and an `overrides` object. Send only `linkedin` keys on a `linkedin` variant. SkedCast reads the keys in the table below and ignores the rest.

## Reference
Field | Type | Values / default | Notes
`visibility` | enum | `PUBLIC` \| `CONNECTIONS` | Defaults to `PUBLIC`.
`targetAudience` | object | `{ geoLocations?, industries?, seniorities?, jobFunctions?, staffCountRanges?, interfaceLocales?, degrees?, fieldsOfStudy? }`, each up to 20 `{ value, name }` | Company Pages connected through LinkedIn's Community Management app: only followers who match see the post. See Audience targeting below.
`content` / `contentOverride` | string | text | The caption is sent as typed. A mention token `@[Name](urn:li:person:ID)` or `@[Name](urn:li:organization:ID)` mentions that person or company. A malformed token fails validation with `mention_malformed`.
`firstComment` | string | — | Posted as a comment on the published post right after publish. Best-effort: a failed comment never fails the post. The outcome is reported as `firstCommentIssue` on `GET /v1/post-targets/{id}`.
After publishing | — | `POST /v1/posts/{id}/targets/{targetId}/edit-published` with `text` | Changes the text of a live post, on an account connected through LinkedIn's Community Management app. Nothing else about the post can change.
`pollQuestion` | string (≤140) | — | Turns the post into a poll with this question. A poll cannot be combined with media.
`pollOptions` | string[] (or a comma-separated string) | 2–4, up to 30 characters each | The poll choices.
`pollDuration` | enum | `ONE_DAY` \| `THREE_DAYS` (default) \| `SEVEN_DAYS` \| `FOURTEEN_DAYS` | How long the poll stays open.
`eventId` | string | — | Share one of the Page's LinkedIn Events: its id, or `urn:li:event:{id}`. LinkedIn shows the event card, so the post carries no media or poll (`event_with_media` otherwise).

## Unknown keys are ignored without an error
A misspelled or unknown key in `overrides` is not an error and not a warning. It is dropped, so check the field names in the table above, especially a required one.
A YouTube-only key (such as `privacyStatus`, `captions` or `chapters`) sent on another platform's variant is ignored and returns an `override_key_wrong_platform` warning.

## How do you add LinkedIn-specific settings?
```json
{
  "clientId": "<clientId>",
  "content": "We're hiring — link in comments.",
  "mediaIds": [],
  "targets": { "mode": "selection", "accountIds": ["<linkedinAccountId>"] },
  "variants": [
    { "platform": "linkedin", "overrides": { "visibility": "PUBLIC", "firstComment": "Apply here: https://example.com/careers" } }
  ],
  "schedule": { "type": "at", "scheduledAt": "2030-01-15T15:00:00Z" }
}
```

## Audience targeting
`targetAudience` limits a Company Page post to followers who match. A personal profile publishes to its usual audience.
- Each category takes up to 20 entries of `{ value, name }`. A follower matches if they match at least one value in every category you send.
- `value` is LinkedIn's targeting URN: `urn:li:geo:…`, `urn:li:industry:…`, `urn:li:seniority:…`, `urn:li:function:…`, `urn:li:locale:…`, `urn:li:degree:…` or `urn:li:fieldOfStudy:…`.
- For `staffCountRanges`, `value` is a company size from `SIZE_1` to `SIZE_10001_OR_MORE`.
- LinkedIn needs more than 300 matching followers. With fewer, the destination fails with `linkedin_audience_too_small` before anything is sent.

## How do you check that the post published?
Publishing creates one post target per account. `GET /v1/post-targets/{id}` (or `GET /v1/posts/{id}`) reports `status`, plus `externalId` (LinkedIn's own post id) and `permalink` (its public URL) once published. To avoid polling, subscribe to the `target.published` and `target.failed` webhooks (see the webhooks guide).

## FAQ
**Q: Can I post to a LinkedIn Company Page as well as a personal profile?**
A: Yes. Connect either in the SkedCast console. Both appear as ordinary accounts in GET /v1/accounts and take the same POST /v1/posts body.
