Post a job

Post a job on Ur Next Door with the API: employment type, work mode, experience level, salary range and currency, deadline and location rules.

View as Markdown

A job post advertises an opening. Members can find it on the Jobs page and apply on the site.

Endpoint: POST /api/v1/jobs · Scope: content (and read for the lookup) · Quota: job

Step 1: Get the allowed values

employment_type, work_mode, experience_level and salary_period accept fixed values. Read them from GET /api/v1/job-options instead of guessing:

cURL
curl "https://urnextdoor.com/api/v1/job-options" \
  -H "Authorization: Bearer $UND_API_KEY"
JavaScript
const res = await fetch("https://urnextdoor.com/api/v1/job-options", {
  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/job-options",
    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/job-options');
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,
  "employment_types": [
    "full_time",
    "part_time",
    "contract",
    "internship",
    "temporary"
  ],
  "work_modes": [
    "remote",
    "hybrid",
    "onsite"
  ],
  "experience_levels": [
    "entry",
    "mid",
    "senior",
    "lead",
    "executive"
  ],
  "salary_periods": [
    "yearly",
    "monthly",
    "hourly",
    "project"
  ],
  "request_id": "9f8e7d6c5b4a3921"
}

Step 2: Write the job

Required: title, an HTML body, employment_type, work_mode and experience_level.

Optional but useful:

  • openings: 1 to 999.
  • salary_min, salary_max and salary_period (for example yearly), in currency (3 letters, INR if you leave it out).
  • application_deadline: the last day to apply, as YYYY-MM-DD.
  • summary: up to 300 characters, shown on cards.
  • tags, featured_image (jobs take one image, no gallery), and community_id or community.

Step 3: Set the location (unless remote)

For onsite and hybrid jobs, send country_code and the state_id, district_id and city_id from GET /api/v1/geo (see Look up ids), plus an optional area. When work_mode is remote, location fields are ignored.

Post a remote job

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

Schedule an on site job

cURL
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": "Store manager",
  "body": "<p>Run our Kothrud store: staff, stock and customers.</p>",
  "employment_type": "full_time",
  "work_mode": "onsite",
  "experience_level": "senior",
  "country_code": "IN",
  "state_id": 19,
  "city_id": 1204,
  "salary_min": 35000,
  "salary_max": 45000,
  "salary_period": "monthly",
  "scheduled_at": "2026-10-20T09:30:00Z"
}'
JavaScript
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: "Store manager",
    body: "<p>Run our Kothrud store: staff, stock and customers.</p>",
    employment_type: "full_time",
    work_mode: "onsite",
    experience_level: "senior",
    country_code: "IN",
    state_id: 19,
    city_id: 1204,
    salary_min: 35000,
    salary_max: 45000,
    salary_period: "monthly",
    scheduled_at: "2026-10-20T09:30:00Z",
  }),
});
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/jobs",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Store manager",
        "body": "<p>Run our Kothrud store: staff, stock and customers.</p>",
        "employment_type": "full_time",
        "work_mode": "onsite",
        "experience_level": "senior",
        "country_code": "IN",
        "state_id": 19,
        "city_id": 1204,
        "salary_min": 35000,
        "salary_max": 45000,
        "salary_period": "monthly",
        "scheduled_at": "2026-10-20T09:30:00Z",
    },
    timeout=30,
)
print(response.status_code, response.json())
PHP
<?php
$apiKey = getenv('UND_API_KEY');

$payload = [
    'title' => 'Store manager',
    'body' => '<p>Run our Kothrud store: staff, stock and customers.</p>',
    'employment_type' => 'full_time',
    'work_mode' => 'onsite',
    'experience_level' => 'senior',
    'country_code' => 'IN',
    'state_id' => 19,
    'city_id' => 1204,
    'salary_min' => 35000,
    'salary_max' => 45000,
    'salary_period' => 'monthly',
    'scheduled_at' => '2026-10-20T09:30:00Z',
];

$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",
  "status": "scheduled",
  "scheduled_at": "2026-10-20T09:30:00Z",
  "item": {
    "id": 23,
    "type": "job",
    "slug": "backend-developer-php"
  },
  "request_id": "9f8e7d6c5b4a3921"
}

All fields

FieldTypeRequiredDescription
titlestringYesThe job title (plain text).
bodystringYesThe job description as HTML.
employment_typestringYesOne of employment_types from GET /job-options, for example full_time.
work_modestringYesOne of work_modes from GET /job-options, for example remote. Location fields are ignored when it is remote.
experience_levelstringYesOne of experience_levels from GET /job-options, for example mid.
openingsintegerNoNumber of openings. From 1 to 999.
salary_minnumberNoLowest salary in currency, per salary_period.
salary_maxnumberNoHighest salary in currency, per salary_period.
salary_periodstringNoOne of salary_periods from GET /job-options, for example yearly.
currencystringNoThree letter currency code. Pattern: ^[A-Z]{3}$. Default: INR.
application_deadlinestring (date)NoLast day to apply, YYYY-MM-DD.
summarystringNoA short plain text summary shown on cards. Up to 300 characters.
country_codestringNoISO 3166-1 alpha-2 country. Ignored when work_mode is remote.
state_idintegerNoFrom GET /geo. Ignored when work_mode is remote.
district_idintegerNoFrom GET /geo. Ignored when work_mode is remote.
city_idintegerNoFrom GET /geo. Ignored when work_mode is remote.
areastringNoNeighbourhood or area, free text. Ignored when work_mode is remote.
featured_imagestringNoA /storage/... path returned by POST /media (data.url), or any https:// image URL (linked, not copied).
tagsarray of stringNoTopic tags, without the leading #. Example: ["water", "home"].
community_idintegerNoPost inside this community. Use an id from GET /communities/postable. You must be an editor (or above) of it.
communitystringNoAlternative to community_id: the community slug. It is resolved to its id.
scheduled_atstring (date-time)NoPublish later instead of now. ISO 8601 with an offset or Z, at least 5 minutes and at most 180 days ahead. Stored in UTC.

Common errors

Status and codeCauseFix
422 validation_failedA required field is missing, or a value is not in job-optionsFix the field named in errors
422 validation_failed on scheduled_atOutside the 5 minute to 180 day windowPick a time in the window, in UTC
429 quota_exceededToday's job quota is used upWait until 00:00 UTC

When you list scheduled items, jobs appear with the type job_post. You can use job or job_post in scheduling paths.

Next steps

Last updated