REST API · v1

Reoogle API Reference

Programmatic access to Reoogle's database of 25,000+ monitored subreddits. Filter by activity, posting safety, mod status, member count, and language — or use /postable to instantly surface communities where you can drop links without them being removed.

Base URL

https://reoogle.com/api/v1

Protocol

HTTPS only

Format

JSON

Auth

Bearer token

Rate limit

60 req / min

Introduction

The Reoogle API is a REST interface that gives you programmatic access to our database of 25,000+ monitored subreddits. Query by moderator activity status, membership size, category, engagement patterns, and posting safety — or use the /postable shortcut to instantly surface communities where links survive.

All endpoints return JSON. All requests must be made over HTTPS. Authentication is via a Bearer token included in the Authorization header. The API follows predictable RESTful conventions — standard HTTP verbs, consistent error envelopes, and cursor-free pagination.

Every subreddit in the database is continuously refreshed. The last_checked and activity_checked_at timestamps on each record tell you exactly how fresh the data is.

New to the API? Jump to Integration Examples to see real-world usage patterns in Node.js, Python, and Next.js before reading the full reference.

Authentication

Every request to a data endpoint must include an API key as a Bearer token in the Authorization header. Generate and manage keys from your Developer dashboard. Keys are prefixed with rog_live_ so they are easy to identify in logs.

http
Authorization: Bearer rog_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key security & storage

The full key is shown only once, immediately after creation — copy it to a secure location such as a password manager or secrets vault. Reoogle stores only a SHA-256 hash of the key; the plaintext cannot be recovered after that initial display. If a key is compromised, revoke it immediately from the dashboard and generate a replacement.

Never expose API keys in client-side JavaScript, public git repositories, or browser requests. Always keep keys in server-side environment variables. If you accidentally commit a key, revoke it immediately.

Verify your key works

The fastest way to confirm a key is valid is to call the /me/usage endpoint. A 200 response means the key is active and you are authenticated. A 401 means the key is missing, malformed, or revoked.

bash
# Verify your key with a minimal request
curl https://reoogle.com/api/v1/me/usage \
  -H "Authorization: Bearer rog_live_xxxxxxxxxx"

# Expected 200 response:
# { "key_name": "Production", "limits": { ... }, "recent_requests": [...] }

Rate Limiting

Each API key is subject to two independent limits:

Per-minute limit

60 requests / min

Resets every 60-second window

Per-day limit

1,000 requests / day

Resets at 00:00 UTC

Limits are tracked per key, not per account or IP address. Every response includes rate-limit headers so your client can proactively back off before hitting the limit:

http
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1750000000   # Unix timestamp when the 60s window resets
X-RateLimit-Daily-Limit: 1000
X-RateLimit-Daily-Remaining: 952

When either limit is exceeded, the API returns 429 Too Many Requests and includes a Retry-After header (in seconds) indicating how long to wait. In production, always implement exponential back-off rather than polling at a fixed interval:

javascript
0
async function fetchWithBackoff(url, options, retries = 4) {
  const res = await fetch(url, options);

  if (res.status === 429 && retries > 0) {
    const retryAfter = Number(res.headers.get(1) ?? 1);
    const jitter     = Math.random() * 500; 2
    await new Promise((r) => setTimeout(r, retryAfter * 1000 + jitter));
    return fetchWithBackoff(url, options, retries - 1);
  }

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err?.error?.message ?? 3);
  }

  return res;
}

Need higher limits? Contact info@reoogle.com — enterprise plans with custom rate limits are available.

Errors

All errors use a consistent JSON envelope with two fields: a machine-readable code (safe to switch on in your code) and a human-readable message (suitable for logging, never show to end users).

json
// All error responses follow this shape
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit of 60 requests/minute exceeded. Retry after 12 seconds."
  }
}

// Successful responses never include an "error" key
{
  "data": [ ... ],
  "pagination": { ... }
}

Check the HTTP status code first, then branch on error.code for fine-grained handling. The message field may change between releases; always use code for logic.

StatusTextError codeMeaning
200OKsuccessRequest succeeded
400Bad Requestinvalid_requestInvalid parameters or body
401Unauthorizedinvalid_api_keyMissing, malformed, or revoked key
404Not Foundnot_foundResource does not exist
429Too Many Requestsrate_limitedRate limit exceeded
500Internal Server Errorinternal_errorUnexpected server error

Subreddits

GET/api/v1/subreddits

Return a paginated list of subreddits matching the given filters.

