Anjal LinkedIn — Posts API

The LinkedIn — Posts API from Anjal — 4 operation(s) for linkedin — posts.

Operations 4

POST /linkedin/posts Publish a new post on the connected account's feed #
GET /linkedin/posts/by-author List recent posts by a profile or company #
GET /linkedin/posts/{postUrn}/comments List comments on a post #
GET /linkedin/posts/{postUrn}/reactions List reactions on a post #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/anjal-app:anjal-app-linkedin-posts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

anjal-app-linkedin-posts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Anjal LinkedIn — Posts API
  version: 1.0.0
  description: 'Anjal is a multi-tenant email API for AI agents.


    Create inboxes on the default `@send.anjal.app` domain or your own custom

    domains, send and receive mail, manage drafts, subscribe to real-time

    events over WebSocket, and isolate resources across workspaces so your

    reseller customers can serve their own end-customers under a single

    billing relationship.


    Install the TypeScript SDK: `npm install anjal`

    (npm)


    MCP server for Claude Desktop / Cursor: `npx -y anjal-mcp`

    (npm)


    ## Authentication


    Every request is authenticated with the `X-API-Key` header (or

    `Authorization: Bearer `). Four key prefixes, each with increasing

    scope:


    | Prefix | Scope | Use it for |

    |----------|-----------------------------------------|-----------------------------------------|

    | `sa_...` | Super admin | Tenant lifecycle (platform operator) |

    | `tk_...` | Tenant master | Everything in your tenant across workspaces |

    | `wk_...` | Workspace master | One workspace only |

    | `ak_...` | Inbox (agent) scoped | One inbox — its messages, drafts, lists |


    ## Resource hierarchy


    ```

    Tenant (billing root)

    └── Workspace (isolation container)

    ├── Inboxes

    │ ├── Messages / Threads / Attachments

    │ ├── Drafts

    │ └── Lists

    └── Domains

    ```


    ## Sending mail


    Mail is sent via `POST /v1/inboxes/{id}/send`. Replies go through

    `/reply/{messageId}`, reply-all through `/reply-all/{messageId}`, and

    forwards through `/forward/{messageId}`. The `From` header always uses

    the inbox''s **primary alias** — add a custom-domain address with

    `POST /v1/inboxes/{id}/addresses` to change it.


    ### Safe retries (Idempotency-Key)


    Every send endpoint (`/send`, `/reply`, `/reply-all`, `/forward` and

    `POST /v1/inboxes/{id}/drafts/{did}/send`) accepts an `Idempotency-Key`

    header. Send a unique value (a UUID works) and retry freely: the first

    request sends and stores its response; a retry with the same key and the

    identical request returns that stored response with the header

    `Idempotent-Replayed: true` and sends nothing.


    | Situation | Result |

    |---|---|

    | Same key, different request (body, inbox or endpoint) | `409 IDEMPOTENCY_KEY_REUSED` |

    | Same key while the first request is still running | `409 IDEMPOTENCY_IN_PROGRESS` |

    | Header present but blank, or longer than 255 characters | `400 IDEMPOTENCY_KEY_INVALID` |

    | The first send failed (non-2xx) | The key is freed; retry with the same key |


    Keys are scoped to your account and expire after 24 hours.


    ### Labels, open tracking, scheduled send


    - **Labels**: pass `labels` (array, or a comma-separated string) on any

    send, reply, reply-all, forward or draft. Change them later with

    `PATCH /v1/inboxes/{id}/messages/{messageId}` or

    `PATCH /v1/inboxes/{id}/threads/{threadId}`, and filter lists with

    `?labels=a,b`. Labels are stored lowercase and deduplicated; at most 32

    per message, each at most 64 characters, no commas.

    - **Open tracking**: `trackOpens: true` on a send with an HTML body adds a

    1x1 pixel (the stored copy never contains it). The first open fires

    `message.opened`. Opens are a hint, not proof: Apple Mail Privacy

    Protection fetches images on delivery, and clients that block images

    never report an open.

    - **Scheduled send**: set `sendAt` on a draft and Anjal sends it at that

    time. See the Drafts endpoints.

    - **Delivery status**: sent messages carry `deliveryStatus`

    (`delivered`, `bounced`, `complained` or `rejected`; null until known)

    and `deliveredAt`.


    ## Receiving mail


    Inbound mail arrives via SMTP on the default domain or any verified

    custom domain. Subscribe to delivery events either by registering a

    webhook (`POST /v1/webhooks`) or by opening a WebSocket

    (`wss://anjal.app/v1/ws`) — useful for in-line 2FA flows where

    the agent doesn''t have a public webhook receiver.'
