This section as Markdown: View Download

LinkedIn Integration

Connect your agent to a LinkedIn Company Page to publish posts and engage with followers.

Overview

The LinkedIn integration uses the LinkedIn Marketing Developer Platform via OAuth 2.0. Agents publish posts on behalf of a Company Page using the connecting member's admin rights.

Skills that use this integration:

  • int-linkedin-post — Publish text, image, and video posts to a Company Page

Agents that typically enable this integration:

  • Social Manager
  • Any custom agent that needs LinkedIn Company Page publishing

Availability

Mode Status Notes
"wiro" Coming soon LinkedIn partner app review pending.
"own" Available now Create your own LinkedIn Developer App.

Prerequisites

  • A Wiro API key — Authentication.
  • A deployed agent — Agent Overview.
  • A LinkedIn Company Page the connecting user is an admin of — personal profiles are not supported.
  • The numeric LinkedIn organization ID (not the vanity slug). Find it in linkedin.com/company/<ID>/admin/.
  • An HTTPS callback URL for your backend.

Complete Integration Walkthrough

Step 1: Create a LinkedIn Developer App

  1. linkedin.com/developers/apps → Create app.
  2. Fill in:
    • App name (shown on consent screen).
    • LinkedIn Page (associate with a Company Page you own — this gives admins automatic development access).
    • Privacy policy URL.
    • App logo (128×128 PNG).
  3. Agree to Legal terms → Create app.

Step 2: Request the required products

Products tab. Request:

  • Sign In with LinkedIn using OpenID Connect — for openid and profile scopes.
  • Community Management API — required for Company Page posting (w_organization_social, r_organization_social).

Community Management API approval is a manual review that can take days. While pending, your app can still post to the Company Page it's associated with for admins listed on that page — this is enough for development and testing.

Step 3: Configure the OAuth redirect URI

  1. Auth tab.
  2. OAuth 2.0 settings → Authorized redirect URLs for your app → add:
    https://api.wiro.ai/v1/UserAgentOAuth/LICallback
  3. Save.

Step 4: Note the required OAuth 2.0 scopes

Wiro requests these exact scopes:

openid profile w_organization_social r_organization_social
Scope Why
openid OpenID Connect basic identity.
profile Member's display name and headline (shown on consent).
w_organization_social Post, comment, and reply on behalf of the Company Page.
r_organization_social Read Company Page posts and engagement.

Wiro does not request email, w_member_social, or rw_organization_admin. Keep your app's scope list limited to the four above for consistency with the Wiro flow.

Enable all four in Auth → OAuth 2.0 scopes. Scopes not enabled in this list will fail at the consent screen.

Step 5: Copy your Client ID and Client Secret

Auth → Application credentials → copy Client ID. Copy the Primary Client Secret — it's shown in plain text here. Store it like a password.

Step 6: Save credentials to Wiro

LinkedIn requires clientid, clientsecret, and organizationid all in the same credential block.

curl -X POST "https://api.wiro.ai/v1/UserAgent/CredentialUpsert" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "fields": [
      { "credentialkey": "linkedin", "fieldname": "clientid",       "fieldvalue": "YOUR_LINKEDIN_CLIENT_ID" },
      { "credentialkey": "linkedin", "fieldname": "clientsecret",   "fieldvalue": "YOUR_LINKEDIN_CLIENT_SECRET" },
      { "credentialkey": "linkedin", "fieldname": "organizationid", "fieldvalue": "12345678" },
      { "credentialkey": "linkedin", "fieldname": "authmethod",     "fieldvalue": "own" }
    ]
  }'

organizationid is the numeric ID from your Company Page admin URL. The vanity slug won't work.

Step 7: Initiate OAuth

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthConnect" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "linkedin",
    "redirecturl": "https://your-app.com/settings/integrations",
    "authmethod": "own"
  }'

Response:

{
  "result": true,
  "authorizeUrl": "https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=...&redirect_uri=...&scope=openid%20profile%20w_organization_social%20r_organization_social&state=...",
  "errors": []
}

Step 8: Handle the callback

After consent, LinkedIn redirects to Wiro's callback. Wiro exchanges the code for access + refresh tokens, fetches the member's localizedFirstName + localizedLastName from GET /v2/me, and returns the user to your redirecturl.

Success URL:

https://your-app.com/settings/integrations?li_connected=true&li_name=Jane%20Doe

li_name is the connected LinkedIn member's display name (a human), not the Company Page name — the page is identified by organizationid which you set in Step 6.

const params = new URLSearchParams(window.location.search);

