Use the API from Claude Code
Let Claude Code publish to Ur Next Door: put your key in UND_API_KEY, add a CLAUDE.md note that points at the docs, allow curl, and start with a test prompt.
Claude Code is Anthropic's agent for the terminal, IDEs and the Code tab of the Claude desktop app. It can run curl, so it can call the Ur Next Door API directly. Your key stays in an environment variable: Claude Code writes $UND_API_KEY in its commands and your shell fills it in, so the key itself never enters the conversation.
Step 1: Create a key for Claude Code
In Settings > API keys on urnextdoor.com, create a key named Claude Code, with the scopes content, media and read (add schedule if it should move or cancel scheduled items), and an expiry of 30 or 90 days. Copy it. See Create an API key.
Step 2: Put the key in the environment, then start Claude Code
Claude Code inherits environment variables from the terminal you start it in. Set the variable first:
# Paste the key when asked; it is not shown or saved in your history.
read -rs UND_API_KEY && export UND_API_KEY
claudeIf you saved the key in your shell profile (see Create an API key), just open a new terminal and run claude.
Do not paste the key into the chat
Anything you type into the conversation is part of the transcript. Keep the key in the environment and let Claude refer to $UND_API_KEY.
Step 3: Add a note to CLAUDE.md
Claude Code reads CLAUDE.md in your project folder at the start of every session. Add this section so it knows how to use the API safely:
## Ur Next Door API
- Before the first call, read https://docs.urnextdoor.com/llms.txt and follow
https://docs.urnextdoor.com/ai/system-prompt.txt.
- Base URL: https://urnextdoor.com/api/v1. Contract: https://urnextdoor.com/api/v1/openapi.json
- The API key is in $UND_API_KEY. Use it only as -H "Authorization: Bearer $UND_API_KEY".
Never print, echo or write the key.
- Send -H "Idempotency-Key: $(uuidgen)" on every POST and DELETE.
- Show me a preview and wait for my yes before publishing anything.
- Upload images with POST /media first, then use data.url as featured_image.
- When done, give me the web_url of everything you created.Step 4: Allow the docs and, if you want, curl
By default Claude Code asks before it fetches a web page or runs a command. To let it read these docs without asking, add a permission rule to .claude/settings.json in your project:
{
"permissions": {
"allow": [
"WebFetch(domain:docs.urnextdoor.com)",
"WebFetch(domain:urnextdoor.com)"
]
}
}You can also add "Bash(curl:*)" to that list so it runs curl without a prompt each time. Only do that if you are comfortable with it publishing without a permission prompt; the CLAUDE.md rule above still asks it to confirm with you first. Leaving curl out means you approve each request, which is a good way to start.
Step 5: Try it
Start with something that cannot publish:
Check my Ur Next Door API key with GET /me and tell me my plan and the key's scopes.
Do not create anything.Then a real task:
Write a short post for Ur Next Door about three ways to save water at home.
Use HTML paragraphs and a list, add the tags water and home, and show me a preview.
After I say yes, publish it and give me the web_url.Claude Code will run a request like this one, with $UND_API_KEY expanded by your shell:
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"
]
}'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());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
$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
{
"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"
}More in Prompt recipes.
Images
Claude Code works with files on your computer. If you have an image (from an image model, a screenshot or a photo), ask Claude Code to upload it and use it:
Upload ./cover.png to Ur Next Door as base64 JSON, building the body in a file,
then create the post with that image as featured_image.It should follow Upload images: build the JSON in a file, send it with --data-binary @file, then use data.url.
Troubleshooting
| Symptom | Fix |
|---|---|
401 missing_api_key | The variable is empty in Claude Code's environment. Quit Claude Code, set UND_API_KEY in that terminal, start claude again. Check with echo ${UND_API_KEY:+set} (prints set without showing the key). |
401 invalid_api_key | Mistyped, revoked or expired key. Create a new one. |
403 insufficient_scope | The key lacks a scope Claude needs, often media or read. |
uuidgen: command not found | On Linux, install uuid-runtime, or ask Claude to use python3 -c "import uuid; print(uuid.uuid4())". |
| Claude invents an id | Remind it to use the lookups; the system prompt says so. |
Next steps
- System prompt for the full rules.
- Prompt recipes.
- Codex CLI if you also use OpenAI's agent.
Last updated