Make your first request

Check your Ur Next Door API key with GET /me, publish your first post, open it on the site, and read your remaining daily quota. About five minutes.

View as Markdown

This page takes about five minutes. You need a key with the content scope stored in UND_API_KEY (see Create an API key).

The examples come in four languages. Pick yours once and every example on the site follows. JavaScript needs Node.js 20 or newer (save the code as a .mjs file); Python needs the requests package (pip install requests); PHP needs the curl extension.

Step 1: Check that the key is set

Shell
echo "${UND_API_KEY:0:12}..."

You should see und_sk_ and five more characters. If you see only ..., the variable is empty in this terminal: set it again, or open a new terminal if you saved it in your profile.

Step 2: Ask who you are

GET /api/v1/me confirms the key works and shows your plan and the key's scopes.

cURL
curl "https://urnextdoor.com/api/v1/me" \
  -H "Authorization: Bearer $UND_API_KEY"
JavaScript
const res = await fetch("https://urnextdoor.com/api/v1/me", {
  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/me",
    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/me');
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,
  "user": {
    "id": 7,
    "username": "aarav",
    "display_name": "Aarav",
    "plan": "free",
    "profile_url": "https://urnextdoor.com/users/aarav"
  },
  "key": {
    "id": 3,
    "name": "Claude Code",
    "prefix": "und_sk_7Hq2x",
    "scopes": [
      "content",
      "media",
      "schedule",
      "read"
    ],
    "created_at": "2026-10-15T09:00:00Z",
    "expires_at": "2027-01-13T09:00:00Z"
  },
  "request_id": "9f8e7d6c5b4a3921"
}

If scopes does not include content, create a key that does before step 3.

Step 3: Publish a post

POST /api/v1/posts needs a title and an HTML body. The Idempotency-Key header makes it safe to retry: if you send the same request again with the same key, you get the first answer back instead of a second post.

cURL
curl -X POST "https://urnextdoor.com/api/v1/posts" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Five easy ways to save water at home",
  "body": "<p>Small habits add up. These five saved our building a lot of water this summer.</p><ul><li>Fix dripping taps the same week.</li><li>Run the washing machine only when it is full.</li></ul>",
  "tags": [
    "water",
    "home"
  ]
}'
JavaScript
const res = await fetch("https://urnextdoor.com/api/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "Five easy ways to save water at home",
    body: "<p>Small habits add up. These five saved our building a lot of water this summer.</p><ul><li>Fix dripping taps the same week.</li><li>Run the washing machine only when it is full.</li></ul>",
    tags: ["water", "home"],
  }),
});
console.log(res.status, await res.json());
Python
import os
import uuid

import requests

api_key = os.environ["UND_API_KEY"]

response = requests.post(
    "https://urnextdoor.com/api/v1/posts",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Five easy ways to save water at home",
        "body": "<p>Small habits add up. These five saved our building a lot of water this summer.</p><ul><li>Fix dripping taps the same week.</li><li>Run the washing machine only when it is full.</li></ul>",
        "tags": ["water", "home"],
    },
    timeout=30,
)
print(response.status_code, response.json())
PHP
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Five easy ways to save water at home',
    'body' => '<p>Small habits add up. These five saved our building a lot of water this summer.</p><ul><li>Fix dripping taps the same week.</li><li>Run the washing machine only when it is full.</li></ul>',
    'tags' => ['water', 'home'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/posts');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

echo $status, PHP_EOL, $body, PHP_EOL;

Sample response: 201 Created

JSON
{
  "ok": true,
  "id": 41,
  "slug": "five-easy-ways-to-save-water-at-home",
  "url": "/posts/five-easy-ways-to-save-water-at-home",
  "web_url": "https://urnextdoor.com/posts/five-easy-ways-to-save-water-at-home",
  "item": {
    "id": 41,
    "type": "post",
    "slug": "five-easy-ways-to-save-water-at-home"
  },
  "request_id": "9f8e7d6c5b4a3921"
}

The post is live. web_url is its public address.

Note

This publishes for real, under your name. To try things out without publishing, add "scheduled_at" a few days ahead, check the result, then cancel it (see Manage scheduled content).

Step 4: Open it

Open the web_url from the response in a browser. You will see the post exactly as if you had written it on the website.

Step 5: See your remaining quota

Each create uses one unit of that action's daily quota. GET /api/v1/usage shows what is left today and when it resets (00:00 UTC):

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"
}

If something went wrong

You gotLikely causeFix
401 missing_api_keyUND_API_KEY is empty in this processSet it again, then rerun
401 invalid_api_keyThe key is mistyped, revoked or expiredCopy it again or create a new key
403 insufficient_scopeThe key lacks contentCreate a key with content
415 unsupported_media_typeMissing Content-Type: application/jsonAdd the header
400 invalid_jsonThe body is not a JSON objectCheck quotes and commas in the body
422 validation_failedA field is missing or wrongRead errors, fix those fields
421 wrong_hostYou called a community subdomainUse https://urnextdoor.com/api/v1

The full list is on Errors.

Next steps

Last updated