Extending a Scripted LinkedIn Posts API with the Documents API
New article articles in ServiceNow Community
ยท
Feb 23, 2026
ยท
article
Articles, Blogs, Videos, Podcasts, Share projects - Experiences from the field
Hi there,
While looking for ways to be more efficient in my content creation, I caught myself thinking:
"If only I could automatically post on LinkedIn..."
LinkedIn is an important channel for sharing my articles, blogs, Share projects, YouTube videos, or just posting random. Usually, I prepare my content in my Personal Developer Instance and then manually schedule it on both the ServiceNow Community and LinkedIn.
So the obvious question became:
"Is it possible to automatically post on LinkedIn?"
Yes, it is! LinkedIn provides a solid set of APIs that allow exactly that.
Let's take a closer look.
What this series will cover
In the coming weeks, I'll be sharing a short series of articles:
- Scripted LinkedIn Posts API Using RESTMessageV2
- Extending a Scripted LinkedIn Posts API with the Images API
- Extending a Scripted LinkedIn Posts API with the Documents API
- Refactoring a Scripted LinkedIn Posts API into an Integration Hub Spoke
This third article focuses on extending the scripted approach for posting text-only content by adding support for one document using the LinkedIn Documents API.
Documents API
Following the first article in this series, the Documents API is an addition to the Posts API. All the steps outlined in the first article are prerequisites for getting the Documents API working.
- REST Message
- OAuth Entity Profile
- Application Registries
- HTTP Method (Posts API)
We left off with a working REST Message that uses OAuth 2.0 authentication and contains HTTP Methods for the Posts API and the Images API.
Registering a document
Adding support for documents follows almost the exact same pattern as adding images, which makes this extension fairly straightforward once you understand the flow.
The main steps are:
- Registering a document
- Uploading a document
- Create document content
To register a document, you need to use the initializeUpload action to register the upload.
HTTP Method
On the REST Message created in the first article, we need to add an HTTP Method for the Documents API.
At the bottom of the REST Message form, you will find the HTTP Methods related list. From here, we can define the method that will call the LinkedIn Documents API.
- On the REST Message record, scroll down to the HTTP Methods related list
- Click New
- Set HTTP Method to:
POST - Set the Endpoint to:
https://api.linkedin.com/rest/documents?action=initializeUpload
In the Authentication section, leave the Authentication type set to:
Inherit from parent
This ensures the HTTP Method uses the OAuth configuration defined on the REST Message.
In the HTTP Request section, add the following HTTP header:
- Name: Content-Type
- Value: application/pdf
In this example, I'm assuming we are adding a PDF document. I haven't tested yet how this behaves with other document types or how to make the value fully dynamic.
In the Content field under HTTP Query Parameters, add the following JSON payload:
{ "initializeUploadRequest": { "owner": "${personUrn}" } }
This payload is almost identical to the example provided in the LinkedIn API Overview, the only difference I introduced variable substitutions for dynamic values. To support the variable substitutions, we need to define them.
- On the HTTP Method, scroll down to the Variable Substitutions related list
- Click New
- Create a record with:
Name: personUrn
When running this HTTP method, you would get a sample response like:
{ "value": { "uploadUrlExpiresAt": 1650567510704, "uploadUrl": "https://www.linkedin.com/dms-uploads/C3E12BQFoyyAjHPMQuQ/uploaded-document/0?ca=vector\_ads&cn=uploads&sync=0&v=beta&ut=07zHRjMiAOLqc1", "image": "urn:li:document:C4B09AQFoyyAjHPMQuQ" } }
Upload a document
If you followed the previous article on the Images API in this series, then there is nothing new to configure here. Uploading a document works exactly the same way as uploading an image and uses the same HTTP Method that was already created for the Images API.
Posts API
After having the document registered and uploaded, the Document URN needs to be appended to the Content of the Posts API HTTP Method.
In the Content field under HTTP Query Parameters, expand the JSON object with the "content" object:
{ "author": "${personUrn}", "commentary": ${content}, "visibility": "PUBLIC", "distribution": { "feedDistribution": "MAIN_FEED", "targetEntities": [], "thirdPartyDistributionChannels": [] }, "content": { "media": { "altText": "Testing", "id": "${imageUrn}" } }, "lifecycleState": "PUBLISHED", "isReshareDisabledByAuthor": false }
The id (Document Urn), is what we obtained from the response when uploading the document.
Script
You can technically trigger the Posts API using a simple script like this:
var rm = new sn_ws.RESTMessageV2('LinkedIn', 'Documents API'); rm.setStringParameterNoEscape('personUrn', 'urn:li:person:**********'); var response = rm.execute(); var responseBody = response.getBody(); var httpStatus = response.getStatusCode(); var uploadUrl = JSON.parse(responseBody).value.uploadUrl; var documentUrn = JSON.parse(responseBody).value.document; var rm = new sn_ws.RESTMessageV2('LinkedIn', 'uploadUrl'); rm.setStringParameterNoEscape('endpoint', uploadUrl); rm.setRequestBodyFromAttachment('<document_sys_id>'); var response = rm.execute(); var responseBody = response.getBody(); var httpStatus = response.getStatusCode(); var rm = new sn_ws.RESTMessageV2('LinkedIn', 'Posts API'); rm.setStringParameterNoEscape('personUrn', 'urn:li:person:**********'); rm.setStringParameterNoEscape('content', JSON.stringify('Your LinkedIn post goes here.')); rm.setStringParameterNoEscape('documentUrn', documentUrn); var response = rm.execute(); var responseBody = response.getBody(); var httpStatus = response.getStatusCode();
Of course this isn't the greatest artwork of scripting ๐ In a later article I'll share how I applied all scripting from a Script Include with re-usable functions.
Also not included in the above scripting:
- What if the document is optional? Now the script will fail, meaning the content object in the Content field under HTTP Query Parameters in the Posts API needs to become dynamic.
I like to leave you all with a tiny bit of work to do yourself, instead of just copy/pasting everything ๐.
Scheduled posts
With all of the above, we can now schedule LinkedIn posts directly from ServiceNow. That was the goal of this article right ๐.
In my Personal Developer Instance I use a custom application that stores all my contributions, amongst them the LinkedIn posts, which are stored in a dedicated table. Each record contains the post content, a Scheduled date field, and optionally you can add attachments (images, documents, etcetera).
To publish posts automatically, I use a Scheduled Script Execution that runs daily at 07:30 AM. The scheduled job queries all records where the Scheduled field is set to today and then triggers the LinkedIn Posts API for each matching record.
Next...
In a follow-up article, I'll refactor the scripted LinkedIn Posts API into an Integration Hub Spoke.
| C |
If this content helped you, I would appreciate it if you hit bookmark or mark it as helpful.
Interested in more Articles, Blogs, Videos, Podcasts, Share projects I shared/participated in?
- Articles, Blogs, Videos, Podcasts, Share projects - Experiences from the field
|
Kind regards,
Mark Roethof
Independent ServiceNow Consultant
10x ServiceNow MVP
https://www.servicenow.com/community/developer-articles/extending-a-scripted-linkedin-posts-api-with-the-documents-api/ta-p/3474481
Mark Roethof