ParameterTypeDescription
searchstringPartial match on subreddit name (case-insensitive)
categorystringExact match on primary_category
min_membersintegerMinimum member count (inclusive)
max_membersintegerMaximum member count (inclusive)
inactive_modsbooleantrue — only subreddits with inactive moderators
has_moderatorsbooleantrue — only subreddits that have at least one mod
restrict_postingbooleanfalse — exclude subs that require approval to post
allows_linksbooleantrue — only subs whose submission_type allows links
link_posts_survivebooleantrue — only subs where promotional/link posts are not deleted
over18booleantrue/false — include or exclude NSFW subreddits
langstringFilter by subreddit language code (e.g. "en")
min_posts_60dintegerMinimum number of posts in the last 60 days
min_avg_commentsfloatMinimum average comments per post
sort_bymembers | last_checked | activity | avg_commentsSort field (default: members)
orderasc | descSort direction (default: desc)
pageintegerPage number, 1-indexed (default: 1)
per_pageintegerResults per page, max 100 (default: 25)

Response fields

ParameterTypeDescription
idstringUUID
namestringSubreddit name (without r/)
member_countintegerSubscriber count
titlestringSubreddit display title
descriptionstringPublic description
icon_imgstringIcon image URL (HD)
banner_imgstringBanner image URL
over18booleanNSFW flag
subreddit_typestring"public" | "restricted" | "private"
restrict_postingbooleanRequires approval/request to post
allows_linksbooleansubmission_type allows external links
link_posts_survivebooleanPromotional/link posts survive mod review
posts_last_60dintegerPosts published in the last 60 days
avg_commentsfloatAverage comments per post (last 60d)
unique_posters_60dintegerUnique authors in the last 60 days
activity_checked_atstringISO timestamp of the last activity scan
langstringSubreddit language code
inactive_modsbooleanModerators are not actively enforcing rules
last_checkedstringISO timestamp of the last refresh

Example

bash
# Active English subs where you can drop links — sorted by most active
curl "https://reoogle.com/api/v1/subreddits?inactive_mods=true&allows_links=true&link_posts_survive=true&lang=en&min_posts_60d=5&sort_by=activity&per_page=10" \
  -H "Authorization: Bearer rog_live_..."
json
{
  "data": [
    {
      "id": "664f9a4a-...",
      "name": "Pacific_Islanders",
      "member_count": 440,
      "title": "Pacific Islanders",
      "icon_img": "https://styles.redditmedia.com/...",
      "over18": false,
      "subreddit_type": "public",
      "restrict_posting": false,
      "allows_links": true,
      "link_posts_survive": true,
      "posts_last_60d": 18,
      "avg_comments": 4.2,
      "unique_posters_60d": 11,
      "inactive_mods": true,
      "last_checked": "2026-06-25T08:00:00Z",
      "activity_checked_at": "2026-06-25T08:01:12Z"
    }
  ],
  "pagination": { "page": 1, "per_page": 10, "total": 3820, "total_pages": 382 }
}
GET/api/v1/subreddits/{name}

Full details for a single subreddit, including its current moderator list.

bash
curl "https://reoogle.com/api/v1/subreddits/Pacific_Islanders" \
  -H "Authorization: Bearer rog_live_..."
json
{
  "id": "664f9a4a-...",
  "name": "Pacific_Islanders",
  "member_count": 440,
  "restrict_posting": false,
  "allows_links": true,
  "link_posts_survive": true,
  "posts_last_60d": 18,
  "avg_comments": 4.2,
  "moderators": [
    {
      "username": "AutoModerator",
      "reddit_user_id": "t2_6l4z3",
      "mod_since": 1483228800,
      "mod_permissions": ["all"],
      "last_checked": "2026-06-25T08:01:12Z"
    }
  ]
}
GET/api/v1/subreddits/{name}/activity

Hour-of-day and day-of-week engagement data — the source for best-posting-time insights.

json
{
  "subreddit": "Pacific_Islanders",
  "activity": [
    { "day_of_week": "monday", "utc_hour": 17, "posts": 4, "comments": 12, "engagement": 41, "last_updated": "2026-06-23T00:00:00Z" }
  ]
}

Postable Subreddits

The /postableendpoint is Reoogle's highest-value query: it returns subreddits where you can submit content without needing approval and where promotional or link posts are not being removed by moderators. Three criteria are enforced automatically:

Inactive mods

Moderators are not actively monitoring or enforcing rules