servers:
- url: https://anjal.app
  description: Production
security:
- apiKeyHeader: []
tags:
- name: LinkedIn — Posts
paths:
  /linkedin/posts:
    post:
      tags:
      - LinkedIn — Posts
      summary: Publish a new post on the connected account's feed
      description: 'Creates a feed post on the connected LinkedIn account. Text is

        required; an inline image is optional. The endpoint handles the

        underlying three-step LinkedIn upload flow (register upload → PUT bytes →

        create share) so the customer just sends one JSON request.


        **Visibility:**

        - `ANYONE` (default) — public on the feed.

        - `CONNECTIONS` — visible to 1st-degree connections only.


        **Image:**

        Pass an `image.dataUrl` (full data URL with embedded mime + base64) for

        the simplest agent shape, OR a separate `image.base64` + `image.contentType`.

        Accepts `image/png`, `image/jpeg`, `image/gif`, `image/webp` up to ~10 MB.


        Quota: 1 `connection_request` slot per call (shared outbound-write

        bucket).'
      operationId: linkedinCreatePost
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - sessionId
              - text
              properties:
                sessionId:
                  type: string
                text:
                  type: string
                  minLength: 1
                  maxLength: 3000
                  description: Post commentary. LinkedIn caps at 3000 characters.
                visibility:
                  type: string
                  enum:
                  - ANYONE
                  - CONNECTIONS
                  default: ANYONE
                image:
                  type: object
                  description: 'Optional inline image. Pass either `dataUrl` (preferred — embeds

                    mime + base64 in one field) or `base64` + `contentType`.

                    '
                  properties:
                    dataUrl:
                      type: string
                      description: Full data URL, e.g. "data:image/png;base64,iVBORw0KG..."
                    base64:
                      type: string
                      description: Bare base64-encoded bytes (no `data:` prefix).
                    contentType:
                      type: string
                      description: Required when using `base64`. Ignored when using `dataUrl`.
                      enum:
                      - image/png
                      - image/jpeg
                      - image/gif
                      - image/webp
                    altText:
                      type: string
                      maxLength: 420
                      description: Accessibility alt-text on the rendered post.
                    filename:
                      type: string
                      maxLength: 255
      responses:
        '200':
          description: Post created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  shareUrn:
                    type: string
                    example: urn:li:share:7455538267644641280
                  shareId:
                    type: string
                  postUrl:
                    type: string
                    format: uri
                  mediaUrn:
                    type: string
                    nullable: true
                    description: Set when an image was uploaded.
        '400':
          description: 'Validation error or LinkedIn rejected the post. Real LinkedIn

            errors are surfaced verbatim in `error` (e.g. commentary too

            long, invalid visibility enum).

            '
        '404':
          description: Session not found.
        '429':
          description: Daily quota exceeded for this session.
  /linkedin/posts/by-author:
    get:
      tags:
      - LinkedIn — Posts
      summary: List recent posts by a profile or company
      description: 'Pull the most recent posts authored by a LinkedIn profile or

        company page. Same helper the engagement-signal runner uses

        internally; exposed as a GET so agents can do one-shot lookups

        ("show me Acme''s last 5 posts") without spinning up a recurring

        signal.


        `profileUrl` accepts either a profile URL

        (`https://www.linkedin.com/in//`) or a company URL

        (`https://www.linkedin.com/company//`). The route resolves

        to a `urn:li:fsd_profile:` or `urn:li:fsd_company:` URN

        automatically.


        Quota: each call burns one `engagement_poll` slot from the

        per-session daily budget.'
      operationId: linkedinListPostsByAuthor
      parameters:
      - name: sessionId
        in: query
        required: true
        schema:
          type: string
      - name: profileUrl
        in: query
        required: true
        schema:
          type: string
      - name: count
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 20
          default: 20
      - name: sinceUrn
        in: query
        schema:
          type: string
        description: Watermark — return only posts whose activityUrn is newer than this.
      responses:
        '200':
          description: Author identity + array of posts (newest first).
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  author:
                    type: object
                    properties:
                      kind:
                        type: string
                        enum:
                        - profile
                        - company
                      urn:
                        type: string
                      label:
                        type: string
                  count:
                    type: integer
                  posts:
                    type: array
                    items:
                      type: object
                      properties:
                        activityUrn:
                          type: string
                          example: urn:li:activity:7332661864792854528
                        postedAt:
                          type: integer
                          nullable: true
                          description: Unix ms; null when LinkedIn omits it.
                        excerpt:
                          type: string
        '400':
          description: Could not resolve the profile/company URL.
        '404':
          description: Session not found.
        '429':
          description: Daily quota exceeded for this session.
  /linkedin/posts/{postUrn}/comments:
    get:
      tags:
      - LinkedIn — Posts
      summary: List comments on a post
      description: 'Fetch commenters on a LinkedIn post. Returns the engager array

        (profile URN, name, headline, comment text), plus the total

        reported by LinkedIn. Same helper the engagement signal uses

        to enumerate commenters on tracked actor posts.


        `postUrn` is the activity URN — `urn:li:activity:`. URL-

        encode it (the `:` characters need to be `%3A` in path

        position).


        Quota: one `engagement_poll` slot per call.'
      operationId: linkedinListPostComments
      parameters:
      - name: postUrn
        in: path
        required: true
        schema:
          type: string
        description: URL-encoded urn:li:activity:<id>
      - name: sessionId
        in: query
        required: true
        schema:
          type: string
      - name: count
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 50
          default: 20
      responses:
        '200':
          description: Commenters + total comment count reported by LinkedIn.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  postUrn:
                    type: string
                  total:
                    type: integer
                    nullable: true
                    description: LinkedIn-reported total. May be null if the count call failed.
                  count:
                    type: integer
                    description: Number of commenters returned in this page.
                  comments:
                    type: array
                    items:
                      type: object
                      properties:
                        profileUrn:
                          type: string
                        slug:
                          type: string
                        name:
                          type: string
                        headline:
                          type: string
                        commentText:
                          type: string
                        postedAt:
                          type: integer
                          nullable: true
        '404':
          description: Session not found.
        '429':
          description: Daily quota exceeded for this session.
  /linkedin/posts/{postUrn}/reactions:
    get:
      tags:
      - LinkedIn — Posts
      summary: List reactions on a post
      description: 'Fetch reactors on a LinkedIn post. Returns each reactor''s

        profile URN, name, headline, and reaction type

        (`LIKE` / `CELEBRATE` / `SUPPORT` / `LOVE` / `INSIGHTFUL` /

        `FUNNY`).


        Quota: one `engagement_poll` slot per call. LinkedIn''s per-call

        rate-limiter cares about call count, not response size — large

        `count` values are no more expensive than small ones.'
      operationId: linkedinListPostReactions
      parameters:
      - name: postUrn
        in: path
        required: true
        schema:
          type: string
        description: URL-encoded urn:li:activity:<id>
      - name: sessionId
        in: query
        required: true
        schema:
          type: string
      - name: count
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 100
      responses:
        '200':
          description: Array of reactors.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  postUrn:
                    type: string
                  count:
                    type: integer
                  reactions:
                    type: array
                    items:
                      type: object
                      properties:
                        profileUrn:
                          type: string
                        slug:
                          type: string
                        name:
                          type: string
                        headline:
                          type: string
                        reactionType:
                          type: string
                          example: LIKE
        '404':
          description: Session not found.
        '429':
          description: Daily quota exceeded for this session.
components:
  securitySchemes:
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'Any of `sa_`, `tk_`, `wk_`, `ak_`, or `mam_` keys. Scope is enforced

        per-endpoint — see individual operation descriptions.

        '