{
  "info": {
    "_postman_id": "d7b940d0-4f10-4774-9544-4e2dc30e097b",
    "name": "Job Portal API",
    "description": "Job publishing API for companies.\n\n1. Set the collection variable `token` (create one at /company/api, or use the token printed by `./deploy.sh --demo`).\n2. Check `base_url` (default http://localhost:8080).\n3. Run \"Create job\" - the new job's id is saved to `job_id` for the other requests.\n\nFull reference: {{base_url}}/developers",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Dates the API needs in the future: deadline in 30 days, job-board expiry in 14 days.",
          "const day = 24 * 60 * 60 * 1000;",
          "pm.collectionVariables.set('deadline', new Date(Date.now() + 30 * day).toISOString().slice(0, 10));",
          "pm.collectionVariables.set('expires_at', new Date(Date.now() + 14 * day).toISOString());"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "http://localhost:8080"
    },
    {
      "key": "token",
      "value": ""
    },
    {
      "key": "job_id",
      "value": ""
    },
    {
      "key": "deadline",
      "value": ""
    },
    {
      "key": "expires_at",
      "value": ""
    },
    {
      "key": "board_job_id",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "1. Reference data",
      "item": [
        {
          "name": "Categories",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/categories",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "categories"
              ]
            },
            "description": "Category and sub-category ids, slugs and names you can send as `category` / `sub_category`."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Allowed values",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/options",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "options"
              ]
            },
            "description": "Allowed values for employment_type, work_arrangement, job_level, salary_period, currencies and question types."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "2. Post a job",
      "item": [
        {
          "name": "Create job (native format)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs"
              ]
            },
            "description": "Creates the job (201) and submits it for approval (status `pending`). Sending the same `external_id` again updates that job instead (200). Use `\"submit\": false` to keep a draft.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_id\": \"MY-ATS-1001\",\n  \"title\": \"Senior Laravel Developer\",\n  \"category\": \"information-communication-technology\",\n  \"sub_category\": \"Software Development\",\n  \"employment_type\": \"full_time\",\n  \"work_arrangement\": \"hybrid\",\n  \"job_level\": \"senior\",\n  \"vacancies\": 2,\n  \"experience_min\": 4,\n  \"experience_max\": 8,\n  \"education_requirement\": \"BSc in CSE or related\",\n  \"skills\": [\n    \"Laravel\",\n    \"MySQL\",\n    \"REST\"\n  ],\n  \"abstract\": \"Build and scale our hiring platform.\",\n  \"description\": \"<p>You will design and build REST APIs.</p><ul><li>4+ years with Laravel</li><li>Strong SQL</li></ul>\",\n  \"salary_min\": 120000,\n  \"salary_max\": 160000,\n  \"salary_currency\": \"BDT\",\n  \"salary_period\": \"month\",\n  \"salary_negotiable\": true,\n  \"country\": \"Bangladesh\",\n  \"country_code\": \"BD\",\n  \"city\": \"Dhaka\",\n  \"area\": \"Gulshan\",\n  \"deadline_at\": \"{{deadline}}\",\n  \"questions\": [\n    \"What is your notice period?\",\n    {\n      \"question\": \"Have you used Laravel queues in production?\",\n      \"type\": \"yes_no\",\n      \"required\": true\n    }\n  ],\n  \"submit\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('job saved', () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));",
                  "const body = pm.response.json();",
                  "if (body.data && body.data.id) {",
                  "    pm.collectionVariables.set('job_id', body.data.id);",
                  "    console.log('job_id =', body.data.id, 'status =', body.data.status);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Create job (job-board data.jobDetails format)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs"
              ]
            },
            "description": "The same JSON you send to other job boards. Fields about the other platform are ignored; `job.id` becomes `external_id`. Add native fields next to `data` to override, e.g. \"category\": \"sales\".",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"data\": {\n    \"jobDetails\": {\n      \"job\": {\n        \"id\": \"94933960\",\n        \"title\": \"DELIVERY MANAGER & RELEASE MANAGER\",\n        \"abstract\": \"DELIVERY MANAGER & RELEASE MANAGER\",\n        \"content2\": \"<p>🚨 <strong>WE’RE HIRING | DELIVERY MANAGER &amp; RELEASE MANAGER</strong></p><p>📍 <strong>Location:</strong> BGC, Taguig<br>🏢 <strong>Work Setup:</strong> Full Onsite<br>💰 <strong>Salary:</strong> ₱120,000–₱130,000 + Benefits</p><h2>🎯 QUALIFICATIONS</h2><p>✅ At least <strong>5 years of experience</strong> in Delivery Management<br>✅ Proficient in <strong>Jira</strong></p>\",\n        \"isExpired\": false,\n        \"isLinkOut\": false,\n        \"expiresAt\": {\n          \"dateTimeUtc\": \"{{expires_at}}\"\n        },\n        \"salary\": {\n          \"currencyLabel\": \"PHP\",\n          \"label\": \"₱120,000 – ₱130,000 per month\"\n        },\n        \"workTypes\": {\n          \"label\": \"Full time\"\n        },\n        \"tracking\": {\n          \"classificationInfo\": {\n            \"classification\": \"Information & Communication Technology\",\n            \"subClassification\": \"Programme & Project Management\"\n          },\n          \"locationInfo\": {\n            \"location\": \"Taguig City\"\n          }\n        },\n        \"products\": {\n          \"questionnaire\": {\n            \"questions\": [\n              \"What's your expected monthly basic salary?\",\n              \"Do you have experience using Microsoft Intune?\"\n            ]\n          }\n        }\n      },\n      \"gfjInfo\": {\n        \"location\": {\n          \"countryCode\": \"PH\",\n          \"country\": \"Philippines\",\n          \"suburb\": \"Bonifacio Global City\",\n          \"region\": \"Bonifacio Global City\",\n          \"state\": \"Metro Manila\",\n          \"postcode\": null\n        },\n        \"workTypes\": {\n          \"label\": [\n            \"FULL_TIME\"\n          ]\n        }\n      },\n      \"workArrangements\": {\n        \"arrangements\": [\n          {\n            \"type\": \"ONSITE\",\n            \"label\": \"On-site\"\n          }\n        ]\n      }\n    }\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('job saved', () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));",
                  "const body = pm.response.json();",
                  "// Kept separate: the requests under \"3. Manage jobs\" use the job from \"Create job (native format)\".",
                  "if (body.data && body.data.id) {",
                  "    pm.collectionVariables.set('board_job_id', body.data.id);",
                  "    console.log('board_job_id =', body.data.id, 'status =', body.data.status);",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "3. Manage jobs",
      "item": [
        {
          "name": "List my jobs",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs?per_page=20",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs?per_page=20"
              ]
            },
            "description": "Filters: status (draft, pending, live, rejected, closed), external_id, per_page (max 100)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Show job",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs/{{job_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs",
                "{{job_id}}"
              ]
            },
            "description": "Status, rejection_reason and public_url (after approval)."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Update job (only changed fields)",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs/{{job_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs",
                "{{job_id}}"
              ]
            },
            "description": "Send only the fields that change. A rejected job with \"submit\": true goes back for approval.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"salary_max\": 180000,\n  \"vacancies\": 3\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('status 200', () => pm.response.to.have.status(200));"
                ]
              }
            }
          ]
        },
        {
          "name": "Close job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs/{{job_id}}/close",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs",
                "{{job_id}}",
                "close"
              ]
            },
            "description": "Only live (approved) jobs can be closed."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('closed, or 409 because the job is not approved (live) yet', () => pm.expect(pm.response.code).to.be.oneOf([200, 409]));",
                  "if (pm.response.code === 409) console.log(pm.response.json().message);"
                ]
              }
            }
          ]
        },
        {
          "name": "Delete job",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/jobs/{{job_id}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "jobs",
                "{{job_id}}"
              ]
            },
            "description": "Only draft, pending or rejected jobs without applicants."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('deleted', () => pm.response.to.have.status(204));"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
