Connect Reddit
The platform publishes approved post drafts to Reddit the same way it posts to
X and LinkedIn: a draft targets a connected account, and the publish worker
submits it via Reddit’s API.
Reddit differs from the other social destinations in one product-shaped way:
a connection is the signed-in user’s own account, not one of viite’s shared
company identities. So the connect provider is owner-principal (like YouTube),
not admin — connecting does not require being named in ADMIN_EMAILS, and
onboarding a customer is not a redeploy.
1. Register the Reddit app (one time)
Section titled “1. Register the Reddit app (one time)”At https://www.reddit.com/prefs/apps, create an app:
| Field | Value |
|---|---|
| type | web app — not “installed app”. A web app is a confidential client, which is what the token endpoint’s HTTP Basic auth needs. |
| redirect uri | https://platform-api.viite.ai/api/connect/reddit/callback — byte-for-byte. Add http://127.0.0.1:3000/api/connect/reddit/callback as well for local development. |
The app is owned by whichever Reddit account registers it (viite’s is u/Viite-ai).
That account is not a credential and not the posting identity — it is just
the owner of record. Users connect their own accounts against it.
Then set three environment variables (see Environment variables):
REDDIT_CLIENT_ID=...REDDIT_CLIENT_SECRET=...REDDIT_OAUTH_REDIRECT_URI=https://platform-api.viite.ai/api/connect/reddit/callbackUntil all three are set — plus SOCIAL_TOKEN_ENCRYPTION_KEY — the provider stays
dormant: it is not registered, Reddit does not appear on /channels/new, and
no publisher is built.
2. Connect an account
Section titled “2. Connect an account”On Channels → Add a channel, pick Post, then Reddit. The OAuth dance
stores an encrypted token on a post://@<handle>@reddit.com connector row, and
the account shows up as a destination for new post drafts.
The requested scopes are identity, submit, read, flair. read and flair are
not used yet and are requested anyway on purpose: Reddit issues a token against
the scopes granted at consent time and a refresh preserves that grant — it
does not pick up scopes added later. Widening the set afterwards would force every
already-connected user to disconnect and reconnect.
3. Where a post lands
Section titled “3. Where a post lands”Every Reddit submission names a target subreddit. A draft may name one in its
subreddit field (the Subreddit card on the draft editor); absent that, the
post goes to the connected account’s own profile subreddit, u_<handle> —
which every Reddit account has. That default is what makes a freshly connected
account publishable with no further configuration.
Both forms are accepted in the field: typescript and r/typescript.
Community rules still apply and are enforced by Reddit, not by us: a subreddit that requires post flair, blocks link-heavy posts, or does not accept your account rejects the submission at publish time and the card returns with the reason.
4. What gets submitted
Section titled “4. What gets submitted”- Always a self (text) post. A Reddit link submission carries a URL and no body, and the composer already embeds the source URL inside the composed text — so a link submission would publish a bare URL and discard the post that was written and reviewed. The URL rides in the selftext instead.
- A title is required. Reddit rejects a submission without one; the draft’s title is used, and publishing refuses before spending a request if it is blank.
- No media. Reddit’s image upload is a separate asset flow and is not
implemented, so the
redditdestination declaresimage: 'none'/video: 'none'and the draft editor offers no picker. - Body cap: 40 000 characters (Reddit’s selftext limit). The composer is steered to a much shorter 10 000.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
| Reddit missing from the channel picker | One of the three REDDIT_* vars (or SOCIAL_TOKEN_ENCRYPTION_KEY) is unset, so the provider never registered. Check GET /api/connect/status. |
| Works for an hour, then “no refresh token is stored” | The grant was not permanent — reconnect the account once the authorize URL carries duration=permanent. |
403 or 429 on every call | A generic User-Agent. Reddit requires a descriptive one; REDDIT_USER_AGENT is sent on every request including the token endpoint. |
| “Reddit submit rejected: SUBREDDIT_NOTALLOWED” | The account cannot post in that subreddit — wrong name, private community, or unmet karma/age requirements. |