Open posting

No approval required — anyone with an account can submit

Links survive

Promotional or link posts are not deleted (or unconfirmed)

GET/api/v1/subreddits/postable

Subreddits with inactive mods, open posting, and surviving link/promo posts.

ParameterTypeDescription
min_membersintegerMinimum member count (default: 100)
max_membersintegerMaximum member count
min_posts_60dintegerMinimum posts in last 60 days (activity floor)
min_avg_commentsfloatMinimum average comments per post
over18booleantrue/false — NSFW filter
langstringLanguage code filter (e.g. "en")
categorystringExact primary_category match
sort_bymembers | activity | avg_commentsSort field (default: activity)
orderasc | descSort direction (default: desc)
pageinteger(default: 1)
per_pageintegermax 100 (default: 25)

Example

bash
# Top 20 active English subs — ready to post in
curl "https://reoogle.com/api/v1/subreddits/postable?lang=en&min_posts_60d=3&sort_by=activity&per_page=20" \
  -H "Authorization: Bearer rog_live_..."
python
import requests

resp = requests.get(
    0,
    params={1: 2, 3: 3, 4: 5, 6: 20},
    headers={7: 8},
)
for sub in resp.json()[9]:
    print(f10)
json
{
  "data": [ ... ],
  "pagination": { "page": 1, "per_page": 20, "total": 1240, "total_pages": 62 },
  "filters_applied": {
    "inactive_mods": true,
    "restrict_posting": false,
    "link_posts_survive": "true_or_unknown"
  }
}

link_posts_survive: "true_or_unknown" means the endpoint includes subreddits where promotional posts are confirmed to survive AND subreddits not yet scanned (benefit of the doubt). Add link_posts_survive=true to the base /subreddits endpoint if you only want confirmed results.

Moderators

Retrieve the full moderator list for any subreddit in the database. Moderator data is refreshed periodically alongside the subreddit refresh cycle.

GET/api/v1/subreddits/{name}/moderators

List all moderators for a subreddit with their permissions and tenure.

bash
curl "https://reoogle.com/api/v1/subreddits/Pacific_Islanders/moderators" \
  -H "Authorization: Bearer rog_live_..."
json
{
  "subreddit": "Pacific_Islanders",
  "count": 2,
  "moderators": [
    {
      "username": "AutoModerator",
      "reddit_user_id": "t2_6l4z3",
      "mod_since": 1483228800,
      "mod_permissions": ["all"],
      "last_checked": "2026-06-25T08:01:12Z"
    },
    {
      "username": "some_inactive_user",
      "reddit_user_id": "t2_abc123",
      "mod_since": 1514764800,
      "mod_permissions": ["posts", "flair"],
      "last_checked": "2026-06-25T08:01:12Z"
    }
  ]
}
ParameterTypeDescription
usernamestringReddit username
reddit_user_idstringReddit internal user ID (t2_...)
mod_sinceintegerUnix timestamp when they became moderator
mod_permissionsstring[]"all" or granular: ["posts", "wiki", "flair", "mail", "config", "access"]
last_checkedstringISO timestamp of the last moderator data sync
GET/api/v1/search

Combined search across all filter dimensions. Recommended when combining multiple criteria in a single query.

Accepts all the same query parameters as /subreddits (including the new activity and posting-safety filters) and returns an identical response shape.

Both /subreddits and /search hit the same underlying index. Prefer /search when combining three or more filters for readability.

Categories

GET/api/v1/categories

Return all distinct subreddit categories and the count of subreddits in each.

json
{
  "data": [
    { "category": "Gaming",      "count": 1820 },
    { "category": "Technology",  "count": 1340 },
    { "category": "General",     "count": 9180 }
  ]
}

Usage

GET/api/v1/me/usage

Return rate-limit consumption and a log of your 20 most recent requests for the calling key.

json
{
  "key_name": "Production",
  "limits": {
    "per_minute": { "limit": 60, "used": 3, "resets_at": "2026-06-24T12:01:00Z" },
    "per_day":    { "limit": 1000, "used": 48, "resets_at": "2026-06-25T00:00:00Z" }
  },
  "recent_requests": [
    {
      "timestamp": "2026-06-24T11:59:43Z",
      "method": "GET",
      "path": "/api/v1/subreddits",
      "status": 200,
      "duration_ms": 34
    }
  ]
}

Webhooks

