- the message sends under
/api/linkedin-messages/:send,send-voice,send-inmail,send-sales-nav,send-recruiterandstart-group - the connection request,
POST /api/linkedin-connection-requests/send - the posting verbs under
/api/linkedin-posting/:comment(a comment or a reply),create-postandrepost
The key
client_reference is your own id for one send. It takes up to 255 characters and is compared byte for byte. Mint one per send (your task id, your outbox row id) and use the same key every time you send that one again.
A key and its place make one send. The place depends on what is sent:
- A repeat to the same place is the same send, whatever its text says. If the first send went out, the repeat answers
200with what it made (the message or the connection request row, the comment, the post or the repost) andresult.idempotent_replay: true, plusresult.content_differs: truewhen the repeat said something else (a re-rendered template, an edited draft). Nothing is sent. - The same key at another place is another send. That is how a bulk run can tag all of its sends with one value.
- The time of a scheduled post is not part of its place under a key: a retry that computes a new
scheduled_atis the same post. - A send without a key gets a weaker net. One that matches an earlier send’s words and place (for a post, its pictures or video too) is held while that send is on its way or in doubt, and answered with it for an hour after it went out. To send the same words twice on purpose, use two keys.
Four outcomes
What a send came to is one of four values. Every error of a send endpoint carries it inerror.context.send_outcome, the request’s own 422 included.
An answer with no
send_outcome at all, such as a gateway page or a dropped connection, is unknown to you.
What a repeat is answered
One more
409 comes from the place. When another send to the same place is running or in doubt (another message to the conversation, another invitation to the person, another comment on the post), yours waits: 409 concurrent_send_in_flight with send_outcome: not_sent, the other attempt in blocking_activity_log_sid, and retry_after. Nothing of yours went out, so send the same request again at retry_after.
activity_log_sid always names an attempt of your own send. Another send’s attempt is only ever blocking_activity_log_sid.
Two answers belong to one kind of send each:
- A connection request meets LinkedIn’s own rule of one pending invitation per person. When LinkedIn refuses an invitation because one of the account’s is out to the person, the platform answers with that one: as the repeat of the same invitation, with a
409naming it while it is in doubt, or with422 resend_not_availableandcontext.cause: "pending"when another invitation of the account is pending. The person never gets two. - A post LinkedIn answered without naming one is
409 post_not_createdwithsend_outcome: unknown. The post may be out, so the platform reads LinkedIn for it. Repeat the same request afterretry_after, never as a new post.
Asking without sending
Three endpoints answer the same question and send nothing. Ask by the key, by the key and a place, or by theactivity_log_sid an answer named.
POST /linkedin/v4/api/linkedin-messages/check-sent
POST /linkedin/v4/api/linkedin-posting/check-sent
item is what the send made once it is known: the message row, the connection request row, a comment’s comment_urn, or a post’s or a repost’s urns and url. result.reason says why. For not_sent it is no_send_under_key, refused, or the read that proved it (not_in_thread, not_in_invitations, not_on_linkedin). While the send is in doubt it is answer_lost, may_still_land, unprovable, or a read that could not be done (thread_unreadable for a message, unreadable for the others). The tools list a few more. When the last read is old enough, check-sent reads LinkedIn during the call, so it can take as long as an inbox read.
post_place is where a post landed: feed:member for your own feed, feed:org:<id> for a company page, group:<id> for a group (group:<id>:org:<id> when a page posted into it).
A key that went to more than one place, such as a bulk run’s tag, answers 422 place_required when you ask by the key alone. error.context.places lists the places. Ask again with one of them. A place the platform cannot tell from the key’s own (named in another form than the sends recorded, or a post LinkedIn could not be read for) answers 422 place_unmatched, with the places too.
What LinkedIn shows, and what it cannot
The platform settles a send in doubt by reading what LinkedIn shows, by the account and the words:
A post into a group whose answer was lost stays
unknown until a person looks and gives their word, and so does a page post the page’s feed has not shown.
A person’s word
The platform reads LinkedIn by itself for up to a day, and check-sent reads it on demand after that. If a send staysunknown longer than your process can wait, a person opens LinkedIn and looks. Their answer rides on the same send request and names the attempt they checked by its activity_log_sid.
confirmed_not_sent: it is not there. It is accepted once the attempt can no longer land. Before that the request answers409 send_outcome_unknownwithwaiting_for: may_still_landand that moment inretry_afterandsend_decisive_at. Once accepted, the attempt is settlednot_sentand your request goes out.confirmed_sent: it is there. The attempt is settledsentat once and nothing is sent. The answer is a409withsend_outcome: sent, or a200once what it made is stored.
422 not_this_message, and confirmed_sent naming an attempt already proven not sent answers 409 confirmed_sent_contradicts.
The rule for a caller
- Mint one key per send and keep it with the send.
- On
sentor a200, record it. - On
not_sent, follow the error. Send the same request again later, or give up. - On anything else, no answer included, keep the send pending. Ask check-sent or send the same request after
retry_after. It goes out again only once the answer isnot_sent, and always under the same key. - Past your own deadline, a person looks and gives their word.
Example
A reply to a lead goes out undertask-48213:
POST /linkedin/v4/api/linkedin-messages/send
task-48213 and sends the linkedin-messages.sent webhook, and the same request now answers 200 with that row and result.idempotent_replay: true. The lead got one message.
Had the conversation shown nothing after the send could no longer land, in two reads five minutes apart, the answer would have been not_sent and the same request would have sent the message once.
In a mass action
Each send a bulk run makes goes out under a key of its own: a message, a connection request, a comment. A target’s ownclient_reference is used as given when the plan sends with that tool once. A client_reference T in a send step’s args is a tag: each send goes out under T:{item sid}:{step id}, so an exact search for T finds nothing. Find the run’s sends by each item’s created_object_sid or by their exact keys, and match the T: prefix in your own code when you read webhooks. Do not create the run again because T matched nothing. That sends everything twice.
A send step whose answer was lost waits with wait_reason: send_outcome_unknown and asks check-sent under its key before anything goes again. The retry is in Run a mass action.
Reactions
A reaction takes no key and has no check-sent. LinkedIn keeps one reaction per account and post, so sending the same reaction again changes nothing on LinkedIn. Every error ofreact still names send_outcome, and after unknown you can send the same reaction again.