# LinkedIn Automation (Official API)

This guide demonstrates how to automate posting to LinkedIn using the official LinkedIn API. It uses `requests` to interact with the REST API endpoints for retrieving user details and creating posts.

**Modules Used:**
*   [[programming/python/modules/requests-module|requests]]: To make HTTP requests.
*   [[programming/python/modules/python-dotenv-module|python-dotenv]]: To manage the access token.
*   [[programming/python/modules/argparse-module|argparse]]: To handle command-line arguments.

## Prerequisites

1.  **LinkedIn Developer App**: Go to LinkedIn Developers, create an app.
2.  **Permissions**: Under "Products", request access to **Share on LinkedIn** (`w_member_social`) and **Sign In with LinkedIn** (`r_liteprofile` or `r_emailaddress`).
3.  **Access Token**:
    *   Go to the **Auth** tab of your app.
    *   Use the **OAuth 2.0 tools** link (Token Generator) to generate an access token for your personal account.
    *   Select the scopes (`w_member_social`, `r_liteprofile`).
    *   Copy the **Access Token**.

## Installation

```bash
pip install requests python-dotenv
```

## Setup

Create a `.env` file in your project directory:
```text
LINKEDIN_ACCESS_TOKEN=your_long_access_token_here
```

## The Code

Save this as `linkedin_bot.py`.

```python
import requests
import os
import argparse
import sys
import json
from dotenv import load_dotenv

# Load Config
load_dotenv()
ACCESS_TOKEN = os.getenv("LINKEDIN_ACCESS_TOKEN")

API_URL = "https://api.linkedin.com/v2"

def get_headers():
    if not ACCESS_TOKEN:
        print("Error: LINKEDIN_ACCESS_TOKEN not found in .env")
        sys.exit(1)
    return {
        "Authorization": f"Bearer {ACCESS_TOKEN}",
        "Content-Type": "application/json",
        "X-Restli-Protocol-Version": "2.0.0"
    }

def get_user_urn():
    """Fetches the authenticated user's URN (ID)."""
    url = f"{API_URL}/me"
    response = requests.get(url, headers=get_headers())
    
    if response.status_code == 200:
        data = response.json()
        # URN format: urn:li:person:ID
        return f"urn:li:person:{data['id']}"
    else:
        print(f"Error fetching profile: {response.status_code} - {response.text}")
        sys.exit(1)

def post_text_share(urn, text, visibility="PUBLIC"):
    """Posts a text update to LinkedIn."""
    url = f"{API_URL}/ugcPosts"
    
    # Visibility mapping
    share_visibility = "PUBLIC" if visibility.upper() == "PUBLIC" else "CONNECTIONS"

    payload = {
        "author": urn,
        "lifecycleState": "PUBLISHED",
        "specificContent": {
            "com.linkedin.ugc.ShareContent": {
                "shareCommentary": {
                    "text": text
                },
                "shareMediaCategory": "NONE"
            }
        },
        "visibility": {
            "com.linkedin.ugc.MemberNetworkVisibility": share_visibility
        }
    }

    print(f"Posting to LinkedIn as {urn}...")
    response = requests.post(url, headers=get_headers(), data=json.dumps(payload))

    if response.status_code == 201:
        print("Success! Post created.")
        print(f"Post ID: {response.json()['id']}")
    else:
        print(f"Error posting: {response.status_code} - {response.text}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="LinkedIn Automation Bot")
    parser.add_argument("text", help="Text content to post")
    parser.add_argument("--visibility", default="PUBLIC", choices=["PUBLIC", "CONNECTIONS"], help="Post visibility")
    
    args = parser.parse_args()
    
    # 1. Get User ID (URN)
    user_urn = get_user_urn()
    
    # 2. Post
    post_text_share(user_urn, args.text, args.visibility)
```

## Usage

```bash
python linkedin_bot.py "Hello LinkedIn network! This post was automated with Python."
```

[[programming/python/python]]