Webhooks let you receive an HTTP POST to your endpoint whenever an event occurs in Reoogle. Configure webhooks from your Developer dashboard — each webhook has its own signing secret.

Event types

Event typeFires whenKey payload fields
subreddit.detectedA new subreddit enters the database{ name, member_count, categories }
activity.changedA favorited subreddit's engagement shifts >20%{ subreddit, delta_pct, engagement }
mods.inactiveA subreddit transitions to inactive moderators{ subreddit, member_count }

Request format

http
POST <your-endpoint-url>
Content-Type: application/json
X-Reoogle-Signature: <hmac-sha256-hex>
X-Reoogle-Event: mods.inactive
X-Reoogle-Delivery: a1b2c3d4-...

{
  "event": "mods.inactive",
  "timestamp": "2026-06-23T16:00:00Z",
  "data": {
    "subreddit": "Pacific_Islanders",
    "member_count": 440
  }
}

Verifying signatures

Compute HMAC-SHA256 of the raw request body using your webhook secret and compare it to the X-Reoogle-Signature header. Always use a timing-safe comparison to prevent timing attacks.

javascript
import crypto from 0;

function verifySignature(rawBody: Buffer, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac(1, secret)
    .update(rawBody)
    .digest(2);

  3
  return crypto.timingSafeEqual(
    Buffer.from(signature, 4),
    Buffer.from(expected, 5)
  );
}

6
app.post(
  7,
  express.raw({ type: 8 }),
  (req, res) => {
    const sig = req.header(9) ?? 10;

    if (!verifySignature(req.body, sig, process.env.REOOGLE_WEBHOOK_SECRET!)) {
      return res.status(401).json({ error: 11 });
    }

    const event = JSON.parse(req.body.toString());
    console.log(12, event.event, event.data);
    res.sendStatus(200);
  }
);

Retry policy

Respond with any 2xx status to acknowledge delivery. Failed requests are retried up to 3 times with increasing delays:

1st
Immediate
2nd
30 seconds
3rd
5 minutes

After 10 consecutive failed deliveries, the webhook is automatically disabled and you receive an email. Re-enable it from the Developer dashboard once your endpoint is healthy.

AI Posts

Manage the Reddit posts generated by the Reoogle AI poster. You can list, retrieve, update and delete posts via the API — changes to the body of a text post are synced back to Reddit automatically.

GET /api/v1/ai-posts

Returns a paginated list of AI-generated posts for the authenticated user.

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerResults per page — max 100 (default: 20)
statusstringFilter by status: posted · pending · failed · removed
bash
curl https://reoogle.com/api/v1/ai-posts \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "data": [
    {
      "id": "uuid",
      "subreddit_name": "SaaS",
      "title": "Six months of cold outreach and the only thing that moved the needle was...",
      "body": "...",
      "post_type": "text",
      "status": "posted",
      "reddit_post_id": "t3_abc123",
      "reddit_post_url": "https://www.reddit.com/r/SaaS/comments/abc123/...",
      "score": 42,
      "upvote_ratio": 0.91,
      "comment_count": 7,
      "view_count": 1204,
      "posted_at": "2026-06-25T10:00:00Z",
      "last_checked_at": "2026-06-25T12:00:00Z"
    }
  ],
  "stats": {
    "total": 14,
    "posted": 11,
    "pending": 1,
    "failed": 1,
    "removed": 1,
    "avg_score": 18,
    "best_score": 42,
    "total_comments": 39
  },
  "page": 1,
  "per_page": 20,
  "total": 14
}

GET /api/v1/ai-posts/{id}

Returns a single post by its UUID.

bash
curl https://reoogle.com/api/v1/ai-posts/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "post": { "id": "uuid", "title": "...", "status": "posted" }
}

PATCH /api/v1/ai-posts/{id}

Updates the body of a post. For text posts, the new body is also pushed to Reddit automatically. Note: Reddit does not allow title edits after publishing — only body can be changed.

ParameterTypeDescription
bodystringNew post body text (markdown). Required.
bash
curl -X PATCH https://reoogle.com/api/v1/ai-posts/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body": "Updated body content here."}'
json
{
  "post": { "id": "uuid", "body": "Updated body content here." },
  "reddit_synced": true,
  "reddit_error": null
}

reddit_synced is false if the Reddit token lacks the edit scope. In that case reddit_error will be "reconnect_required" — the user needs to reauthorise their Reddit account via the dashboard.

DELETE /api/v1/ai-posts/{id}

Deletes the post from Reoogle and attempts to remove it from Reddit using the connected account.

