Messaging API
Send LinkedIn messages through your connected accounts and manage reusable message templates. Sends count against the account's daily message limits, the same counters your campaigns use.
Sending Messages
Send Message
/api/messages/sendSend a text message from a connected LinkedIn account. Reply into an existing conversation with chatId, or start a new one with recipientProviderId. The send is rate-limit checked first; when the account's daily message limit is reached or the account is paused, the request is rejected with 429 and never sent. A manual send counts as a person taking over: any running campaign sequence for that lead on this account stops (handedOver tells you how many), so the campaign never messages over your conversation.
Request Body
| Parameter | Type | Description |
|---|---|---|
accountIdrequired | string | LinkedIn account ID to send from |
textrequired | string | Message text |
chatId | string | Existing conversation ID to reply into. Provide this or recipientProviderId. |
recipientProviderId | string | Recipient's contact identifier (e.g. from the Pipeline CRM or conversation APIs) to start a new conversation |
recipientName | string | Recipient display name, stored on the message log (only used with recipientProviderId) |
curl --location --request POST 'https://outreach.weezly.com/api/messages/send' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"accountId": "cm3acc123mno",
"recipientProviderId": "contact_abc123",
"recipientName": "Sarah Chen",
"text": "Hi Sarah, great connecting with you!"
}'{
"success": true,
"chatId": "chat_xyz789",
"messageId": "msg_def456",
"handedOver": 1,
"bookingStageMove": null
}Response Fields
| Parameter | Type | Description |
|---|---|---|
handedOver | number | Number of running campaign sequences for this lead that were stopped because a person replied by hand |
bookingStageMove | object|null | Set when the text contains one of your Weezly booking links and the contact was moved to your existing "Booking link sent" pipeline stage: { stageId, providerContactId }. null otherwise. |
{
"error": "sender_inactive",
"status": "DISCONNECTED"
}{
"error": "daily_limit_reached",
"retryAfter": "2026-08-20T00:00:00.000Z"
}Response Codes
| 200 | Message sent |
| 400 | Missing accountId or text, or neither chatId nor recipientProviderId provided |
| 404 | Account not found |
| 409 | sender_inactive: the account is disconnected or suspended (status tells you which) |
| 429 | Rate limited. error is daily_limit_reached, account_paused, or too_fast; retryAfter is when to retry |
Send InMail
/api/messages/send-inmailSend a new InMail to someone you are not connected with. Needs a Premium, Sales Navigator or Recruiter plan; Sales Navigator accounts use their Sales Navigator credits. Counts against the account's daily InMail limit.
Request Body
| Parameter | Type | Description |
|---|---|---|
accountIdrequired | string | LinkedIn account ID to send from |
recipientProviderIdrequired | string | Recipient's contact identifier |
textrequired | string | InMail body, max 1,900 characters |
subject | string | Subject, max 200 characters |
recipientName | string | Recipient display name, stored on the message log |
curl --location --request POST 'https://outreach.weezly.com/api/messages/send-inmail' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"accountId": "cm3acc123mno",
"recipientProviderId": "contact_abc123",
"recipientName": "Sarah Chen",
"subject": "Quick question",
"text": "Hi Sarah, I saw your post about..."
}'{
"success": true,
"chatId": "chat_xyz789",
"messageId": "msg_def456",
"salesNavFallback": false
}salesNavFallback is true when a Sales Navigator account could not send through Sales Navigator (its Sales Navigator session is not established) and the InMail went out through the classic LinkedIn InMail instead. Re-sync the account to restore Sales Navigator sending.
Response Codes
| 200 | InMail sent |
| 400 | Missing recipient or text, subject or text too long, or code no_credits (no InMail credits left), not_subscribed (the plan cannot send InMails), recipient_unreachable (LinkedIn will not deliver to this person) |
| 404 | Account not found |
| 409 | sender_inactive: the account is disconnected or suspended |
| 429 | Rate limited (daily InMail limit, account paused); retryAfter is when to retry |
| 502 | provider_error: LinkedIn did not accept the InMail, try again |
InMail Credits
/api/messages/inmail-balanceRemaining InMail credits for one LinkedIn account, per plan. total is the sum, or null when the account has no InMail plan. When LinkedIn cannot be reached, every value is null and unavailable is true.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
accountIdrequired | string | LinkedIn account ID |
curl --location --request GET 'https://outreach.weezly.com/api/messages/inmail-balance?accountId=cm3acc123mno' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"premium": null,
"recruiter": null,
"sales_navigator": 48,
"total": 48,
"accountType": "SALES_NAVIGATOR"
}Response Codes
| 200 | Credits returned |
| 400 | accountId is required |
| 404 | Account not found |
Conversations
Read the inbox of your connected accounts. Both endpoints respect each account's inbox privacy setting: an account set to track only conversations started from Weezly Outreach returns only those.
List Conversations
/api/messages/chatsList an account's conversations, newest first, with the other participant and the last message. Use the returned cursor to load the next page.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
accountIdrequired | string | LinkedIn account ID, or "all" for the first page of every connected account merged (up to 80 conversations, no cursor) |
cursor | string | Cursor from the previous response |
unread | string | "true" = only unread conversations |
box | string | "inbox" = regular conversations only, "inmail" = InMail conversations only (25 per page). Omit for everything. |
curl --location --request GET 'https://outreach.weezly.com/api/messages/chats?accountId=cm3acc123mno&unread=true' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"chats": [
{
"id": "chat_xyz789",
"unread_count": 1,
"attendees": [
{ "id": "contact_abc123", "name": "Sarah Chen", "profile_picture_url": "https://..." }
],
"last_message": { "text": "Sounds good, let's talk Thursday", "timestamp": "2026-10-06T14:02:00.000Z" },
"senderAccountId": "conn_1a2b3c",
"senderName": "John Smith",
"senderPhotoUrl": "https://..."
}
],
"cursor": "next_page_cursor"
}Response Codes
| 200 | Conversations returned |
| 400 | accountId is required |
| 404 | Account not found |
Unread Counts
/api/messages/unread-countsUnread conversation counts for every connected account. counts is every unread conversation, inmailCounts the InMail part of it (regular inbox = counts minus inmailCounts). Both are keyed by the account's LinkedIn connection identifier (the same value the conversations endpoint returns as senderAccountId), not by the account ID.
curl --location --request GET 'https://outreach.weezly.com/api/messages/unread-counts' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"counts": { "conn_1a2b3c": 4, "conn_4d5e6f": 0 },
"inmailCounts": { "conn_1a2b3c": 1, "conn_4d5e6f": 0 }
}Response Codes
| 200 | Counts returned |
| 401 | Unauthorized |
Voice note and video message sends (/api/messages/send-voice, /api/messages/send-video) exist for the in-app inbox and require media from your recording library; they are not designed for external integrations.
Message Templates
Reusable message bodies with variables like {{firstName}}, {{lastName}}, {{fullName}}, {{company}}, and {{jobTitle}}. Variables are resolved from the conversation's lead when a template is inserted in the inbox; the send endpoint sends text as-is. Up to 50 templates per user.
List Templates
/api/message-templatesList all message templates for the authenticated user, newest first.
curl --location --request GET 'https://outreach.weezly.com/api/message-templates' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{
"templates": [
{
"id": "mt_001",
"name": "Thanks for connecting",
"body": "Hi {{firstName}}, thanks for connecting! I saw you're at {{company}} and wanted to reach out.",
"createdAt": "2026-08-10T09:00:00.000Z",
"updatedAt": "2026-08-10T09:00:00.000Z"
}
]
}Create Template
/api/message-templatesCreate a message template. Names are capped at 100 characters and bodies at 5,000.
Request Body
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Template name (max 100 characters) |
bodyrequired | string | Message body, may contain {{variables}} (max 5,000 characters) |
curl --location --request POST 'https://outreach.weezly.com/api/message-templates' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"name": "Follow up",
"body": "Hi {{firstName}}, just following up on my last message. Would love to hear your thoughts!"
}'{
"template": {
"id": "mt_002",
"name": "Follow up",
"body": "Hi {{firstName}}, just following up on my last message. Would love to hear your thoughts!",
"createdAt": "2026-08-19T10:00:00.000Z",
"updatedAt": "2026-08-19T10:00:00.000Z"
}
}Response Codes
| 200 | Template created |
| 400 | Name and message are required, or the 50-template limit is reached |
Update Template
/api/message-templates/:idUpdate a template. Both name and body must be provided (full replace, not a partial patch).
Request Body
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Template name (max 100 characters) |
bodyrequired | string | Message body (max 5,000 characters) |
curl --location --request PATCH 'https://outreach.weezly.com/api/message-templates/:id' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"name": "Follow up",
"body": "Hi {{firstName}}, circling back on this. Any thoughts?"
}'{
"template": {
"id": "mt_002",
"name": "Follow up",
"body": "Hi {{firstName}}, circling back on this. Any thoughts?",
"createdAt": "2026-08-19T10:00:00.000Z",
"updatedAt": "2026-08-19T11:30:00.000Z"
}
}Response Codes
| 200 | Template updated |
| 400 | Name and message are required |
| 404 | Template not found |
Delete Template
/api/message-templates/:idDelete a message template.
curl --location --request DELETE 'https://outreach.weezly.com/api/message-templates/:id' \
--header 'X-API-KEY: sk_live_YOUR_API_KEY'{ "success": true }Response Codes
| 200 | Template deleted |
| 404 | Template not found |