1

I'm trying to post a job description to LinkedIn using their ugcPosts API through my Flask backend.

I’ve successfully obtained a 3-legged OAuth 2.0 access token with w_member_social scope.
Token works fine — it’s active and returns 200 when I call:

curl -H "Authorization: Bearer <ACCESS_TOKEN>" https://api.linkedin.com/v2/me

However, when I try to post using the following Python code, I get a 403 ACCESS_DENIED error.

My request code:

payload = {
 "author": "urn:li:organization:123456789", # my company URN
 "lifecycleState": "PUBLISHED",
 "specificContent": {
 "com.linkedin.ugc.ShareContent": {
 "shareCommentary": {
 "text": f"🚀 {jd.job_title} at {jd.company_name}\n\n{jd.description}"
 },
 "shareMediaCategory": "NONE"
 }
 },
 "visibility": {
 "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
 }
}
headers = {
 "Authorization": f"Bearer {token.access_token}",
 "Content-Type": "application/json"
}
response = requests.post(
 "https://api.linkedin.com/v2/ugcPosts",
 json=payload,
 headers=headers
)
print(response.status_code, response.text)

Error received:

{
 "status":403,
 "serviceErrorCode":100,
 "code":"ACCESS_DENIED",
 "message":"Field Value validation failed in REQUEST_BODY: Data Processing Exception while processing fields [/author]"
}

What I’ve tried:

  • Verified access token is valid (GET /v2/me works ✅)
  • Used company URN (urn:li:organization:123456789) from the LinkedIn company page
  • Tried both company and personal URNs (urn:li:person:<id>)
  • Confirmed app has the w_member_social permission

My questions:

  1. Do I need to request additional permissions (e.g., w_organization_social) to post as a company page?
  2. Is this error caused because I’m using a personal access token instead of an organization-admin token?
  3. How can I correctly get an organization access token that allows posting to a company page?

Environment:

  • Python 3.9
  • Flask backend
  • LinkedIn API (v2)

This is the error I got

ERROR:app.middleware.error_handlers:Error 400 on POST /api/job-description/post/linkedin/df7d7d57-624f-44e7-9d37-3a043b118db5: 
Traceback (most recent call last):
 File "D:\ntdp_backend\app\api\routes\job_description_routes.py", line 95, in post_jd_linkedin
 result = service.post_jd_to_linkedin(jd_id, user_email)
 File "D:\ntdp_backend\app\services\job_description_service.py", line 243, in post_jd_to_linkedin
 raise ValueError(f"LinkedIn posting failed: {response.text}")
ValueError: LinkedIn posting failed: {"status":403,"serviceErrorCode":100,"code":"ACCESS_DENIED","message":"Field Value validation failed in REQUEST_BODY: Data Processing Exception while processing fields [/author]"}
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
 File "D:\ntdp_backend\venv\lib\site-packages\starlette\middleware\exceptions.py", line 68, in __call__
 await self.app(scope, receive, sender)
 File "D:\ntdp_backend\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 20, in __call__
 raise e
 File "D:\ntdp_backend\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 17, in __call__
 await self.app(scope, receive, send)
 File "D:\ntdp_backend\venv\lib\site-packages\starlette\routing.py", line 718, in __call__
 await route.handle(scope, receive, send)
 File "D:\ntdp_backend\venv\lib\site-packages\starlette\routing.py", line 276, in handle
 await self.app(scope, receive, send)
 File "D:\ntdp_backend\venv\lib\site-packages\starlette\routing.py", line 66, in app
 response = await func(request)
 File "D:\ntdp_backend\venv\lib\site-packages\fastapi\routing.py", line 274, in app
 raw_response = await run_endpoint_function(
 File "D:\ntdp_backend\venv\lib\site-packages\fastapi\routing.py", line 193, in run_endpoint_function
 return await run_in_threadpool(dependant.call, **values)
 File "D:\ntdp_backend\venv\lib\site-packages\starlette\concurrency.py", line 41, in run_in_threadpool
 return await anyio.to_thread.run_sync(func, *args)
 File "D:\ntdp_backend\venv\lib\site-packages\anyio\to_thread.py", line 33, in run_sync
 return await get_asynclib().run_sync_in_worker_thread(
 File "D:\ntdp_backend\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 877, in run_sync_in_worker_thread
 return await future
 File "D:\ntdp_backend\venv\lib\site-packages\anyio\_backends\_asyncio.py", line 807, in run
 result = context.run(func, *args)
 File "D:\ntdp_backend\app\api\routes\job_description_routes.py", line 98, in post_jd_linkedin
 raise HTTPException(status_code=400, detail=str(e))
fastapi.exceptions.HTTPException
INFO: 127.0.0.1:52513 - "POST /api/job-description/post/linkedin/df7d7d57-624f-44e7-9d37-3a043b118db5?user_email=sheezarafique266%40gmail.com HTTP/1.1" 400 Bad Request

I tried generating a LinkedIn OAuth URL using my Flask backend function generate_linkedin_oauth_url(user_email) to connect a user’s LinkedIn account. I expected LinkedIn to show an authorization screen so I could log in and get an authorization code in the callback URL.

furas
149k12 gold badges121 silver badges171 bronze badges
asked Oct 7, 2025 at 11:30
1
  • 1
    in question (not in comment) you could add link to API documentation. Commented Oct 7, 2025 at 11:46

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.