bash
curl -X DELETE https://reoogle.com/api/v1/ai-posts/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "success": true,
  "reddit_deleted": true
}

PUT /api/v1/ai-posts/{id}

Edits a pending-review post before publishing. Only works while status = pending_review. All three fields are optional — send only what you want to change.

ParameterTypeDescription
titlestringNew post title (max 300 chars)
bodystringNew post body text (markdown)
subreddit_namestringTarget subreddit — must be in your configured list
bash
curl -X PUT https://reoogle.com/api/v1/ai-posts/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Better title", "subreddit_name": "SaaS"}'
json
{
  "post": { "id": "uuid", "title": "Better title", "status": "pending_review" },
  "reddit_synced": false
}

POST /api/v1/ai-posts/{id}/approve

Immediately publishes a pending_review post to Reddit using the connected account. On success the post status changes to posted.

bash
curl -X POST https://reoogle.com/api/v1/ai-posts/POST_UUID/approve \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "ok": true,
  "post": {
    "id": "uuid",
    "status": "posted",
    "reddit_post_id": "t3_abc123",
    "reddit_post_url": "https://www.reddit.com/r/SaaS/comments/abc123/..."
  }
}

POST /api/v1/ai-posts/{id}/reject

Discards a pending_review post without publishing it. The post is marked deleted and removed from the approval queue.

bash
curl -X POST https://reoogle.com/api/v1/ai-posts/POST_UUID/reject \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{ "ok": true }
ParameterTypeDescription
postedLive on Reddit, visible to users
pending_reviewAI-generated, waiting for your approval
pendingQueued, will post at the scheduled time
failedPost attempt failed — see error_message field
removedRemoved by subreddit moderators
deletedDiscarded or deleted — excluded from list results

Image Upload

There are two ways to attach an image to a scheduled post. The simplest is to send the image file directly in the schedule request. Alternatively you can upload the image separately first and pass the returned URL.

Option A — attach image directly (recommended)

Send POST /api/v1/schedule as multipart/form-data. Include the image as the image field alongside the other post fields. The image is uploaded and the post is created in one request.

ParameterTypeDescription
titlestring (form-data)Post title — max 300 chars. Required.
subredditstring (form-data)Target subreddit with or without r/ prefix. Required.
scheduled_forstring (form-data)ISO 8601 UTC datetime — must be in the future. Required.
imageFile (form-data)Image file — JPEG, PNG, GIF or WebP, max 20 MB. Required for image posts.
bodystring (form-data)Post body text. Ignored when an image is attached.
bash
curl -X POST https://reoogle.com/api/v1/schedule \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -F "title=Check out our new dashboard" \
  -F "subreddit=indiehackers" \
  -F "scheduled_for=2026-07-10T14:00:00Z" \
  -F "image=@/path/to/screenshot.png"
json
// 201 Created
{
  "post": {
    "id": "uuid",
    "title": "Check out our new dashboard",
    "subreddit_name": "indiehackers",
    "scheduled_for": "2026-07-10T14:00:00.000Z",
    "status": "scheduled",
    "post_type": "link",
    "image_url": "https://reoogle.com/api/v1/images/uid_1751234567.png"
  }
}

Option B — upload separately, then schedule

Upload the image first via POST /api/v1/uploads, then pass the returned URL as image_url in a JSON schedule request. Useful when you want to reuse the same image across multiple posts.

POST/api/v1/uploads

Upload an image file and receive a hosted URL. Request must be multipart/form-data.

ParameterTypeDescription
fileFile (form-data)Image file — JPEG, PNG, GIF or WebP, max 20 MB. Required.
bash
# Step 1 — upload once
curl -X POST https://reoogle.com/api/v1/uploads \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -F "file=@screenshot.png"
# → { "url": "https://reoogle.com/api/v1/images/uid_1751234567.png" }

# Step 2 — reuse the URL in multiple schedule requests
curl -X POST https://reoogle.com/api/v1/schedule \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Check out our new dashboard",
    "subreddit": "indiehackers",
    "scheduled_for": "2026-07-10T14:00:00Z",
    "image_url": "https://reoogle.com/api/v1/images/uid_1751234567.png"
  }'

When an image is attached (either via the image file field or image_url), the post becomes a Reddit link post and the body field is ignored. Omit both to create a plain text post.

Schedule

Create, list, update, and cancel posts that are queued to be published at a specific future date and time. Scheduled posts are held in Reoogle until the scheduled_for time arrives, at which point the AI poster publishes them to Reddit using the connected account.

