Reference

Commands

Seven commands do the real work. Everything else exists because the generator emitted it, and you will never need it.

Command What it does
postCreate a post and record it locally.
historyEvery post recorded locally, newest first.
searchFull-text search over your own post bodies.
forgetRemove a post from your local history only.
unpublishDelete the post on LinkedIn, then from local history. Irreversible.
authLogin, logout, status.
doctorConfig, credential, and connectivity check.
userinfoPrint your app-scoped member ID. See the note below.

You do not need images. It exists, but post --image already uploads and attaches in one step, and images on its own wants raw headers spelled out. Same for userinfo: it works, but it prints an identifier you never type yourself.

post

postiee post "some text"
postiee post --file post.md
postiee post "with a picture" --image chart.png --alt "a line chart"
postiee post "connections only" -v CONNECTIONS
FlagMeaning
--fileRead the body from a file. Avoids shell quoting entirely.
--imageAttach one image. JPG, PNG, or GIF. One, not many — see the note below.
--altAlt text for that image.
-v, --visibilityPUBLIC, CONNECTIONS, or LOGGED_IN. Defaults to PUBLIC.

Prefer --file for anything long. Quoting a multi-line post through a shell is how you end up with mangled apostrophes.

One image only. --image takes a single file, and that is the whole of what a self-serve app can attach. Multi-image posts and video both need LinkedIn partner approval, so there is no flag for them. See Limits and scope.

history

postiee history
postiee history --limit 200

Reads only the local database. No network call, no rate-limit cost. --limit defaults to 50.

search

postiee search harness
postiee search "harness agent" --json

Terms are ANDed, so more words narrow the result. Porter stemming is on — authentic finds authentication. --limit defaults to 25.

Whole words only. SQLite FTS5 indexes complete tokens, so postiee search harn will not find harness. Type the full word. This is documented rather than worked around, because a search that quietly returns nothing is worse than one that states where it stops.

Search covers posts made through postiee on this machine. Anything you posted from LinkedIn's app or website is invisible to every API, including this one.

forget

postiee forget urn:li:ugcPost:12345

Removes the post from your local history and from the search index. Take the URN from history.

This is local only. forget deletes your record, not the post. To take a post down on LinkedIn itself, use unpublish, below. That is the one write that cannot be undone.

unpublish

postiee unpublish urn:li:share:12345

Deletes the post on LinkedIn, then removes it from your local history. Both halves, in that order — if LinkedIn refuses the delete, the local row stays so the post is still findable and you can retry.

This cannot be undone. There is no trash, and no API can read a post back afterwards to reconstruct it. Take the URN from history and check it before you run the command.

--dry-run reports what it would do and stops there.

auth and doctor

postiee auth login --port 8085
postiee auth status
postiee auth logout
postiee doctor

doctor is the one to run first when something looks wrong. It reports where it found your config and credentials, whether a token is loaded, and whether api.linkedin.com answers.

Tokens last 60 days. Automatic refresh is partner-only, so an expired token means one more auth login. If you are still signed in to LinkedIn the consent screen is skipped and it takes seconds. The login window stays open 15 minutes, which covers a password, a 2FA prompt, and an emailed code.

Agent mode

postiee --agent search harness

Sets --json --compact --no-input --no-color together. Use it whenever anything is parsing the output.

Environment variables

VariableEffect
POSTIEE_SCOPES Override the requested OAuth scopes. Useful during setup if Sign In with LinkedIn isn't added yet.
POSTIEE_REDIRECT_URI Override the redirect host spelling. Must match your app's registration exactly.
POSTIEE_TOKEN Use a specific access token instead of the stored one.
POSTIEE_HISTORY_DB Point the history database somewhere else.
POSTIEE_CONFIG Use a specific config file instead of the default location.

Troubleshooting

Most of these fail the same way: LinkedIn answers 401 or 403 with a short reason, and postiee passes it through. Match the first line of the error here.

What you see Why What to do
unauthorized_scope_error Your app wasn't granted a scope postiee asked for. Share on LinkedIn gives w_member_social; Sign In with LinkedIn gives openid and profile. Both are needed. Open Products on your developer app and add whichever is missing. If you're mid-setup and just want to post text, set POSTIEE_SCOPES=w_member_social to skip the rest.
redirect_uri does not match the registered value LinkedIn compares redirect URLs as exact strings — host, port, path, trailing slash. localhost and 127.0.0.1 are different values to it, and postiee sends 127.0.0.1 by default. Copy the exact string from your app's Auth tab into POSTIEE_REDIRECT_URI, or re-register http://127.0.0.1:8085/callback. auth login prints the URI it is sending, so you can compare them directly.
403 from /v2/userinfo The token has no openid. Either the product was just added and hasn't propagated, or you logged in before adding it. Add Sign In with LinkedIn, then auth logout and auth login again. A fresh token is required; the old one won't gain the scope.
422 from /rest/posts, mention of author The member URN couldn't be resolved, which means the same missing openid. It is never a bad post body. Same fix as the row above. Add the product, then re-login.
state mismatch The callback that arrived carried a different state than the one this run generated — a stale login tab, or two logins racing. Run auth login again and use only the URL it prints this time. Don't reuse a tab from an earlier attempt.
no access token found No token on disk, or the one there has expired. Tokens last 60 days and can't be refreshed without partner access. Run auth login. Confirm with auth status.
401 from any endpoint, on a token that worked yesterday The 60 days are up. Run auth login. Nothing was lost — the local history is a file on your disk, not a LinkedIn-side record.
Search finds nothing for a word you can see in the text FTS5 matches whole tokens. harn doesn't match harness. Search the full word. Stemming handles endings — authentic finds authentication.
Search finds nothing and the word is complete The post was made somewhere other than postiee. Only posts postiee wrote are in the index. Nothing to fix. LinkedIn exposes no API for reading posts you made in its own app.
Something fails only in a loop or a script You've used up the daily budget: 150 requests per member per day. One post is one request. Wait until the budget resets. history and search are local and never count against it.