if (params.get("li_connected") === "true") {
  const name = params.get("li_name");
  showSuccess(`Connected as ${name}`);
} else if (params.get("li_error")) {
  handleError(params.get("li_error"));
}

Step 9: Verify

curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthStatus" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "credentialkey": "linkedin"
  }'

Response:

{
  "result": true,
  "connected": true,
  "accounts": [
    { "id": "Jane Doe", "name": "Jane Doe" }
  ],
  "connectedat": "2026-04-17T12:00:00.000Z",
  "tokenexpiresat": "2026-06-16T12:00:00.000Z",
  "errors": []
}
  • accounts[0].id and accounts[0].name both carry the connected LinkedIn member's display name (a human), not the Company Page name — the page is identified by organizationid you set in Step 6.
  • Access tokens last ~60 days; LinkedIn typically issues a longer-lived refresh token. Wiro maintains the connection automatically while the agent is running.

Step 10: Start the agent

curl -X POST "https://api.wiro.ai/v1/UserAgent/Start" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{ "guid": "your-useragent-guid" }'

API Reference

POST /UserAgentOAuth/OAuthConnect

Parameter Type Required Description
useragentguid string Yes Agent instance GUID.
credentialkey string Yes "linkedin".
redirecturl string Yes HTTPS URL.
authmethod string No "wiro" (coming soon) or "own".

GET /UserAgentOAuth/LICallback

Query params: li_connected=true&li_name=... or li_error=.... The callback path is per-provider — LinkedIn's stays LICallback.

POST /UserAgentOAuth/OAuthStatus

Body: { useragentguid, credentialkey: "linkedin" }. Response: connected, accounts: [{id, name}] (1-element with the connected LinkedIn member's name), connectedat, tokenexpiresat.

POST /UserAgentOAuth/OAuthDisconnect

Body: { useragentguid, credentialkey: "linkedin" }. Clears LinkedIn credentials (no remote revoke).

Token lifecycle

Wiro maintains the LinkedIn connection automatically while the agent is running. If LinkedIn revokes the authorization or OAuthStatus reports connected: false, reconnect through the OAuth flow.

Using the Skill

Once the LinkedIn Company Page is connected (organization ID persisted), the agent's scheduled tasks use the int-linkedin-post platform skill to publish text, image, and video posts to the Company Page. To adjust the cron of the built-in cs-cron-social-content-scanner task (Social Manager), call POST /UserAgent/CustomSkillUpsert with enabled and interval only — cron skill bodies are template-controlled and value is silently ignored for bundled crons.

curl -X POST "https://api.wiro.ai/v1/UserAgent/CustomSkillUpsert" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "useragentguid": "your-useragent-guid",
    "skillkey": "cs-cron-social-content-scanner",
    "enabled": true,
    "interval": "0 */4 * * *"
  }'

To change what the scheduled task posts (topics, tone, audience angle), edit the paired preference skill content-tone instead — see Agent Skills → Updating Preference Skills.

Troubleshooting

Error code Meaning What to do
missing_params Callback reached without state or code. Restart from Step 7.
session_expired >15 min between OAuthConnect and callback. Call OAuthConnect again.
authorization_denied User cancelled, or missing required scopes in app. Verify all four scopes are enabled under Auth → OAuth 2.0 scopes.
token_exchange_failed Wrong Client Secret or redirect URI mismatch. Re-copy secret; verify URL.
useragent_not_found Invalid or unauthorized guid. Use POST /UserAgent/MyAgents.
LinkedIn credentials not configured Returned in OAuthConnect's errors[] when authmethod: "own" but clientid / clientsecret are missing. UserAgent/CredentialUpsert with clientid + clientsecret.
internal_error Server error. Retry; contact support if persistent.

Posts rejected with 401 Unauthorized

Most likely cause: the Community Management API product hasn't been approved yet. During the pending phase, posting works only for admins of the Company Page the app is associated with (My Pages in LinkedIn Developers). Verify admin membership.

"Scope w_organization_social not authorized"

Enable it under Auth → OAuth 2.0 scopes, then have the user reconnect. LinkedIn doesn't automatically grant scopes you haven't enabled.

Wrong organization ID

Use the numeric ID from linkedin.com/company/<ID>/admin/ — not the slug. Update via POST /UserAgent/CredentialUpsert and reconnect if needed.

Multi-Tenant Architecture

  1. One LinkedIn Developer App per product.
  2. One Wiro agent instance per customer; capture organizationid during onboarding.
  3. Community Management API approval is per app (not per customer) — apply once.
  4. Tokens are isolated per agent instance.
  5. Rate limits per app and per organization; see LinkedIn's rate-limits docs.