# 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.

Source: https://docs.urnextdoor.com/getting-started/first-request/

This page takes about five minutes. You need a key with the `content` scope stored in `UND_API_KEY` (see [Create an API key](https://docs.urnextdoor.com/getting-started/create-api-key.md)).

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

```bash
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**

```bash
curl "https://urnextdoor.com/api/v1/me" \
  -H "Authorization: Bearer $UND_API_KEY"
```

**JavaScript**

```js
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**

```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
<?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**

```bash
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**

```js
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**

```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
<?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](https://docs.urnextdoor.com/guides/manage-scheduled.md)).

## 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**

```bash
curl "https://urnextdoor.com/api/v1/usage" \
  -H "Authorization: Bearer $UND_API_KEY"
```

**JavaScript**

```js
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**

```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
<?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 got | Likely cause | Fix |
| --- | --- | --- |
| `401 missing_api_key` | `UND_API_KEY` is empty in this process | Set it again, then rerun |
| `401 invalid_api_key` | The key is mistyped, revoked or expired | Copy it again or create a new key |
| `403 insufficient_scope` | The key lacks `content` | Create a key with `content` |
| `415 unsupported_media_type` | Missing `Content-Type: application/json` | Add the header |
| `400 invalid_json` | The body is not a JSON object | Check quotes and commas in the body |
| `422 validation_failed` | A field is missing or wrong | Read `errors`, fix those fields |
| `421 wrong_host` | You called a community subdomain | Use `https://urnextdoor.com/api/v1` |

The full list is on [Errors](https://docs.urnextdoor.com/errors.md).

## Next steps

- [Create a post](https://docs.urnextdoor.com/guides/create-post.md) with tags, images and a community.
- [Schedule content](https://docs.urnextdoor.com/guides/schedule-content.md) for later.
- Let an AI agent do it: [Claude Code](https://docs.urnextdoor.com/ai/claude-code.md) or [Codex CLI](https://docs.urnextdoor.com/ai/codex-cli.md).
