Skip to main content

Projects

A project is a named container for content inside a workspace — typically one personal-brand profile or one company page. Notes, posts, sources, and queue slots all attach to a project. The API exposes a paginated list of the workspace’s projects and a single-project read — both read-only; mutating projects (creation, archive, pause) is dashboard-only. For LinkedIn company pages specifically, GET /v1/company-pages adds activation status, stored admin-token health, and follower counts on top of the plain project rows.

GET /v1/projects

List the projects the authenticated workspace owns, ordered by creation time descending.

Query parameters

Response

Semantics

Field types, nullability and the type / typeLabel enums live in the OpenAPI reference tab (Project). What the schema doesn’t tell you:
  • There is no url field. The LinkedIn identity lives on username, and it is a bare slug, never a URL: the author handle for a personal brand or amplifier (resolving to https://www.linkedin.com/in/<username>) and the company vanity name for a company page (https://www.linkedin.com/company/<username>). It is null until the project is connected. Build the link yourself; don’t split the value on /in/.
  • name is resolved, not raw: a connected project reports the name LinkedIn holds, falling back to the dashboard label.
  • avatarUrl is a CDN URL, null before the project connects.
  • status is ACTIVE for every project the API can return today — the column has exactly one value — and isActive is derived from it. Both are here for forward-compatibility; treat an unknown status as active.
  • AMPLIFIER is a live type alongside PERSONAL_BRAND and COMPANY_PAGE, and shares the personal-brand projection.
  • linkedIn answers whether Scripe can publish as this project right now — see the next section.
Internal fields like the workspace’s owner user id, billing customer id, and onboarding flags are intentionally not in this response. If you need them, use the dashboard.

linkedIn — the publishing precondition

Every project row carries the answer to “can Scripe post as this account right now, and if not, what has to happen”.
Branch on canPublish or state, never on connectionStatus. connectionStatus is the stored health cache written by whatever last talked to LinkedIn. It reads CONNECTED for accounts holding no access token at all, and UNKNOWN for accounts that were simply never connected; state applies token presence first. Reading a project never probes LinkedIn — this is stored health as of lastValidatedAt. The live check runs inside the schedule and publish pre-flights, where a write is about to happen. A company page has no connection of its own: it publishes through the personal account it was linked to, so its block — including reconnectUrl — describes that account. null means the page was never linked to one, which is itself the answer. linkedIn cannot be repaired through this API. Reconnecting is an OAuth flow a human performs in the dashboard; relay reconnectUrl rather than retrying.

GET /v1/projects/{projectId}

Single project read. Returns the same shape as above, wrapped in a data field for symmetry with future write endpoints.

Response

Errors


Cross-workspace isolation

Every project read is scoped by the API key’s workspace. A request for proj_<other-workspace> returns 404 not_found — never a 403, so attackers cannot enumerate which project ids exist outside their workspace. The same isolation applies to the list endpoint: you only see your own workspace’s projects, and the pagination cursor is bound to that filter. You cannot inflate the result set by replaying another workspace’s cursor — the embedded (createdAt, id) keyset is workspace-agnostic, so it just no-ops against your own data.

What’s NOT here (yet)

  • Filtering by status / type. The list returns all projects, regardless of status. Filter client-side.
  • Project metrics. Engagement and analytics live on Analytics.
  • Write endpoints. Creating, pausing, or archiving a project is dashboard-only.