Bullhorn REST API for PHP and Laravel

darvis/bullhorn-api is a client for the Bullhorn REST API, the API of the Bullhorn staffing and recruitment CRM. It logs in with OAuth, keeps one session for all your requests, renews that session when Bullhorn ends it, and sends your calls with the session token.

The client is plain PHP and works in any project. In a Laravel application the package adds a service provider, a facade, an encrypted session cache and a connection test on top of the same client.

What it does

  • The whole login. loginInfo, the OAuth code, the access token and the REST login, on the first call and not before. Creating the client calls nothing.
  • One session for every request. The session is kept in a store that all PHP processes share: Laravel’s cache, encrypted, or a file outside the web root. Bullhorn limits how often an API user may log in; this keeps it to one.
  • Safe renewal. On a 401 the client takes the session another process already renewed, or renews it with the refresh token under a lock, and repeats the call once. When the refresh token is no longer accepted it logs in again.
  • Helpers that use Bullhorn’s verbs: createEntity() sends PUT and updateEntity() sends POST, plus entity(), deleteEntity(), search(), query(), meta(), upload() and ping().
  • Every other endpoint through get(), post(), put() and delete(), with a path relative to your corporation’s REST URL.
  • Failures you can act on: a BullhornException with the whole response in the message, the HTTP status, Bullhorn’s errorKey() and the rejected invalidFields(); an AuthenticationException when the login itself fails.
  • Secrets stay out of sight: removed from every exception message, never in a log line or command output.
  • Is Bullhorn alive? isAlive() answers true or false and never throws, for a health check or an if around a feature.
  • Examples for every common task: thirteen runnable scripts and a page of Laravel examples, commented step by step.
  • In Laravel: the Bullhorn facade, Http::fake() in your tests, and php artisan bullhorn:test.

What it does not do

  • No Eloquent models, no migrations and no database tables. You get arrays back and keep what you need yourself.
  • No synchronisation, no scheduler and no queue jobs. When and how often you call Bullhorn is up to your application.
  • No event subscriptions helper and no paging helper yet. Both work through get() and put() with the parameters Bullhorn documents.
  • No retries of a 429 or a 5xx. Whether a failed POST may be sent again is your application’s decision.

Pages

Page What is on it
Installation Install, configure, and check the connection
Quick start The calls you need first, and how a failure looks
Examples Recipes to copy: health check, candidates, jobs, applications, CVs, notes, forms, queues and tests
Without Laravel The client in any PHP project, with a file store
How it works The login, the shared session, renewal and the lock
API reference Every public method, the config and the exceptions
Testing Http::fake() and FakeTransport
Troubleshooting Every message the package can give, and what to do
Migrating From jonathanraftery/bullhorn-rest-client
FAQ Short answers

Requirements

  • PHP 8.2 or newer
  • The cURL extension, for projects without Laravel
  • Laravel 11, 12 or 13, for the Laravel integration
  • REST API credentials from Bullhorn: client id, client secret, API username and password