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/meworks ✅) - 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_socialpermission
My questions:
- Do I need to request additional permissions (e.g.,
w_organization_social) to post as a company page? - Is this error caused because I’m using a personal access token instead of an organization-admin token?
- 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.
-
1in question (not in comment) you could add link to API documentation.furas– furas2025年10月07日 11:46:43 +00:00Commented Oct 7, 2025 at 11:46