GET/api/v1/schedule

Return all posts currently queued, sorted by scheduled_for ascending.

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerResults per page — max 100 (default: 20)
bash
curl https://reoogle.com/api/v1/schedule \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "data": [
    {
      "id": "uuid",
      "title": "How I automated my Reddit presence without spamming",
      "body": "After 6 months of trial and error I found the approach that works…",
      "subreddit_name": "indiehackers",
      "scheduled_for": "2026-07-10T14:00:00.000Z",
      "status": "scheduled",
      "post_type": "text",
      "image_url": null,
      "created_at": "2026-07-04T09:00:00.000Z"
    }
  ],
  "page": 1,
  "per_page": 20,
  "total": 3
}
POST/api/v1/schedule

Queue a new post to be published at a specific future time.

ParameterTypeDescription
titlestringPost title — max 300 chars. Required.
subredditstringTarget subreddit with or without r/ prefix. Required.
scheduled_forstringISO 8601 UTC datetime — must be in the future. Required.
bodystringPost body text (text posts only). Optional.
image_urlstringImage / link URL — turns the post into a link post. Optional.
bash
curl -X POST https://reoogle.com/api/v1/schedule \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "How I automated my Reddit presence without spamming",
    "body": "After 6 months of trial and error I found the approach that works…",
    "subreddit": "indiehackers",
    "scheduled_for": "2026-07-10T14:00:00Z"
  }'
json
// 201 Created
{
  "post": {
    "id": "uuid",
    "title": "How I automated my Reddit presence without spamming",
    "body": "After 6 months of trial and error I found the approach that works…",
    "subreddit_name": "indiehackers",
    "scheduled_for": "2026-07-10T14:00:00.000Z",
    "status": "scheduled",
    "post_type": "text",
    "image_url": null,
    "created_at": "2026-07-04T09:00:00.000Z"
  }
}

Pass image_url to create a link post — the body field is ignored when an image URL is provided. Omit image_url (or leave it empty) for a standard text post.

GET/api/v1/schedule/{id}

Fetch a single scheduled post by its UUID.

bash
curl https://reoogle.com/api/v1/schedule/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "post": { "id": "uuid", "title": "…", "scheduled_for": "2026-07-10T14:00:00.000Z", "status": "scheduled" }
}

Returns 404 if the post has already been published (status changed from scheduled) or was cancelled.

PATCH/api/v1/schedule/{id}

Update any field of a scheduled post before it goes live. Send only the fields you want to change.

ParameterTypeDescription
titlestringNew title (max 300 chars)
bodystringNew body text
subredditstringNew target subreddit
scheduled_forstringNew ISO 8601 datetime — must be in the future
image_urlstringSet or clear the image/link URL
bash
# Reschedule to a different time
curl -X PATCH https://reoogle.com/api/v1/schedule/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scheduled_for": "2026-07-11T09:00:00Z" }'

# Change title and subreddit at the same time
curl -X PATCH https://reoogle.com/api/v1/schedule/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Better headline", "subreddit": "SaaSneeded" }'
json
{
  "post": {
    "id": "uuid",
    "title": "Better headline",
    "subreddit_name": "SaaSneeded",
    "scheduled_for": "2026-07-11T09:00:00.000Z",
    "status": "scheduled"
  }
}
DELETE/api/v1/schedule/{id}

Cancel a scheduled post. Returns 404 if the post has already been published.

bash
curl -X DELETE https://reoogle.com/api/v1/schedule/POST_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "success": true,
  "cancelled_id": "uuid"
}

No-Mod Subreddits

Returns subreddits that have been verified to have zero moderators. These are communities where enforcement is absent — useful for outreach, research, or identifying abandoned niches. Results are drawn from the main subreddit database (hasModerators = false) and are updated by the daily refresh job.

GET /api/v1/subreddits/unmoderated

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerResults per page — max 100 (default: 25)
searchstringFilter by subreddit name (partial match)
bash
curl "https://reoogle.com/api/v1/subreddits/unmoderated?limit=10" \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "subreddits": [
    {
      "id": "uuid",
      "name": "DigitalNomadHub",
      "member_count": 12400,
      "title": "Digital Nomad Hub",
      "icon_img": "https://...",
      "over18": false,
      "posts_last_60d": 8,
      "avg_comments": 3.2,
      "allows_links": true,
      "link_posts_survive": true
    }
  ],
  "total": 341,
  "page": 1,
  "limit": 10
}

