Skip to content

Lever Sensor

What it ingests

Hiring activity from Lever — the Data API, not the public Postings API used for career sites:

Lever objectOntology entitySignal
PostingProjectposting
OpportunityIssue + Person (identity)opportunity

A posting is a body of work (the Greenhouse job / HubSpot deal analog); an opportunity is the pipeline ticket. The candidate on an opportunity is identity — they resolve to Person via email/name, the same contract as a HubSpot contact or Greenhouse candidate. There is no separate candidate stream: Lever deprecated /candidates in favour of /opportunities.

This is Lever alone. Greenhouse is a different ATS with a different API (harvest.greenhouse.io) and stays its own source.

Read-only and poll-based against https://api.lever.co/v1. Lever webhooks exist but are configured in the Lever UI, never via API, so they cannot be provisioned at install time.

Credential

References a lever_api_key credential by id. The secret is a Lever API key. Lever authenticates with HTTP Basic: the key as the username and an empty password. Lever is a single cloud API, so there is no site URL beside the key.

OAuth is a partner-app product and will not authenticate here.

bash
curl -sS -X POST https://your-corveil-host/api/credentials \
  -H "Authorization: Bearer <admin>" -H "Content-Type: application/json" \
  -d '{"type":"lever_api_key","name":"acme-lever","secret":"<lever-api-key>"}'

Config fields

KeyRequiredNotes
enabled_objectsnoComma-separated Lever object kinds. Blank polls every supported kind. Unknown names are rejected at configure time.

Supported object names: postings, opportunities. jobs is accepted as an alias for postings; candidates and applications alias opportunities.

There is no default_entity_type. This source emits multiple primary types, so a single override would silently mistype the rest.

There is no app_host. Lever records already carry hire.lever.co URLs.

Provider-side setup

  1. In Lever, go to Settings → Integrations → API.
  2. Create an API key (not an OAuth partner app).
  3. Grant read access to postings and opportunities. Keys that can list postings may still 403 on opportunities.
  4. Copy the key. Store only the key value, not key: or Basic ….
  5. Optional: enable confidential-data access on the key if you need confidential postings and opportunities. v1 requests Lever's default (non-confidential).

Wire-up

POST /api/sensors

json
{
  "sensor_type": "lever",
  "name": "Acme Lever",
  "config": {
    "enabled_objects": "postings, opportunities"
  },
  "credentials": { "api_key": "<lever_api_key credential id>" }
}

Verify

Run Test connection. It authenticates the key against the first enabled object's list endpoint, so a 401/403 fails at save/test rather than on the first poll.

Once polling, each object kind's count appears in the per-poll summary log (postings_collected, opportunities_collected). A kind stuck at zero while the other moves is the signal to check that kind's Lever permission.

How incremental sync works

Worth knowing, because it explains a few behaviours you may notice.

  • Opportunities filter on updated_at_start (epoch milliseconds). That filter matches any change on the opportunity, not the updatedAt field Lever returns on the record. Corveil pins the millisecond literal with a test.
  • Postings are re-listed each tick. Lever refuses updated_at_* in combination with expand, and expand is how hiring-manager names arrive. Posting volume is small; the extra list is cheaper than dropping WORKS_ON edges.
  • Each opportunities poll re-reads a two-minute overlap. Lever list clocks can lag the write, so a strict resume would step permanently past a record that was briefly behind.
  • Deletes are invisible. A record vanishing from results is not treated as a deletion.
  • Rate limits are shared. Lever's published budget is 10 requests per second per API key, shared with every other Lever integration in the account. The source paces itself under that floor and backs off for the cycle on a 429 rather than retrying in-loop.

Not included

  • Greenhouse. A different ATS; do not configure this source against Greenhouse Harvest.
  • OAuth / partner apps. Only needed for multi-customer marketplace distribution.
  • Webhooks. Lever supports them, but subscriptions are created in the Lever UI, never via API — so they cannot be provisioned at install time. Polling is the supported path.
  • Interviews, feedback, offers. Lever has no account-wide list; they are per-opportunity N+1, the same class the Greenhouse source deferred as activity-feed N+1.
  • EEOC, attachments, requisitions, the public Postings API (career site). Deferred.