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.