Inbox

Access Reddit inbox messages collected by the Reoogle bot for the authenticated user — direct messages, comment replies, and subreddit mentions. Messages are synced every 30 minutes.

GET /api/v1/reddit/inbox

ParameterTypeDescription
limitintegerMax messages to return — max 50 (default: 25)
unreadbooleanIf true, return only unread messages
bash
curl "https://reoogle.com/api/v1/reddit/inbox?unread=true" \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "messages": [
    {
      "id": 1,
      "message_type": "comment_reply",
      "author": "redditor123",
      "subject": "re: My post title",
      "body": "Great post! How did you...",
      "subreddit": "SaaS",
      "reddit_link": "https://reddit.com/r/SaaS/comments/...",
      "is_read": false,
      "created_utc": 1751400000
    }
  ],
  "total": 4
}

PATCH /api/v1/reddit/inbox

Mark messages as read. Either pass an array of message ids or set mark_all: true to mark all unread messages at once.

bash
# Mark specific messages
curl -X PATCH https://reoogle.com/api/v1/reddit/inbox \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids": [1, 2, 3]}'

# Mark all as read
curl -X PATCH https://reoogle.com/api/v1/reddit/inbox \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mark_all": true}'
json
{ "ok": true }
ParameterTypeDescription
idsinteger[]Array of message IDs to mark as read
mark_allbooleanIf true, marks all messages as read (ignores ids)

DELETE /api/v1/reddit/inbox

Permanently delete one or more inbox messages. Pass an array of message ids — deleted messages are removed from the database and cannot be recovered.

ParameterTypeDescription
idsinteger[]Array of message IDs to permanently delete. Required.
bash
curl -X DELETE https://reoogle.com/api/v1/reddit/inbox \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids": [1, 2, 3]}'
json
{ "ok": true, "deleted": 3 }

Deletion is permanent — messages are removed from the database and cannot be recovered. Use PATCH with mark_all: true to hide messages without losing them.

Competitors

Track competitor brands on Reddit. Add a competitor name (and optionally a domain) — the Reoogle bot scans Reddit every 6 hours for posts and comments that mention your competitors, so you can monitor sentiment and spot opportunities to engage. Each account can track up to 10 competitors.

GET /api/v1/competitors

Returns all competitors being tracked for the authenticated user.

bash
curl https://reoogle.com/api/v1/competitors \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "competitors": [
    {
      "id": "uuid",
      "name": "CompetitorBrand",
      "domain": "competitor.com",
      "created_at": "2026-06-01T10:00:00Z"
    }
  ]
}

POST /api/v1/competitors

Add a new competitor to track.

ParameterTypeDescription
namestringCompetitor brand name to search for on Reddit. Required.
domainstringCompetitor domain (e.g. competitor.com). Optional.
bash
curl -X POST https://reoogle.com/api/v1/competitors \
  -H "Authorization: Bearer rog_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "CompetitorBrand", "domain": "competitor.com"}'
json
{
  "competitor": {
    "id": "uuid",
    "name": "CompetitorBrand",
    "domain": "competitor.com",
    "created_at": "2026-07-02T10:00:00Z"
  }
}

DELETE /api/v1/competitors/{id}

Remove a tracked competitor and all associated mention data.

bash
curl -X DELETE https://reoogle.com/api/v1/competitors/COMPETITOR_UUID \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{ "ok": true }

GET /api/v1/competitors/{id}/mentions

Returns Reddit posts and comments where a competitor was mentioned.

ParameterTypeDescription
limitintegerMax results — max 50 (default: 25)
bash
curl "https://reoogle.com/api/v1/competitors/COMPETITOR_UUID/mentions?limit=10" \
  -H "Authorization: Bearer rog_live_YOUR_KEY"
json
{
  "competitor": { "id": "uuid", "name": "CompetitorBrand" },
  "mentions": [
    {
      "id": "uuid",
      "reddit_post_id": "t3_xyz",
      "post_title": "Which tool is better — CompetitorBrand or alternatives?",
      "post_url": "https://reddit.com/r/SaaS/comments/xyz/...",
      "subreddit": "SaaS",
      "author": "some_redditor",
      "body_snippet": "I tried CompetitorBrand last month and...",
      "score": 14,
      "found_at": "2026-07-01T08:00:00Z"
    }
  ],
  "total": 23
}

Integration Examples

