# Bullhorn redeployment board for contracts ending soon

> See every contract placement ending in the next 90 days, ranked by revenue at risk, and redeploy your finishers before they walk out the door.

- Workflow type: app
- Services: Bullhorn, Gmail, Google Sheets
- Categories: Operations, HR & People
- Published: 2026-08-16

## What it does

- Builds a working board of every contractor whose assignment ends in the next 90 days, split into columns by weeks remaining so the urgent finishers sit up front
- Ranks every card by revenue at risk, bill rate times contracted weekly hours, so the biggest contracts get attention first
- Opens a side panel with the contractor's skills and work history next to your open roles that plausibly match, so a recruiter can put them forward on the spot
- Lets you submit a contractor to a job, email the contractor or the client, set a redeployment status that sticks, and export the board to a spreadsheet for the weekly delivery meeting

## What you'll need

- A Bullhorn account with API access and permission to view placements, jobs and candidates
- A Google account for sending email and for the tracker spreadsheet
- A spreadsheet you want to use as the running redeployment tracker
- Bill rates and contracted weekly hours filled in on your placements, so the revenue at risk ranking is accurate

## Prompt

I run a contract desk and I lose money every time a contractor finishes an assignment without a next one lined up. Build me a redeployment board that I open and work out of. There is no schedule and no trigger here: a person opens the app, works the board, and takes action from it.

The board reads from Bullhorn. Call Authenticate and Get Session once at the start of a handler run and reuse the returned BhRestToken and restUrl for every following call in that run, because the session is short lived and cannot be re-established mid run. Load every Placement whose dateEnd falls between today and 90 days from now using Search Entities with Lucene syntax against Placement. Every Bullhorn read needs an explicit fields list, and all Bullhorn timestamps are epoch milliseconds, so do the date maths on dateEnd in milliseconds. Ask for everything the card needs in one pass: the candidate name and id, the job order title and id, the client corporation, billRate, the contracted weekly hours, dateEnd, and the owning recruiter. Where a field is not available on Placement, fill the gaps with batched Search Entities reads on JobOrder and Candidate by id rather than one call per card, and page through results with start and count.

Lay the board out in three columns by weeks remaining until the end date: 0 to 2 weeks, 3 to 6 weeks, and 7 to 13 weeks. Within each column sort by revenue at risk, which is the bill rate multiplied by the contracted weekly hours, so the biggest contracts surface first. Show the revenue at risk figure on each card and a total at the top of each column.

Each card shows the contractor, the client, the job title, the bill rate, the owning recruiter, and the placement end date with the number of weeks remaining. If contracted weekly hours are missing on a placement, still show the card, rank it on bill rate alone, and mark it visibly so someone can go and fix the record.

Clicking a card opens a side panel. On one side show that contractor's profile: skills and category read from the Candidate record with Search Entities, and their work history read with Query Entities in JPQL against CandidateWorkHistory filtered to that candidate id. On the other side show my currently open job orders, read with Search Entities on JobOrder filtered to open and accepting candidates, ranked by how plausibly each one matches the contractor on skills overlap, job title similarity, location and rate. Give each match a one line reason so the recruiter can judge it in a second rather than reading two profiles side by side.

From that side panel the recruiter acts immediately. A put forward button on any matched job creates the submission in Bullhorn with Create Job Submission for that candidate and job order, then reflects the result on the card. Two email buttons open a composer with a short prefilled draft, one aimed at the contractor about their next assignment and one aimed at the client contact about extending, and send through the Gmail Send a Message operation from the signed in recruiter's mailbox. Always show the draft for editing first and never send anything automatically.

Every card carries a redeployment status the recruiter sets: extending, redeploying, ending, or redeployed. Persist the status in the app's own storage keyed by the Bullhorn placement id, along with who set it and when, and do not write it back to Bullhorn. Statuses are shared across the desk so everyone sees the same board, and they survive a refresh and a full data reload. Let me filter the board by status and collapse the ones that are already resolved.

An Export button appends the board as it currently stands to a Google Sheets tracker using Append Values, one row per placement with the contractor, client, job title, bill rate, weekly hours, revenue at risk, end date, weeks remaining, owning recruiter, redeployment status and the export date, so the weekly delivery meeting has a running record it can look back on.

Load the Bullhorn data behind a manual refresh button and show when the board was last loaded. A full 90 day board is a lot of records, so fetch it in as few calls as possible and keep the working set in the app rather than refetching every time someone opens a card.

## How to customize

- Change the 90 day lookahead or reshape the columns, for example 0 to 4 weeks and 5 to 12 weeks, to match how far ahead your desk plans
- Sort the board by end date, client or recruiter instead of revenue at risk, or filter it down to one office, division or owner
- Rename the redeployment statuses and edit the wording recruiters start from when they email a contractor or a client

## FAQ

### Does this change anything in my Bullhorn records?

It only reads from Bullhorn until you deliberately act. The one thing it writes is a job submission, and only when a recruiter clicks to put a contractor forward for a specific role. Redeployment statuses are stored in the app, not on the Bullhorn record.

### Where do the redeployment statuses live?

In the app itself, saved against each placement along with who set it and when. They survive a refresh and everyone on the desk sees the same board, so the Tuesday delivery meeting works from one shared view instead of a personal spreadsheet.

### Does it email contractors or clients on its own?

No. Nothing runs on a schedule and nothing sends by itself. The email buttons open a prefilled draft that the recruiter reads, edits and sends from their own mailbox.

### What if a placement has no contracted weekly hours recorded?

The card still appears on the board. It gets ranked on bill rate alone and is flagged so someone can go and fix the underlying record.

### Can I use it without the spreadsheet export?

Yes. The export is one button for the weekly meeting. Skip it and the board works exactly the same.

Use this prompt in General Input: https://www.generalinput.com/prompts/bullhorn-redeployment-board-for-contracts-ending-soon