> ## Documentation Index
> Fetch the complete documentation index at: https://www.outx.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# LinkedIn Message API - Send Direct Messages Programmatically

> Send LinkedIn direct messages to your connections programmatically using the OutX LinkedIn Messaging API. Automate outreach and follow-up sequences.

<script type="application/ld+json">
  {`{
    "@context": "https://schema.org",
    "@type": "WebAPI",
    "name": "OutX LinkedIn Messaging API",
    "url": "https://api.outx.ai/linkedin-agent/send-message",
    "description": "Send LinkedIn direct messages to your connections programmatically via API. Automate outreach and follow-up sequences.",
    "documentation": "https://outx.ai/docs/linkedin-api/send-message",
    "provider": {
      "@type": "Organization",
      "name": "OutX.ai",
      "url": "https://www.outx.ai"
    }
    }`}
</script>

The Send Message endpoint creates an async task to send a LinkedIn direct message to a connection. You provide the recipient's person URN and the message text; the API handles delivery through your team's oldest admin member's LinkedIn account.

## Endpoint

```
POST https://api.outx.ai/linkedin-agent/send-message
```

## Request Body

<ParamField body="recipient_urn" type="string" required>
  The LinkedIn person URN of the message recipient (e.g., `"urn:li:person:ACoAABCDEFG"`)
</ParamField>

<ParamField body="message" type="string" required>
  The message text to send. Maximum 10,000 characters. Must not be empty or whitespace-only.
</ParamField>

<Tip>
  **Don't have a recipient URN?** Use the [Fetch Profile](/linkedin-api/fetch-profile) endpoint to look up a profile by slug, the response includes a `profile_urn` field you can use here. You can also get URNs from the [Search Profiles](/linkedin-api/search-profiles) endpoint.
</Tip>

<Warning>
  The message is sent from your team's **oldest admin member's LinkedIn account**. You can only send messages to people who are 1st-degree connections of that account. Make sure this team member has an active Chrome extension session.
</Warning>

## Response

The endpoint returns immediately with a task ID:

<ResponseField name="success" type="boolean">
  Whether the task was created successfully
</ResponseField>

<ResponseField name="api_agent_task_id" type="string">
  UUID to poll for results via [Get Task Status](/linkedin-api/get-task-status)
</ResponseField>

<ResponseField name="message" type="string">
  Human-readable confirmation
</ResponseField>

<ResponseExample>
  ```json Response theme={null}
  {
    "success": true,
    "api_agent_task_id": "550e8400-e29b-41d4-a716-446655440000",
    "message": "Send message task created successfully"
  }
  ```
</ResponseExample>

## Polling for Results

Poll the [Get Task Status](/linkedin-api/get-task-status) endpoint to confirm the message was sent:

```
GET https://api.outx.ai/linkedin-agent/get-task-status?api_agent_task_id=550e8400-e29b-41d4-a716-446655440000
```

### Completed Response

```json theme={null}
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "task_input": {
      "task_type": "agent_send_message",
      "recipient_urn": "urn:li:person:ACoAABCDEFG",
      "message": "Hi Jane, great connecting with you! I'd love to chat about..."
    },
    "task_output": {
      "sent": true
    }
  }
}
```

## Code Examples

