linkedin-developers / linkedin-api-js-client

LinkedIn API JavaScript Client Library
Other
75 stars 16 forks source link

Lacking Documentation: Creating a Post through the Share API #20

Closed ozorOzora closed 1 year ago

ozorOzora commented 1 year ago

Dear developers,

I can't find any documentation regarding the format required to create a Post with the linkedin Share API, the following code fails with AxiosError {message: 'Request failed with status code 401', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: ClientRequest, …}


restliClient.create({

        accessToken: accessToken,
        resourcePath: "/v2/posts",
        entity: {
            "shareCommentary": {
                "text": "Hello World! This is my first Share on LinkedIn!"
            },
            "shareMediaCategory": "NONE"
        }
    })
shimizust commented 1 year ago

Hi @ozorOzora , one thing I see to at least get past this error is the resourcePath should not include the "/v2" prefix. So if you're trying to hit the "posts" endpoint, it would just be resourcePath: "/posts". The prefix is different depending on whether you are using non-versioned or versioned APIs, so it is handled by the client.

ozorOzora commented 1 year ago

Hi @shimizust, thank you for your quick response! Unfortunately the error is still the same with resourcePath: "/posts".

Maybe it comes from the entity property? As per the restli-client.d.ts file, entity should be of type Record<string, any> , which is very limited information.

shimizust commented 1 year ago

@ozorOzora This client is intentionally pretty generic, so it doesn't provide interfaces for specific APIs (only at the Rest.li protocol level). The documentation for the Share on LinkedIn product seems lacking for the /posts endpoint, so I will file a ticket with that team.

In the meantime, I think this page has information on the /posts API. While this is for an ads api product, it uses the same permission (w_member_social) as provided by Share on LinkedIn. Not all of it is completely applicable--for example, with w_member_social only, you would only be able to post on behalf of an authenticated member as opposed to an organization.

shimizust commented 1 year ago

@ozorOzora Got a chance to try the /posts API. Here is a working example. You will need a member-based token using the permissions provided by the Sign in with LinkedIn and Share on LinkedIn API products.

I will add this as an example soon, as this is probably a pretty common use case.

The /ugcPosts API is an older, legacy API. The new /posts API is a bit more streamlined and easier to use, as you can see below.

Hope that helps!

async function main() {
  /**
   * First get the authenticated member's profile to get the person URN id.
   */
  let meResponse = await restliClient.get({
    resourcePath: '/me',
    accessToken: MEMBER_POST_ACCESS_TOKEN,
  });
  console.log(meResponse.data);

  /**
   * Calling the legacy /ugcPosts API to create a text post on behalf of the member
   */
  let ugcPostsCreateResponse = await restliClient.create({
    resourcePath: '/ugcPosts',
    entity: {
      author: `urn:li:person:${meResponse.data.id}`,
      lifecycleState: 'PUBLISHED',
      specificContent: {
        'com.linkedin.ugc.ShareContent': {
          shareCommentary: {
              text: 'Sample text post created with /ugcPosts API'
          },
          shareMediaCategory: 'NONE'
        }
      },
      visibility: {
        'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC'
      }
    },
    accessToken: MEMBER_POST_ACCESS_TOKEN
  });
  // This is the share URN
  console.log(ugcPostsCreateResponse.createdEntityId);

  /**
   * Calling the newer, more streamlined (and versioned) /posts API to create a text post on behalf of the member
   */
  let postsCreateResponse = await restliClient.create({
    resourcePath: '/posts',
    entity: {
      author: `urn:li:person:${meResponse.data.id}`,
      lifecycleState: 'PUBLISHED',
      visibility: 'PUBLIC',
      commentary: 'Sample text post created with /posts API',
      distribution: {
        feedDistribution: 'MAIN_FEED',
        targetEntities: [],
        thirdPartyDistributionChannels: []
      }
    },
    accessToken: MEMBER_POST_ACCESS_TOKEN,
    versionString: '202302'
  });
  // This is the share URN
  console.log(postsCreateResponse.createdEntityId);
}

main();
shimizust commented 1 year ago

Added this example here: #21