Job publishing API
Publish and manage your jobs from your own system. You can send our simple JSON format, or the
data.jobDetails JSON you already send to other job boards — we convert it for you.
1. Get a token
- Sign in as a company and complete verification (needed to submit jobs for approval).
- Open API in the menu (
/company/api) and create a token. Copy it — it is shown once. - Send it with every request:
Authorization: Bearer <token>andAccept: application/json.
Download the Postman collection
— import it in Postman, set the token variable, and every request below is ready to send.
Base URL: https://jorajobs.com/api/v1 · Rate limit: 60 requests per minute per company.
2. Endpoints
| Method | Path | Permission | What it does |
|---|---|---|---|
| GET | /jobs | jobs:read | Your jobs, newest first. Filters: status, external_id, per_page (max 100). |
| GET | /jobs/{id} | jobs:read | One job, with status and rejection reason. |
| POST | /jobs | jobs:write | Create a job (201), or update the job with the same external_id (200). |
| PUT / PATCH | /jobs/{id} | jobs:write | Update a job. Send only the fields that change. |
| POST | /jobs/{id}/close | jobs:write | Stop taking applications for a live job. |
| DELETE | /jobs/{id} | jobs:write | Delete a draft / pending / rejected job without applicants. |
| GET | /categories | any | Categories and sub-categories (id, slug, name). |
| GET | /options | any | Allowed values for employment_type, work_arrangement, salary_period, … |
3. How a job moves
- New jobs are submitted for approval (status
pending). Send"submit": falseto keep adraft. - An administrator approves (
live) or rejects (rejected, withrejection_reason). PollGET /jobs/{id}to follow it. - Updating a live job keeps it live. Updating a rejected job and sending
"submit": truesends it back for approval. - Unverified companies can only create drafts; submitting returns
403 company_not_verified.
4. Native format
Required: title, category (id, slug or name), description, country (name or ISO code, see GET /options), city, deadline_at (within a year).
New regions (state) and cities are added automatically.
salary_currency and salary_period are required when you send an amount. questions takes up to 10 strings or objects (type: text, yes_no, number).
curl -X POST https://jorajobs.com/api/v1/jobs \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d @job.json
{
"external_id": "ATS-2026-0042",
"title": "Senior Laravel Developer",
"category": "information-communication-technology",
"sub_category": "Software Development",
"employment_type": "full_time",
"work_arrangement": "hybrid",
"job_level": "senior",
"vacancies": 2,
"experience_min": 4,
"experience_max": 8,
"education_requirement": "BSc in CSE or related",
"skills": [
"Laravel",
"MySQL",
"REST"
],
"abstract": "Build and scale our hiring platform.",
"description": "<p>You will design APIs…</p><ul><li>4+ years with Laravel</li></ul>",
"salary_min": 120000,
"salary_max": 160000,
"salary_currency": "BDT",
"salary_period": "month",
"salary_negotiable": true,
"country": "Bangladesh",
"country_code": "BD",
"city": "Dhaka",
"area": "Gulshan",
"deadline_at": "2026-12-05",
"questions": [
"What is your notice period?",
{
"question": "Have you used Laravel queues in production?",
"type": "yes_no",
"required": true
}
],
"submit": true
}
5. Job board (data.jobDetails) format
Send the same JSON you send to other job boards. Fields about the other platform (tracking, insights, SEO, reviews,
branding, advertiser and company profile) are ignored — your company always comes from the token.
Any native field sent next to data overrides the converted value, for example
{"data": {…}, "category": "sales", "submit": false}.
{
"data": {
"jobDetails": {
"job": {
"id": "94933960",
"title": "DELIVERY MANAGER & RELEASE MANAGER",
"abstract": "DELIVERY MANAGER & RELEASE MANAGER",
"content2": "<p><strong>WE’RE HIRING</strong> …</p>",
"isExpired": false,
"isLinkOut": false,
"expiresAt": {
"dateTimeUtc": "2026-11-19T14:17:36.612Z"
},
"salary": {
"currencyLabel": "PHP",
"label": "₱120,000 – ₱130,000 per month"
},
"workTypes": {
"label": "Full time"
},
"tracking": {
"classificationInfo": {
"classification": "Information & Communication Technology",
"subClassification": "Programme & Project Management"
},
"locationInfo": {
"location": "Taguig City"
}
},
"products": {
"questionnaire": {
"questions": [
"What's your expected monthly basic salary?"
]
}
}
},
"gfjInfo": {
"location": {
"countryCode": "PH",
"country": "Philippines",
"suburb": "Bonifacio Global City",
"state": "Metro Manila",
"postcode": null
},
"workTypes": {
"label": [
"FULL_TIME"
]
}
},
"workArrangements": {
"arrangements": [
{
"type": "ONSITE",
"label": "On-site"
}
]
}
}
}
}
| Your field | Becomes | Notes |
|---|---|---|
| job.id | external_id | Re-sending the same id updates the job instead of creating a new one. |
| job.title | title | |
| job.abstract | abstract | Ignored when it just repeats the title. |
| job.content2 (or job.content) | description | HTML is cleaned to basic formatting. |
| job.expiresAt.dateTimeUtc | deadline_at | Must be in the future; jobs with job.isExpired = true are refused. |
| job.salary.label + currencyLabel | salary_min, salary_max, salary_currency, salary_period, salary_label | Amounts and period are read from the label, e.g. "₱120,000 – ₱130,000 per month". |
| gfjInfo.workTypes.label / job.workTypes.label | employment_type | FULL_TIME → full_time, CONTRACTOR → contract, … |
| workArrangements / badges | work_arrangement | ONSITE, REMOTE, HYBRID |
| tracking.classificationInfo | category, sub_category | Matched by name. Send "category" next to "data" to override. |
| gfjInfo.location + tracking.locationInfo.location | country, country_code, state, city, area, postcode | |
| products.questionnaire.questions | questions | Added as optional text questions. |
| job.isLinkOut + job.shareLink | apply_method, external_apply_url | Link-out jobs send candidates to your URL. |
6. Responses and errors
Jobs are returned as {"data": {…}} with id, external_id, status,
rejection_reason, public_url (once approved), salary, location, questions and dates.
POST /jobs also returns meta.created.
401missing or invalid token ·403missing permission,not_a_company,account_blockedorcompany_not_verified404the job does not exist or belongs to another company409invalid_status,cannot_deleteorduplicate_external_id422validation failed —errorslists the problems per field429rate limit reached — wait for theRetry-Afterseconds