<RequestExample>
  ```bash cURL theme={null}
  # Send the message
  curl -X POST \
    "https://api.outx.ai/linkedin-agent/send-message" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "recipient_urn": "urn:li:person:ACoAABCDEFG",
      "message": "Hi Jane, great connecting with you! I'd love to chat about your work at TechCorp."
    }'

  # Check the result
  curl -X GET \
    "https://api.outx.ai/linkedin-agent/get-task-status?api_agent_task_id=TASK_ID" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  async function sendMessage(recipientUrn, message) {
    // Create the send message task
    const response = await fetch(
      "https://api.outx.ai/linkedin-agent/send-message",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": "YOUR_API_KEY",
        },
        body: JSON.stringify({ recipient_urn: recipientUrn, message }),
      }
    );

    const { api_agent_task_id } = await response.json();

    // Poll for completion
    while (true) {
      const statusRes = await fetch(
        `https://api.outx.ai/linkedin-agent/get-task-status?api_agent_task_id=${api_agent_task_id}`,
        { headers: { "x-api-key": "YOUR_API_KEY" } }
      );

      const result = await statusRes.json();
      if (result.data.status === "completed") {
        return result.data.task_output;
      }

      await new Promise((r) => setTimeout(r, 5000));
    }
  }

  const result = await sendMessage(
    "urn:li:person:ACoAABCDEFG",
    "Hi Jane, great connecting with you!"
  );
  console.log(result); // { sent: true }
  ```

  ```python Python theme={null}
  import requests
  import time

  def send_message(recipient_urn, message):
      headers = {
          "Content-Type": "application/json",
          "x-api-key": "YOUR_API_KEY",
      }

      # Create the send message task
      response = requests.post(
          "https://api.outx.ai/linkedin-agent/send-message",
          headers=headers,
          json={"recipient_urn": recipient_urn, "message": message},
      )
      task_id = response.json()["api_agent_task_id"]

      # Poll for completion
      while True:
          result = requests.get(
              "https://api.outx.ai/linkedin-agent/get-task-status",
              headers={"x-api-key": "YOUR_API_KEY"},
              params={"api_agent_task_id": task_id},
          ).json()

          if result["data"]["status"] == "completed":
              return result["data"]["task_output"]

          time.sleep(5)

  result = send_message(
      "urn:li:person:ACoAABCDEFG",
      "Hi Jane, great connecting with you!"
  )
  print(result)  # {"sent": True}
  ```
</RequestExample>

## Error Responses

| Status | Error                                             | Description                                                                                        |
| ------ | ------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `400`  | `Missing or invalid 'recipient_urn'`              | The `recipient_urn` field is missing or not a string                                               |
| `400`  | `Missing or invalid 'message'`                    | The `message` field is missing, empty, or not a string                                             |
| `400`  | `Message text is too long (max 10000 characters)` | The message exceeds the 10,000 character limit                                                     |
| `401`  | `Missing API Key` / `Invalid API Key`             | API key is missing or invalid                                                                      |
| `403`  | `Plugin installation required...`                 | No team member has an active Chrome extension. See [Authentication](/api-reference/authentication) |
| `404`  | `No admin user found in the team`                 | Your team has no admin members                                                                     |

## FAQ

<AccordionGroup>
  <Accordion title="Whose LinkedIn account sends the message?">
    The message is sent from your team's **oldest admin member's** LinkedIn account (sorted by when they joined the team). This is the team member whose Chrome extension session executes the action. Make sure this team member is aware that messages will be sent from their account via the API.
  </Accordion>

  <Accordion title="Can I message anyone or only connections?">
    LinkedIn messaging via the API works the same as manual messaging, you can only send direct messages to 1st-degree connections of the account sending the message. Attempting to message a non-connection will result in a task failure.
  </Accordion>

  <Accordion title="Where do I get the recipient_urn?">
    The `recipient_urn` is a LinkedIn person URN in the format `urn:li:person:XXXXXXXXXXX`. You can obtain it from the `profile_urn` field in the [Fetch Profile](/linkedin-api/fetch-profile) response, or from the results of the [Search Profiles](/linkedin-api/search-profiles) endpoint.
  </Accordion>

  <Accordion title="What about rate limits and LinkedIn safety?">
    **OutX does not rate-limit these requests for you.** Each message is executed as a real LinkedIn message send. Sending many messages in quick succession can trigger LinkedIn's spam detection. Space out messages by at least 30–60 seconds and avoid sending the same message to many people in a short time window. See [Rate Limits](/api-reference/rate-limits) for safe usage guidelines.
  </Accordion>

  <Accordion title="Is there a message length limit?">
    Yes, messages are capped at **10,000 characters**. Requests with messages exceeding this limit will return a `400` error.
  </Accordion>
</AccordionGroup>

## Related

* [Get Task Status](/linkedin-api/get-task-status) - Poll for task results
* [Fetch Profile](/linkedin-api/fetch-profile) - Get a profile URN to use as `recipient_urn`
* [Search Profiles](/linkedin-api/search-profiles) - Find profiles and get their URNs
* [Like Post](/linkedin-api/like-post) - Like posts alongside messaging

***

## Learn More

* [LinkedIn Automation Safety Guide](https://www.outx.ai/blog/linkedin-automation-safety-guide-best-practices-2026)
* [LinkedIn API Guide](https://www.outx.ai/blog/linkedin-api-guide)
