Installation
composer require darvis/bullhorn-api
In Laravel the service provider and the Bullhorn facade register themselves. Without Laravel, see Without Laravel.
Credentials
Bullhorn gives you four values for a REST API integration. Put them in .env:
BULLHORN_CLIENT_ID=your-client-id
BULLHORN_CLIENT_SECRET=your-client-secret
BULLHORN_USERNAME=your.api.user
BULLHORN_PASSWORD=the-password-of-the-api-user
The API user must have logged in to Bullhorn once and accepted the terms of service. Until it has, the login ends without an authorization code.
Optional settings
| Variable | Default | What it does |
|---|---|---|
BULLHORN_API_VERSION | * | Sent as version to the REST login. * is the latest. |
BULLHORN_CONNECT_TIMEOUT | 10 | Seconds to wait for the connection. |
BULLHORN_LOGIN_INFO_URL | https://rest.bullhornstaffing.com/rest-services/loginInfo | Where the data center of the API user is looked up. |
BULLHORN_OAUTH_URL | empty | The OAuth URL of your data center. Set it with BULLHORN_REST_URL to skip loginInfo. |
BULLHORN_REST_URL | empty | The REST URL of your data center, such as https://rest-emea.bullhornstaffing.com/rest-services. |
BULLHORN_SESSION_CACHE | true | Keep the session in the cache. Off: every process logs in. |
BULLHORN_SESSION_CACHE_STORE | empty | A store from config/cache.php; empty is the default store. |
BULLHORN_SESSION_TTL | 60 | Minutes a session lives without a call, sent as ttl to the REST login. |
BULLHORN_TIMEOUT | 30 | Seconds for a whole request. |
To change the config file itself:
php artisan vendor:publish --tag=bullhorn-config
The session cache
The session goes into your application’s cache, encrypted with APP_KEY, so every web request, queue worker and command shares one. Use a store that all of them reach and that has locks: redis, database, memcached or file on a single server. The array store lives only as long as one request, so every request would log in again.
When the cache is down the client goes on with the session in memory and writes one warning to the log. A call to Bullhorn never fails because of the cache.
After rotating APP_KEY the cached session cannot be decrypted. The client treats that as “no session” and logs in once.
Check that it works
php artisan bullhorn:test
It logs in when there is no session yet, pings, and prints:
Testing Bullhorn API connection...
✓ Connection successful! Session expires 2026-10-19 14:32:10.
--fresh drops the kept session first and logs in again. Bullhorn limits logins, so use it only to test the credentials themselves.
When it fails, the first word says where: Login failed is about the credentials or the data center, Ping failed about the API. See Troubleshooting.