0
Create a Simple Post (Organization)
One script reply has been approved by the moderators Verified

Create post on LinkedIn using text, URL or article. See the docs for more information

Created by hugo697 133 days ago Viewed 52 times
0
Submitted by hugo697 Typescript (fetch-only)
Verified 133 days ago
1
type Linkedin = {
2
	token: string
3
	apiVersion: string
4
}
5

6
type Base64 = string
7

8
async function initializeImageUpload(resource: Linkedin, owner: string) {
9
	const endpoint = 'https://api.linkedin.com/rest/images?action=initializeUpload'
10
	const response = await fetch(endpoint, {
11
		method: 'POST',
12
		headers: {
13
			Authorization: `Bearer ${resource.token}`,
14
			'X-Restli-Protocol-Version': '2.0.0',
15
			'Content-Type': 'application/json',
16
			'LinkedIn-Version': `${resource.apiVersion}`
17
		},
18
		body: JSON.stringify({
19
			initializeUploadRequest: {
20
				owner
21
			}
22
		})
23
	})
24

25
	if (!response.ok) {
26
		throw new Error(`HTTP error! status: ${response.status}`)
27
	}
28

29
	const data = await response.json()
30
	return data.value
31
}
32

33
async function uploadImage(uploadUrl: string, image: Base64) {
34
	const buffer = Buffer.from(image, 'base64')
35

36
	const response = await fetch(uploadUrl, {
37
		method: 'PUT',
38
		headers: {
39
			'Content-Type': 'application/octet-stream'
40
		},
41
		body: buffer
42
	})
43

44
	if (!response.ok) {
45
		throw new Error(`HTTP error! status: ${response.status}`)
46
	}
47
}
48

49
async function uploadThumbnail(resource: Linkedin, owner: string, thumbnail: Base64) {
50
	const uploadData = await initializeImageUpload(resource, owner)
51
	const uploadUrl = uploadData.uploadUrl
52
	const imageUrn = uploadData.image
53

54
	await uploadImage(uploadUrl, thumbnail)
55

56
	return imageUrn
57
}
58

59
export async function main(
60
	resource: Linkedin,
61
	postData: {
62
		author: string
63
		commentary: string
64
		visibility: 'CONNECTIONS' | 'PUBLIC' | 'LOGGED_IN' | 'CONTAINER'
65
		distribution: {
66
			feedDistribution: 'NONE' | 'MAIN_FEED'
67
		}
68
		content?: {
69
			article: {
70
				source: string
71
				title: string
72
				description?: string
73
				thumbnail?: string
74
				thumbnailAltText?: string
75
			}
76
		}
77
		isReshareDisabledByAuthor: boolean
78
	},
79
	thumbnail?: Base64
80
) {
81
	if (postData.content?.article && thumbnail) {
82
		const thumbnailUrn = await uploadThumbnail(resource, postData.author, thumbnail)
83
		postData.content.article.thumbnail = thumbnailUrn
84
	}
85

86
	// Can use unversioned API too, but using versioned one to introduce consistency with Create_a_Simple_Post__Organization_
87
	const endpoint = 'https://api.linkedin.com/rest/posts'
88

89
	const response = await fetch(endpoint, {
90
		method: 'POST',
91
		headers: {
92
			Authorization: `Bearer ${resource.token}`,
93
			'X-Restli-Protocol-Version': '2.0.0',
94
			'LinkedIn-Version': `${resource.apiVersion}`,
95
			'Content-Type': 'application/json'
96
		},
97
		body: JSON.stringify(postData)
98
	})
99

100
	if (!response.ok) {
101
		throw new Error(`HTTP error! status: ${response.status}`)
102
	}
103

104
	const postId = response.headers.get('x-restli-id')
105
	const data = await response.json()
106

107
	return { ...data, postId }
108
}
109