Lever
Post a job to Lever: title, team/department/location categories, description, requirement lists, workplace type, salary range, tags and requisition codes. BYOK-only, production writes.
Lever calls a job a posting. Use Lever to stand up a posting in the customer's ATS, and publish it.
It is a write target — Hyreflow reads only the user list, to resolve a perform_as and verify the key.
Free (BYOK). Lever writes cost no credits. Connect your own Lever API key from the dashboard
Integrations page. A Lever Super Admin mints the key under Settings → Integrations and API; access
to confidential objects is granted when the key is created, not later. list_users is the free connection check: it verifies the key and returns the users a perform_as comes from.
Capability
| Tool | Does | Cost |
|---|---|---|
create_job | Create a posting as a given user (draft unless state says otherwise) | Free |
set_job_state | Publish a posting (or move it to another state), as a given user | Free |
Every write needs a perform_as user
Lever has no system actor — every posting is attributed to a real Lever user, passed as
perform_as. That user becomes the creator and, unless owner says otherwise, the owner. Ask the user
whose Lever account the posting should be created under; do not guess an id.
create_job parameters
| Field | Type | Required | Notes |
|---|---|---|---|
perform_as | user id | yes | The Lever user the posting is created as. Sent as a query parameter, not in the body. |
text | string | yes | Title of the posting. |
categories.team | string | yes | The team the posting belongs to, e.g. Engineering. |
categories.department | string | yes | The department the team sits in. |
categories.location | string | yes | The job's location. |
categories.commitment | string | no | Work type, e.g. Full-time, Part-time, Internship. |
categories.allLocations | array of string | no | Additional locations. |
state | string | no | published, internal, closed, draft, pending, rejected. Defaults to draft. |
distributionChannels | array of string | no | internal, public. Defaults to BOTH. |
owner | user id | no | Who manages applicants. Defaults to perform_as. |
hiringManager | user id | no | The hiring manager for the posting. |
tags | array of string | no | Additional posting tags. |
content.descriptionHtml | string | no | Top-of-page description, HTML limited to Lever's subset. |
content.lists | array of {text, content} | no | Requirement/responsibility lists; content is HTML. |
content.closingPostingHtml | string | no | Custom closing statement, appended to any closing template. |
salaryDescriptionHtml | string | no | Free-text salary blurb, HTML. |
salaryRange.currency | string | no | ISO currency code, e.g. USD. |
salaryRange.interval | string | no | Payment interval, e.g. per-year-salary. |
salaryRange.min | integer | no | Bottom of the range. |
salaryRange.max | integer | no | Top of the range. |
workplaceType | string | no | onsite, remote, hybrid. |
requisitionCodes | array of string | no | Requisition codes to associate with the posting. |
perform_as (Lever user id, required) travels in the payload like any other field, and is sent
as the query parameter Lever requires rather than as part of the posting body.
hyreflow tools execute lever_create_job --payload '{
"text": "Senior Platform Engineer",
"state": "draft",
"categories": {"team": "Engineering", "department": "Technology",
"location": "Berlin", "commitment": "Full-time"},
"content": {"descriptionHtml": "<p>Own the deployment platform.</p>",
"lists": [{"text": "Requirements", "content": "<ul><li>Kubernetes</li></ul>"}]},
"workplaceType": "hybrid",
"perform_as": "8d49b010-cc6a-4f40-ace5-e86061c677ed"
}'The response is {data}; the posting's id is data.id, and data.urls carries the live
list/show/apply links once it's published.
state defaults to draft — the posting is not live unless you send "state": "published".
distributionChannels defaults to BOTH public and internal — an internal-only posting must say
["internal"] explicitly. Confirm both with the user before executing; publishing is the irreversible
half of this call.
set_job_state parameters
set_job_state is a partial update — POST /postings/{id} — that changes only what it sends.
| Field | Type | Required | Notes |
|---|---|---|---|
posting_id | string | yes | The posting to update. |
perform_as | user id | yes | The Lever user performing the update. Sent as a query parameter. |
state | string | no | published, internal, closed, draft, pending, rejected. Defaults to published. |
payload | object | no | Any of the create_job fields, to change alongside the state. |
hyreflow tools execute lever_set_job_state --payload '{
"posting_id": "730e37db-93d3-4acf-b9de-7cfc397cef1d",
"perform_as": "8d49b010-cc6a-4f40-ace5-e86061c677ed"
}'state defaulting to published takes a draft posting live on the sites named by its
distributionChannels.
Read the posting first so a partial update doesn't clobber a concurrent edit in Lever Hire — updating through the API skips the approvals chain, exactly like creating does.
What creating a posting does not do
- It does not publish by default —
stateisdraftunless told otherwise. - Creating through the API skips Lever's approvals chain. If the client runs approvals, create as
draftand let them route it inside Lever Hire. - A confidential posting cannot be created through the API at all.
Lever paces at 10 requests/second per key. Hyreflow already spaces calls — don't parallelize a batch of postings on top of that.