# Content endpoints

> Create posts, questions, polls, MCQs, communities, Marketplace services and jobs, now or at a scheduled time.

Source: https://docs.urnextdoor.com/reference/content/

All paths are relative to `https://urnextdoor.com/api/v1`. See [API reference](https://docs.urnextdoor.com/reference.md) for the envelope and headers every endpoint shares.

| Endpoint | What it does | Scope | Daily quota |
| --- | --- | --- | --- |
| [`POST /posts`](https://docs.urnextdoor.com/reference/content/#createPost) | Create a post | `content` | `post` |
| [`POST /questions`](https://docs.urnextdoor.com/reference/content/#createQuestion) | Ask a question | `content` | `question` |
| [`POST /polls`](https://docs.urnextdoor.com/reference/content/#createPoll) | Create a poll | `content` | `poll` |
| [`POST /mcqs`](https://docs.urnextdoor.com/reference/content/#createMcq) | Create an MCQ | `content` | `mcq` |
| [`POST /communities`](https://docs.urnextdoor.com/reference/content/#createCommunity) | Create a community | `content` | `community` |
| [`POST /services`](https://docs.urnextdoor.com/reference/content/#createService) | List a service | `content` | `service` |
| [`POST /jobs`](https://docs.urnextdoor.com/reference/content/#createJob) | Post a job | `content` | `job` |

## Create a post {#createPost}

`POST https://urnextdoor.com/api/v1/posts`

Publishes a post now, or schedules it when scheduled_at is set. title and body (HTML) are required. Send an Idempotency-Key so a retry never posts twice. Counts against the post quota.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `post` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createPost`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The post title (plain text). |
| `body` | string | Yes | The post body as HTML. See the Formatting guide for allowed tags. |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `gallery` | array of string | No | Extra images. Each is a /storage/... path from POST /media or an https:// image URL. Up to 12 items. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

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

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## Ask a question {#createQuestion}

`POST https://urnextdoor.com/api/v1/questions`

Publishes a question now, or schedules it when scheduled_at is set. Only title is required; body (HTML) adds details. Counts against the question quota.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `question` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createQuestion`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The question itself (plain text). |
| `body` | string | No | Optional details as HTML. |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `gallery` | array of string | No | Extra images. Each is a /storage/... path from POST /media or an https:// image URL. Up to 12 items. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/questions" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Which plants survive a north facing balcony?",
  "body": "<p>We get about two hours of direct sun. What has worked for you?</p>",
  "tags": [
    "gardening"
  ]
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/questions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "Which plants survive a north facing balcony?",
    body: "<p>We get about two hours of direct sun. What has worked for you?</p>",
    tags: ["gardening"],
  }),
});
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/questions",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Which plants survive a north facing balcony?",
        "body": "<p>We get about two hours of direct sun. What has worked for you?</p>",
        "tags": ["gardening"],
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Which plants survive a north facing balcony?',
    'body' => '<p>We get about two hours of direct sun. What has worked for you?</p>',
    'tags' => ['gardening'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/questions');
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": 52,
  "slug": "which-plants-survive-a-north-facing-balcony",
  "url": "/questions/which-plants-survive-a-north-facing-balcony",
  "web_url": "https://urnextdoor.com/questions/which-plants-survive-a-north-facing-balcony",
  "item": {
    "id": 52,
    "type": "question",
    "slug": "which-plants-survive-a-north-facing-balcony"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## Create a poll {#createPoll}

`POST https://urnextdoor.com/api/v1/polls`

Publishes a poll now, or schedules it. title and options (2 to 5 unique strings) are required. Counts against the poll quota.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `poll` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createPoll`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The poll question (plain text). |
| `options` | array of string | Yes | The answers people vote on: 2 to 5 unique strings. 2 to 5 items. Items must be unique. |
| `body` | string | No | Optional context as HTML. |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `gallery` | array of string | No | Extra images. Each is a /storage/... path from POST /media or an https:// image URL. Up to 12 items. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/polls" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "When should the weekend cleanup start?",
  "options": [
    "7 am",
    "8 am",
    "9 am"
  ],
  "tags": [
    "neighbourhood"
  ]
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/polls", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "When should the weekend cleanup start?",
    options: ["7 am", "8 am", "9 am"],
    tags: ["neighbourhood"],
  }),
});
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/polls",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "When should the weekend cleanup start?",
        "options": ["7 am", "8 am", "9 am"],
        "tags": ["neighbourhood"],
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'When should the weekend cleanup start?',
    'options' => ['7 am', '8 am', '9 am'],
    'tags' => ['neighbourhood'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/polls');
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": 18,
  "slug": "when-should-the-weekend-cleanup-start",
  "url": "/polls/when-should-the-weekend-cleanup-start",
  "web_url": "https://urnextdoor.com/polls/when-should-the-weekend-cleanup-start",
  "item": {
    "id": 18,
    "type": "poll",
    "slug": "when-should-the-weekend-cleanup-start"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## Create an MCQ {#createMcq}

`POST https://urnextdoor.com/api/v1/mcqs`

Publishes a multiple choice quiz question now, or schedules it. title, options (2 to 5) and correct_option_index (0-based) are required. Counts against the mcq quota.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `mcq` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createMcq`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The quiz question (plain text). |
| `options` | array of string | Yes | The choices: 2 to 5 unique strings. 2 to 5 items. Items must be unique. |
| `correct_option_index` | integer | Yes | The 0-based position of the correct choice in options. From 0 to 4. |
| `body` | string | No | Optional context or explanation as HTML. |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `gallery` | array of string | No | Extra images. Each is a /storage/... path from POST /media or an https:// image URL. Up to 12 items. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/mcqs" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Which planet has the shortest year?",
  "options": [
    "Venus",
    "Mercury",
    "Mars",
    "Earth"
  ],
  "correct_option_index": 1,
  "tags": [
    "science"
  ]
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/mcqs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "Which planet has the shortest year?",
    options: ["Venus", "Mercury", "Mars", "Earth"],
    correct_option_index: 1,
    tags: ["science"],
  }),
});
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/mcqs",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Which planet has the shortest year?",
        "options": ["Venus", "Mercury", "Mars", "Earth"],
        "correct_option_index": 1,
        "tags": ["science"],
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Which planet has the shortest year?',
    'options' => ['Venus', 'Mercury', 'Mars', 'Earth'],
    'correct_option_index' => 1,
    'tags' => ['science'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/mcqs');
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": 77,
  "slug": "which-planet-has-the-shortest-year",
  "url": "/mcqs/which-planet-has-the-shortest-year",
  "web_url": "https://urnextdoor.com/mcqs/which-planet-has-the-shortest-year",
  "item": {
    "id": 77,
    "type": "mcq",
    "slug": "which-planet-has-the-shortest-year"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## Create a community {#createCommunity}

`POST https://urnextdoor.com/api/v1/communities`

Creates a community now (201), or schedules its creation (202) when scheduled_at is set. name must be unique. A scheduled creation fails later if the name is taken by then. Counts against the community quota.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `community` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createCommunity`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | The community name. It must be unique. |
| `description` | string | No | What the community is about, as HTML. |
| `visibility` | string | No | Who can see and join it. One of: `public`, `ask_to_join`, `private`. |
| `icon_url` | string | No | One of the paths returned by GET /community-icons. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/communities" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "name": "Morning Runners Pune",
  "description": "<p>Early runs, routes and race plans around Pune.</p>",
  "visibility": "public",
  "icon_url": "/avatars/community/running.png"
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/communities", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    name: "Morning Runners Pune",
    description: "<p>Early runs, routes and race plans around Pune.</p>",
    visibility: "public",
    icon_url: "/avatars/community/running.png",
  }),
});
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/communities",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "name": "Morning Runners Pune",
        "description": "<p>Early runs, routes and race plans around Pune.</p>",
        "visibility": "public",
        "icon_url": "/avatars/community/running.png",
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'name' => 'Morning Runners Pune',
    'description' => '<p>Early runs, routes and race plans around Pune.</p>',
    'visibility' => 'public',
    'icon_url' => '/avatars/community/running.png',
];

$ch = curl_init('https://urnextdoor.com/api/v1/communities');
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": 5,
  "slug": "morning-runners-pune",
  "url": "/communities/morning-runners-pune",
  "web_url": "https://urnextdoor.com/communities/morning-runners-pune",
  "item": {
    "id": 5,
    "type": "community",
    "slug": "morning-runners-pune",
    "name": "Morning Runners Pune"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created now. |   |
| `202 Accepted` | Accepted: the community will be created at scheduled_at. id is the scheduled-creation id. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## List a service {#createService}

`POST https://urnextdoor.com/api/v1/services`

Publishes a Marketplace service now, or schedules it. title, body and category_id are required, plus a location (country_code, postal_code, state_id) unless service_mode is online. Prices are in rupees.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `service` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createService`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The service title (plain text). |
| `body` | string | Yes | The full description as HTML. |
| `category_id` | integer | Yes | A category id from GET /service-categories. |
| `summary` | string | No | A short plain text summary shown on cards. Up to 300 characters. |
| `service_mode` | string | No | How you deliver. Unless it is online, a location is required. One of: `online`, `in_person`, `both`. Default: `both`. |
| `country_code` | string | No | ISO 3166-1 alpha-2 country, for example IN. Required unless service_mode is online. |
| `postal_code` | string | No | Postal code, valid for the country. Required unless service_mode is online. |
| `state_id` | integer | No | From GET /geo?level=states. At least a state (or a district or city) is required unless service_mode is online. |
| `district_id` | integer | No | From GET /geo?level=districts. If you send a district, also send a city. |
| `city_id` | integer | No | From GET /geo?level=cities. |
| `area` | string | No | Neighbourhood or area, free text. Up to 120 characters. |
| `packages` | array of object | No | Up to 3 priced packages. Up to 3 items. |
| `packages[].name` | string | No | Package name. Defaults to Basic, Standard or Premium by position. Up to 120 characters. |
| `packages[].description` | string | No | What the package includes. Up to 500 characters. |
| `packages[].price` | number | Yes | Price in Indian rupees, for example 4999. A package without a positive price is skipped. |
| `packages[].delivery_days` | integer | No | Days to deliver. Defaults to 1. |
| `packages[].revisions` | integer | No | Revisions included. -1 means unlimited. |
| `packages[].features` | array of string | No | Short feature lines, up to 20. Up to 20 items. |
| `faqs` | array of object | No | Up to 20 questions and answers. Up to 20 items. |
| `faqs[].q` | string | Yes | The question. Up to 200 characters. |
| `faqs[].a` | string | Yes | The answer. Up to 1000 characters. |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `gallery` | array of string | No | Extra images. Each is a /storage/... path from POST /media or an https:// image URL. Up to 12 items. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/services" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Business website in 7 days",
  "body": "<p>I build fast, mobile friendly websites for small shops and clinics.</p><ul><li>Design and build</li><li>Hosting setup</li></ul>",
  "category_id": 12,
  "summary": "A fast, mobile friendly website for your shop or clinic.",
  "service_mode": "online",
  "packages": [
    {
      "name": "Starter",
      "description": "One page site",
      "price": 4999,
      "delivery_days": 5,
      "revisions": 2,
      "features": [
        "1 page",
        "Contact form"
      ]
    },
    {
      "name": "Business",
      "description": "Up to 5 pages",
      "price": 14999,
      "delivery_days": 7,
      "revisions": -1,
      "features": [
        "5 pages",
        "Blog",
        "Basic SEO"
      ]
    }
  ],
  "faqs": [
    {
      "q": "Do you provide hosting?",
      "a": "I set it up on your account, so you own it."
    }
  ],
  "tags": [
    "web-design"
  ]
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/services", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "Business website in 7 days",
    body: "<p>I build fast, mobile friendly websites for small shops and clinics.</p><ul><li>Design and build</li><li>Hosting setup</li></ul>",
    category_id: 12,
    summary: "A fast, mobile friendly website for your shop or clinic.",
    service_mode: "online",
    packages: [
      {
        name: "Starter",
        description: "One page site",
        price: 4999,
        delivery_days: 5,
        revisions: 2,
        features: ["1 page", "Contact form"],
      },
      {
        name: "Business",
        description: "Up to 5 pages",
        price: 14999,
        delivery_days: 7,
        revisions: -1,
        features: ["5 pages", "Blog", "Basic SEO"],
      },
    ],
    faqs: [
      {
        q: "Do you provide hosting?",
        a: "I set it up on your account, so you own it.",
      },
    ],
    tags: ["web-design"],
  }),
});
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/services",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Business website in 7 days",
        "body": "<p>I build fast, mobile friendly websites for small shops and clinics.</p><ul><li>Design and build</li><li>Hosting setup</li></ul>",
        "category_id": 12,
        "summary": "A fast, mobile friendly website for your shop or clinic.",
        "service_mode": "online",
        "packages": [
            {
                "name": "Starter",
                "description": "One page site",
                "price": 4999,
                "delivery_days": 5,
                "revisions": 2,
                "features": ["1 page", "Contact form"],
            },
            {
                "name": "Business",
                "description": "Up to 5 pages",
                "price": 14999,
                "delivery_days": 7,
                "revisions": -1,
                "features": ["5 pages", "Blog", "Basic SEO"],
            },
        ],
        "faqs": [
            {
                "q": "Do you provide hosting?",
                "a": "I set it up on your account, so you own it.",
            },
        ],
        "tags": ["web-design"],
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Business website in 7 days',
    'body' => '<p>I build fast, mobile friendly websites for small shops and clinics.</p><ul><li>Design and build</li><li>Hosting setup</li></ul>',
    'category_id' => 12,
    'summary' => 'A fast, mobile friendly website for your shop or clinic.',
    'service_mode' => 'online',
    'packages' => [
        [
            'name' => 'Starter',
            'description' => 'One page site',
            'price' => 4999,
            'delivery_days' => 5,
            'revisions' => 2,
            'features' => ['1 page', 'Contact form'],
        ],
        [
            'name' => 'Business',
            'description' => 'Up to 5 pages',
            'price' => 14999,
            'delivery_days' => 7,
            'revisions' => -1,
            'features' => ['5 pages', 'Blog', 'Basic SEO'],
        ],
    ],
    'faqs' => [
        [
            'q' => 'Do you provide hosting?',
            'a' => 'I set it up on your account, so you own it.',
        ],
    ],
    'tags' => ['web-design'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/services');
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": 9,
  "slug": "business-website-in-7-days",
  "url": "/marketplace/business-website-in-7-days",
  "web_url": "https://urnextdoor.com/marketplace/business-website-in-7-days",
  "item": {
    "id": 9,
    "type": "service",
    "slug": "business-website-in-7-days"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |

## Post a job {#createJob}

`POST https://urnextdoor.com/api/v1/jobs`

Publishes a job now, or schedules it. title, body, employment_type, work_mode and experience_level are required (values from GET /job-options). Jobs take featured_image only, no gallery.

- **Auth:** your API key (Bearer or X-API-Key)
- **Scope:** `content`
- **Daily quota:** counts as `job` (see [limits](https://docs.urnextdoor.com/limits.md))
- **Idempotency-Key:** supported (see [Idempotency](https://docs.urnextdoor.com/idempotency.md))
- **operationId:** `createJob`

### Request body

Send `Content-Type: application/json`.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Yes | The job title (plain text). |
| `body` | string | Yes | The job description as HTML. |
| `employment_type` | string | Yes | One of employment_types from GET /job-options, for example full_time. |
| `work_mode` | string | Yes | One of work_modes from GET /job-options, for example remote. Location fields are ignored when it is remote. |
| `experience_level` | string | Yes | One of experience_levels from GET /job-options, for example mid. |
| `openings` | integer | No | Number of openings. From 1 to 999. |
| `salary_min` | number | No | Lowest salary in currency, per salary_period. |
| `salary_max` | number | No | Highest salary in currency, per salary_period. |
| `salary_period` | string | No | One of salary_periods from GET /job-options, for example yearly. |
| `currency` | string | No | Three letter currency code. Pattern: `^[A-Z]{3}$`. Default: `INR`. |
| `application_deadline` | string (date) | No | Last day to apply, YYYY-MM-DD. |
| `summary` | string | No | A short plain text summary shown on cards. Up to 300 characters. |
| `country_code` | string | No | ISO 3166-1 alpha-2 country. Ignored when work_mode is remote. |
| `state_id` | integer | No | From GET /geo. Ignored when work_mode is remote. |
| `district_id` | integer | No | From GET /geo. Ignored when work_mode is remote. |
| `city_id` | integer | No | From GET /geo. Ignored when work_mode is remote. |
| `area` | string | No | Neighbourhood or area, free text. Ignored when work_mode is remote. |
| `featured_image` | string | No | A /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied). |
| `tags` | array of string | No | Topic tags, without the leading #. Example: ["water", "home"]. |
| `community_id` | integer | No | Post inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it. |
| `community` | string | No | Alternative to community_id: the community slug. It is resolved to its id. |
| `scheduled_at` | string (date-time) | No | Publish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC. |

### Example

**cURL**

```bash
curl -X POST "https://urnextdoor.com/api/v1/jobs" \
  -H "Authorization: Bearer $UND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Backend developer (PHP)",
  "body": "<p>Join a small team building tools for local shops.</p><ul><li>3+ years with PHP or Node.js</li><li>Comfortable with MySQL</li></ul>",
  "employment_type": "full_time",
  "work_mode": "remote",
  "experience_level": "mid",
  "openings": 2,
  "salary_min": 900000,
  "salary_max": 1400000,
  "salary_period": "yearly",
  "currency": "INR",
  "application_deadline": "2026-11-30",
  "summary": "Remote, full time, PHP and MySQL.",
  "tags": [
    "php",
    "hiring"
  ]
}'
```

**JavaScript**

```js
const res = await fetch("https://urnextdoor.com/api/v1/jobs", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UND_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    title: "Backend developer (PHP)",
    body: "<p>Join a small team building tools for local shops.</p><ul><li>3+ years with PHP or Node.js</li><li>Comfortable with MySQL</li></ul>",
    employment_type: "full_time",
    work_mode: "remote",
    experience_level: "mid",
    openings: 2,
    salary_min: 900000,
    salary_max: 1400000,
    salary_period: "yearly",
    currency: "INR",
    application_deadline: "2026-11-30",
    summary: "Remote, full time, PHP and MySQL.",
    tags: ["php", "hiring"],
  }),
});
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/jobs",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Backend developer (PHP)",
        "body": "<p>Join a small team building tools for local shops.</p><ul><li>3+ years with PHP or Node.js</li><li>Comfortable with MySQL</li></ul>",
        "employment_type": "full_time",
        "work_mode": "remote",
        "experience_level": "mid",
        "openings": 2,
        "salary_min": 900000,
        "salary_max": 1400000,
        "salary_period": "yearly",
        "currency": "INR",
        "application_deadline": "2026-11-30",
        "summary": "Remote, full time, PHP and MySQL.",
        "tags": ["php", "hiring"],
    },
    timeout=30,
)
print(response.status_code, response.json())
```

**PHP**

```php
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Backend developer (PHP)',
    'body' => '<p>Join a small team building tools for local shops.</p><ul><li>3+ years with PHP or Node.js</li><li>Comfortable with MySQL</li></ul>',
    'employment_type' => 'full_time',
    'work_mode' => 'remote',
    'experience_level' => 'mid',
    'openings' => 2,
    'salary_min' => 900000,
    'salary_max' => 1400000,
    'salary_period' => 'yearly',
    'currency' => 'INR',
    'application_deadline' => '2026-11-30',
    'summary' => 'Remote, full time, PHP and MySQL.',
    'tags' => ['php', 'hiring'],
];

$ch = curl_init('https://urnextdoor.com/api/v1/jobs');
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": 23,
  "slug": "backend-developer-php",
  "url": "/jobs/backend-developer-php",
  "web_url": "https://urnextdoor.com/jobs/backend-developer-php",
  "item": {
    "id": 23,
    "type": "job",
    "slug": "backend-developer-php"
  },
  "request_id": "9f8e7d6c5b4a3921"
}
```

### Responses

| Status | Meaning | Codes |
| --- | --- | --- |
| `201 Created` | Created. Published now, or scheduled when scheduled_at was sent. |   |
| `400 Bad Request` | The body is not a JSON object, or the Idempotency-Key header is malformed. | `invalid_json`, `invalid_idempotency_key` |
| `401 Unauthorized` | No key, or the key is unknown, malformed, revoked or expired, or the member is not active. | `missing_api_key`, `invalid_api_key` |
| `403 Forbidden` | The key lacks the scope, or the member may not do this. | `insufficient_scope`, `forbidden` |
| `404 Not Found` | Unknown route or item, or the item is not yours. | `not_found` |
| `409 Conflict` | Conflicts with the current state, or the same Idempotency-Key is still being processed. | `conflict`, `idempotency_in_progress` |
| `413 Payload Too Large` | The body is over the limit, or the image is over 8 MB. | `payload_too_large` |
| `415 Unsupported Media Type` | Wrong Content-Type, or a file type that is not allowed. | `unsupported_media_type` |
| `421 Misdirected Request` | Called on a community subdomain. Use https://urnextdoor.com. | `wrong_host` |
| `422 Unprocessable Content` | Field errors, or an Idempotency-Key reused with a different body. | `validation_failed`, `idempotency_key_reused` |
| `429 Too Many Requests` | Over 60 requests a minute from this member (or too many failed key checks from one address), or today's quota for this action is used up. | `rate_limited`, `quota_exceeded` |
| `500 Internal Server Error` | Our fault. Safe to retry with the same Idempotency-Key. | `server_error` |
| `503 Service Unavailable` | The API is switched off. | `api_disabled` |