1 — Forward mod-inactive alerts to Slack

Listen for mods.inactive webhooks and post a Slack message whenever a new opportunity surfaces.

javascript
app.post(0, express.raw({ type: 1 }), async (req, res) => {
  if (!verifySignature(req.body, req.header(2) ?? 3, SECRET)) {
    return res.sendStatus(401);
  }

  const { event, data } = JSON.parse(req.body.toString());

  if (event === 4) {
    await fetch(process.env.SLACK_WEBHOOK_URL!, {
      method: 5,
      headers: { 6: 7 },
      body: JSON.stringify({
        text: 8,
      }),
    });
  }

  res.sendStatus(200);
});

2 — Daily engagement drop alert

Run as a cron job to compare current engagement against a stored baseline and trigger an email when a favorited subreddit drops significantly.

python
import requests

API    = 0
HEADERS = {1: 2}
WATCHLIST = [3, 4]

for name in WATCHLIST:
    resp = requests.get(f5, headers=HEADERS)
    resp.raise_for_status()

    total = sum(row[6] for row in resp.json()[7])
    baseline = load_baseline(name)  8

    if baseline and total < baseline * 0.8:
        send_email(f9)

    save_baseline(name, total)

3 — Find the best subreddits to post your product

Use /postable to build an automated posting pipeline that targets only communities with real traffic and tolerant moderation.

typescript
const API     = 0;
const HEADERS = { Authorization: 1 };

async function findPostableSubreddits(opts = {}) {
  const params = new URLSearchParams({
    lang:          2,
    min_posts_60d: 3,     4
    min_members:   5,
    sort_by:       6,
    per_page:      7,
    ...opts,
  });

  const res  = await fetch(8, { headers: HEADERS });
  const body = await res.json();

  return body.data.map((s: any) => ({
    name:               s.name,
    members:            s.member_count,
    posts_per_60d:      s.posts_last_60d,
    avg_comments:       s.avg_comments,
    restrict_posting:   s.restrict_posting,   9
    link_posts_survive: s.link_posts_survive,
    icon:               s.icon_img,
  }));
}

10
const targets = await findPostableSubreddits();
console.table(targets.slice(0, 10));

4 — External dashboard: top 10 by category

typescript
const API = 0;
const HEADERS = { Authorization: 1 };

async function topSubreddits(category: string, limit = 10) {
  const url = new URL(2);
  url.searchParams.set(3, category);
  url.searchParams.set(4, 5);
  url.searchParams.set(6, 7);
  url.searchParams.set(8, String(limit));

  const res = await fetch(url.toString(), { headers: HEADERS });
  if (!res.ok) throw new Error(9);

  const { data } = await res.json();
  return data.map((s: any) => ({ name: s.name, members: s.member_count }));
}

10
const gaming = await topSubreddits(11);
console.table(gaming);

Versioning & Changelog

The API version is encoded in the path (/api/v1). Breaking changes are released under a new version number; additive changes — new fields or endpoints — may be introduced within an existing version.

Version v1 will remain supported for a minimum of 12 months after any successor is published. Deprecation notices are sent by email 90 days before end-of-life.

Changelog

v1.4Jul 2026

DELETE /api/v1/reddit/inbox — permanently delete inbox messages by ID. Image uploads now work on Vercel deployments: files are stored on the bot server and served via a transparent proxy through reoogle.com/api/v1/images/.

Current
v1.3Jul 2026

New endpoints: /schedule (GET · POST), /schedule/{id} (GET · PATCH · DELETE), /uploads (POST). Schedule text and image/link posts via API. Upload images with an API key and use the returned URL as image_url when scheduling.

v1.2Jul 2026

New endpoints: /subreddits/unmoderated, /reddit/inbox (GET + PATCH), /competitors (CRUD), /competitors/{id}/mentions, /ai-posts/{id}/approve, /ai-posts/{id}/reject, PUT /ai-posts/{id}. All new endpoints accept API key auth. AI Posts status now includes pending_review for the approval queue.

v1.1Jun 2026

Rich subreddit data: icon/banner URLs, restrict_posting, allows_links, link_posts_survive, posts_last_60d, avg_comments. New endpoints: /subreddits/postable, /subreddits/{name}/moderators. New filters on /subreddits and /search.

v1.0Jun 2026

Initial release — subreddits, search, categories, usage, API keys, webhooks.

Ready to build?

Generate an API key from your developer dashboard and make your first request in minutes.

Generate your API key