Post to LinkedIn with Node.js
A working Node.js example that posts to LinkedIn via the PostGate API using fetch.
Post to LinkedIn with Node using the built-in fetch (Node 18+): connect a profile once through PostGate's hosted OAuth, keep POSTGATE_API_KEY in a server-side environment variable, then send POST /api/posts with the profile ID, post body, visibility under post.options.linkedin, and a stable Idempotency-Key. Confirm delivery via the targets array on GET /api/posts/{id}.
This uses Node's built-in fetch (Node 18+) against POST /api/posts directly — no dependency required. PostGate does generate a typed Node.js/TypeScript client from its OpenAPI contract (see SDKs & MCP), but the published npm package name for it isn't documented publicly, so this guide sticks to the REST contract itself. For the general Node.js setup, see the Node.js quickstart.
Step 1 — Connect a LinkedIn profile
Through PostGate's hosted OAuth, the customer authorizes LinkedIn access once from a URL your backend creates with POST /api/profiles/connect; PostGate stores and refreshes the resulting token, so your Node backend never handles LinkedIn credentials directly. See Profiles & connections.
Step 2 — Keep the API key server-side
Read the key from a plain server environment variable — never one prefixed for client bundling, such as Next.js' NEXT_PUBLIC_ convention. Use a pg_test_ key while you build; it runs the complete lifecycle against a sandbox adapter without publishing anything real. See Authentication.
POSTGATE_API_KEY=pg_test_...Step 3 — Send the request
Attach the connected LinkedIn profile ID, the post body, and an explicit visibility under post.options.linkedin, with a stable Idempotency-Key so a dropped connection and a retry never post twice — see Idempotency & safe retries and platform-specific options.
const API_URL = "https://postgate.studio";
const API_KEY = process.env.POSTGATE_API_KEY!;
const response = await fetch(`${API_URL}/api/posts`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "li-launch-004",
},
body: JSON.stringify({
post: {
body: "We just shipped something.",
options: {
linkedin: { visibility: "PUBLIC" },
},
},
profiles: ["pro_linkedin456"],
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message}`);
}
const post = await response.json();
console.log(post.id, post.status);Step 4 — Confirm delivery, do not assume it
The create response is acceptance, not proof of publication. Read GET /api/posts/{id} and look at the targets array — a published target carries LinkedIn's own post ID and permalink. For production traffic, subscribe to the post.published / post.partial / post.failed webhooks instead of polling — see the full delivery lifecycle.
const statusResponse = await fetch(`${API_URL}/api/posts/${post.id}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const status = await statusResponse.json();
for (const target of status.targets) {
console.log(target.platform, target.status, target.permalink);
}Step 5 — Handle the failure paths you will actually hit
A failed target returns a structured error with a stable code and a retryable flag — see errors & retries. profile_disconnected means LinkedIn revoked or expired the token and the customer needs to reconnect. Only retry when retryable is true, reusing the same Idempotency-Key.
Frequently asked questions
Do I need an npm package to post to LinkedIn from Node.js?
No dependency is required — Node's built-in fetch (Node 18+) against POST /api/posts is enough. PostGate does generate a typed Node.js/TypeScript client from its OpenAPI contract, but the published npm package name for it is not documented publicly, so the REST contract itself is the path guaranteed to match what ships.
Does my Node backend need to handle LinkedIn credentials?
No. Through PostGate's hosted OAuth, the customer authorizes LinkedIn access once from a URL your backend creates with POST /api/profiles/connect. PostGate stores and refreshes the resulting token, so your Node backend never handles LinkedIn credentials directly.
How do I test posting to LinkedIn without publishing anything real?
Use a pg_test_ key while you build — it runs the complete lifecycle against a sandbox adapter without publishing anything real. Read the key from a plain server environment variable, never one prefixed for client bundling such as Next.js' NEXT_PUBLIC_ convention.
When should I retry a failed LinkedIn post from Node?
Only when the structured error's retryable flag is true, reusing the same Idempotency-Key so the retry never posts twice. profile_disconnected means LinkedIn revoked or expired the token and the customer needs to reconnect — a retry alone will not fix that.
