Rate limits and daily quotas

Ur Next Door API daily quotas per plan and action, the 60 requests a minute limit, rate limit headers, UTC midnight resets, and size limits.

View as Markdown

Two limits apply to API use: a daily quota for each kind of create, and a burst limit on requests a minute. Both are per member: all of your keys share them, so five keys do not give you five times the quota.

Daily quotas

Each successful create or upload uses one unit of its action's quota for the current UTC day:

ActionFreeProBusiness
post2060200
question2060200
poll1030100
mcq3090300
community2520
service51550
job51550
media50150500
  • The columns are plans. Your plan is shown by GET /api/v1/me and GET /api/v1/usage; you can change it in Settings > Billing.
  • community is small on purpose: communities are long lived.
  • Quotas count only API requests. What you do on the website or in the app never uses them.
  • A scheduled create counts on the day you schedule it, not the day it goes live. Cancelling it later does not give the unit back.
  • Reads and schedule management are not counted: GET /me, GET /usage, the lookups, GET /scheduled, reschedule, publish now and cancel.

Failed requests never count

Only a successful answer (2xx) uses quota. A 422 because of a typo, a 403, a 409 or even a 500 gives the unit back at once. Fix the problem and try again.

When the day resets

Counters reset at 00:00 UTC every day (05:30 in India). X-RateLimit-Reset and resets_at give the exact moment.

Check your usage

cURL
curl "https://urnextdoor.com/api/v1/usage" \
  -H "Authorization: Bearer $UND_API_KEY"
JavaScript
const res = await fetch("https://urnextdoor.com/api/v1/usage", {
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
  },
});
console.log(res.status, await res.json());
Python
import os

import requests

api_key = os.environ["UND_API_KEY"]

response = requests.get(
    "https://urnextdoor.com/api/v1/usage",
    headers={
        "Authorization": f"Bearer {api_key}",
    },
    timeout=30,
)
print(response.status_code, response.json())
PHP
<?php
$apiKey = getenv('UND_API_KEY');

$ch = curl_init('https://urnextdoor.com/api/v1/usage');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
    ],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

echo $status, PHP_EOL, $body, PHP_EOL;

Sample response: 200 OK

JSON
{
  "ok": true,
  "plan": "free",
  "day": "2026-10-15",
  "resets_at": "2026-10-16T00:00:00Z",
  "quotas": [
    {
      "action": "post",
      "limit": 20,
      "used": 3,
      "remaining": 17
    },
    {
      "action": "question",
      "limit": 20,
      "used": 0,
      "remaining": 20
    },
    {
      "action": "media",
      "limit": 50,
      "used": 2,
      "remaining": 48
    }
  ],
  "request_id": "9f8e7d6c5b4a3921"
}

Every quota-counted response also carries three headers:

HeaderMeaning
X-RateLimit-LimitToday's limit for this action
X-RateLimit-RemainingUnits left today for this action
X-RateLimit-ResetUnix seconds of the next UTC midnight

When the quota runs out

The request answers 429 with the code quota_exceeded and a Retry-After header (seconds until the reset):

JSON
{
  "ok": false,
  "error": "You have used today's 20 posts for the API. The limit resets at 00:00 UTC.",
  "code": "quota_exceeded",
  "request_id": "a1b2c3d4e5f60718"
}

Do not retry before the reset; schedule the rest for tomorrow instead, or upgrade your plan.

The burst limit: 60 requests a minute

Across every endpoint, counted or not, a member may make 60 requests a minute. Beyond that, requests answer 429 with the code rate_limited and a Retry-After header. Wait that many seconds and continue.

Separately, repeated failed key checks from one network address are limited, so a script stuck in a loop with a wrong key is slowed down. Fix the key first.

A simple, polite client:

JavaScript
async function call(url, options, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch(url, options);
    if (res.status !== 429 && res.status < 500) return res;
    const body = await res.clone().json().catch(() => ({}));
    if (body.code === "quota_exceeded") return res;
    const wait = Number(res.headers.get("Retry-After") || 2 ** i);
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  return fetch(url, options);
}

Reuse the same Idempotency-Key in options across the attempts, so a retried create never posts twice.

Size limits

LimitValue
JSON request body256 KB
JSON request body for POST /media12 MB
Image in8 MB, PNG, JPEG, GIF or WebP
Image stored2 MB or less after conversion to WebP
gallery12 images
Poll and MCQ options2 to 5
Service packages3
Service faqs20
Active API keys per member5
scheduled_at5 minutes to 180 days ahead

Over a size limit, the request answers 413 payload_too_large.

Frequently asked questions

Do all my keys share one quota?

Yes. Quotas and the burst limit are per member, across all of your keys.

Does posting on the website use my API quota?

No. Only requests made with an API key count.

Does a failed request use quota?

No. Anything that is not a 2xx answer gives the unit back immediately.

How do I get higher limits?

Higher plans have higher quotas, as the table shows. Upgrade in Settings > Billing on the website.

Next steps

Last updated