Bullhorn ATS & CRM to Power BI, done for you

A Bullhorn Power BI Dashboard Built From Your ATS and CRM Records

OAuth extraction from the Bullhorn REST API, a modelled star schema over job orders, submissions, candidates and placements, and DAX for time-to-fill, submittals-to-hire and recruiter margin — built by a senior US-based engineer, not exported to a spreadsheet every Monday.

  • Microsoft-certified
  • Read-only API access
  • Hours never expire
  • 3–5 day turnaround
  • You own the model
Revenue Overview Revenue$4.2M Margin38% Orders12.4k Churn2.1% Monthly performance By segment 64%

Representative dashboard — sample data

Where these projects actually stall

Getting the data out is the hard part. Charting it is not.

Bullhorn holds the whole recruiting lifecycle — the job order, every submission against it, the interviews, the placement, the rates — and hands almost none of it over in a shape a report can use. The REST API is paged, session-based, and fronted by an OAuth handshake that has to be provisioned before anyone writes a query. Related records arrive as nested references rather than clean foreign keys. That is where most in-house attempts run aground, long before anyone argues about chart colours.

So the work runs extraction, then modelling, then measures. Authenticate properly and page the history once. Flatten job orders, submissions, candidates, client corporations and placements into conformed dimensions and facts. Add the date table and the recruiter-to-desk mapping the ATS does not give you. Then write the DAX that turns dated events into time-to-fill, submittal ratios and gross profit per desk — numbers you would put in front of an owner without a caveat.

What we build from Bullhorn

  • Time-to-fill
  • Submittals-to-hire
  • Recruiter gross profit
  • Spread & margin
  • Placement & falloff trend
  • Desk-secured views

Try us risk-free for 4 hours

Buy a block of prepaid Flex hours and, if you're unhappy within the first 4 hours, we refund you in full — no questions asked. Hours are deducted only for work you've reviewed and approved, there's no project minimum, and your banked hours never expire.

What the build covers

Six things that decide whether this works

Every one sits upstream of the report page, and every one is where an in-house attempt tends to stop.

OAuth provisioned before code

API credentials requested from Bullhorn by your administrator, authorised against the endpoints your cluster actually uses, and scoped so reporting reads your instance rather than writing to it.

Sessions and paging handled

REST sessions expire and result sets are paged. History is pulled once in staged batches, then only records whose modified stamp has moved — the difference between a refresh that finishes and one that times out.

Nested references flattened

Candidate, client corporation, owner and job order arrive embedded inside each record. They become surrogate keys against real dimensions, so a client means one thing across submissions, placements and invoices.

Time-to-fill defined once

Open-to-start, open-to-offer, submit-to-interview: each is a different question. We agree the start and end events with you, then write them as separate measures rather than one ambiguous average.

Margin past the raw spread

Bill rate minus pay rate is the starting point, not the answer. Burden, overtime and unbilled hours from payroll or timekeeping turn spread into gross profit a finance lead will sign off on.

Refresh and security that hold

Scheduled or incremental refresh, row-level security by desk, branch or division, and failures fixed by us out of your banked hours rather than landing on whoever built it.

How does the OAuth connection to the REST API work?

Your administrator requests API credentials from Bullhorn — a client ID and client secret tied to an API user on your instance. We then run the standard OAuth 2.0 authorisation-code flow against the endpoints that serve your cluster, exchange the code for an access token and a refresh token, and open a REST session that returns the base URL your data actually lives behind. Bullhorn runs several data centres, so hard-coding a URL you found in a forum post is the first way this breaks.

Two things matter beyond getting a 200 back. First, scope: a reporting credential has no business being able to edit a candidate record, so we ask for read access and nothing more. Second, ownership: the credentials belong to your instance and are provisioned by your administrator, so nothing about the connection depends on us continuing to exist. If you later take the model in-house, the access is already yours. Where an agency already replicates Bullhorn into a SQL database or warehouse, we model from that copy instead — usually faster to refresh and easier to join to payroll.

Which Bullhorn entities does the model need?

Fewer than people expect. Almost every question a staffing owner asks — fill rate, time-to-fill, submittal ratios, gross profit by desk — resolves to some combination of job orders, submissions, placements, candidates and the client records they hang off. The table below maps each entity to the job it does once the data is modelled rather than listed.

Bullhorn entities and the role each one plays in the semantic model
Entity What it holds Role in the model
JobOrder Requisition detail, openings, status, employment type, client and owner references, dated open and close events Fact table for demand — the denominator behind fill rate and time-to-fill
JobSubmission Each candidate put forward against a job order, with status and the dates the status moved Fact table for recruiter activity and every submittal-to-hire ratio
Placement The filled assignment: pay rate, bill rate, start and end dates, employment type, fee where permanent Fact table for revenue, spread and contractor headcount over time
Candidate Candidate records, source, skills, status and owner Dimension for talent supply, redeployment and source-of-hire analysis
ClientCorporation Client accounts, status, industry and billing structure Client dimension — the key every fact table conforms to
ClientContact Hiring managers and their relationship to the account Dimension for contact-level activity and account penetration
CorporateUser Recruiters, account managers, teams and departments Desk dimension, joined to the recruiter-to-branch mapping you supply
Note and Appointment Logged calls, meetings, interviews and other dated activity Activity fact behind leading indicators rather than lagging results

Two structural details cause most of the rework. Related records — candidate, client corporation, owner, job order — arrive nested inside each result rather than as flat foreign keys, so they must be expanded and conformed into a star schema before any relationship exists. And most agencies have repurposed the numbered custom fields on job orders and placements to carry something load-bearing: a division, a margin category, a client-specific rate code. Those need documenting in scoping, because nothing in the API tells you that customText7 means "vertical".

How are time-to-fill and recruiter margin calculated?

In DAX, over a star schema, against a date table that covers the full history. The measures below are the ones that get argued about in every staffing engagement, because each one embeds a definition your leadership has to agree with before the number means anything at all. We write them explicitly and document them, rather than hiding the logic inside a query step.

Core staffing measures we build over the Bullhorn model
Measure How it is defined Why it is written this way
Time to Fill Average days from job order open date to the start date of the placed candidate Measured against placements, so cancelled and expired requisitions cannot flatter it
Time to Submit Average days from job order open to the first submission against it Separates a sourcing problem from a client decision problem — different fixes entirely
Submittals to Hire Submissions divided by placements, over the same period and desk Ratio, not a count, so a busy recruiter and an effective one stop looking identical
Fill Rate Job orders filled divided by job orders opened in the period Cohorted by open date, so a slow fill lands in the month the work was taken on
Spread Bill rate less pay rate on contract placements, weighted by hours Weighted, because an average of rates ignores how many hours each assignment ran
Gross Profit Spread less employment burden and unbilled hours, plus permanent placement fees Burden comes from payroll, so margin reflects cost rather than the rate on the record
Active Assignments Count of placements whose start and end dates span the selected date Point-in-time headcount and the ending-soon list that drives redeployment

Submittals-to-hire by desk is usually the measure that changes a conversation. It is arithmetically trivial and organisationally uncomfortable: it distinguishes the recruiter submitting twelve candidates to make one placement from the one submitting three, and it does it per desk rather than as an agency average that hides both. The modelling discipline underneath — conformed dimensions, one date table, measures instead of calculated columns — is the same craft described on our Power BI data modeling and DAX page.

Where does built-in ATS reporting stop?

Bullhorn ships perfectly reasonable reporting, and Canvas goes further for agencies that license it. Both are built to answer questions inside the ATS, against the ATS's own shape of the data. The questions agencies bring us are almost always the ones that cross a boundary — into payroll, into accounting, or across several years of restructured desks.

Built-in ATS reporting compared with a custom Power BI semantic model
What you are trying to do Reporting inside the ATS Custom Power BI model
Daily desk and pipeline lists Its core strength — live, in context, already built Possible, but not the reason to build a model
Gross profit including burden Burden and unbilled hours sit in payroll, outside the ATS Payroll joined to placements and costed hour by hour
Time-to-fill your way Fixed to the start and end events the report author chose Each definition an explicit, documented measure you can change
Multi-year trend across reorganised desks Constrained by current team structure Slowly changing dimension keeps history comparable
Client concentration and AR exposure Needs invoice and cash data the ATS does not hold Accounting modelled alongside placements as a second fact
Where the logic lives Inside the vendor's reporting layer In a model file in your own tenant, which you own outright

The practical answer is usually both. Keep the ATS views for running the desk, and build the model for the numbers that decide pricing, headcount and which accounts to defend. If what you want is the wider agency metric set rather than the Bullhorn plumbing, start with Power BI dashboards for staffing agencies instead — that page covers fill rate, spread and redeployment at an industry level, while this one is deliberately the technical half about extracting and modelling one source system.

How does refresh and desk-level security get set up?

The model is published to your Power BI workspace and refreshed on a schedule, following Microsoft's documented data refresh guidance (opens in new tab). For agencies with several years of submission and placement history, we normally configure incremental refresh (opens in new tab) so only a recent window is re-pulled each cycle rather than the entire history every morning.

One API-specific trap is worth naming. Paging a REST source means constructing request URLs in code, and the Power BI service refuses to refresh a query whose data source it cannot determine in advance. The fix is to keep the base address constant and vary only the relative path and query parameters. Desk-level visibility is then handled with row-level security (opens in new tab) driven from a mapping table of users to desks and branches, so onboarding a recruiter is a data change rather than a development task.

What does the build cost, and how long does it take?

Prepaid Flex hours that never expire: Starter 20 hours at $125/hr ($2,500), Growth 40 hours at $115/hr ($4,600), Power 80 hours at $100/hr ($8,000), with hourly work from $100/hour on the largest block. A first build covering job orders, submissions, placements and desk-level activity from a single Bullhorn instance usually fits a Starter block. Full gross-profit reporting — payroll burden, timekeeping hours, accounting reconciliation — typically needs Growth, because agreeing the burden rules takes discussion as well as development.

Most tasks ship within 3–5 business days of scope approval. You get a scope and hours estimate before anything starts, and hours deduct only for work you approve. Our guide to Power BI dashboard development cost covers what moves the number, and how prepaid Flex hours work explains the model in full.

Who is this for?

Staffing and recruiting agencies running Bullhorn with enough history to trend and no in-house data engineer — typically the point where someone exports to Excel every month and nobody quite trusts the result. Owners, operations leaders and finance managers are the people who usually get in touch, often after a quarter-end where two reports disagreed.

Agencies billing projects rather than placements should read Power BI for professional services, and if your commercial pipeline runs in a separate CRM, the Salesforce Power BI dashboard build covers modelling that alongside your ATS. Contact is form-only — send your request and we'll reply with a scope estimate.

What we build from Bullhorn

  • Time-to-fill, time-to-submit and fill rate
  • Submittal ratios by recruiter and desk
  • Spread and gross profit after burden
  • Active assignments and ending-soon lists
  • Desk and branch views secured by row-level security
3–5

business days, typical

Prepaid

hours, never expire

You

own everything

A first Bullhorn build usually fits inside one Flex block, and hours deduct only for work you approve. See Flex pricing →

How it works

From API credentials to a model you own

  1. 1

    Provision and scope

    Your administrator requests read-only API credentials from Bullhorn; we confirm which custom fields carry meaning, agree the time-to-fill and margin definitions, and reply with a scope and hours estimate before any work begins.

  2. 2

    Extract, model, measure

    A senior US-based engineer pages the history, flattens the nested references into conformed dimensions, builds the star schema and date table, and writes the DAX for time-to-fill, submittal ratios and gross profit — validating totals against your own ATS reports.

  3. 3

    Refresh, secure, hand over

    Published to your workspace with scheduled or incremental refresh, row-level security so each desk or branch sees only its slice, and documentation you keep. We maintain it from your banked hours.

Representative perspective

Submittals-to-hire per desk ended an argument we'd been having for two years. Two of our busiest recruiters were the least efficient once the ratio was on the screen.
Managing director, contract staffing agency

Representative perspective

Our own extract worked in Desktop and died on the first scheduled refresh. Getting the authentication and the paging done properly was most of the value.
Operations lead, healthcare recruiting firm

Get your recruiting data into a model you can defend

Tell us how you define time-to-fill, what payroll data you hold, and the reporting your leadership actually asks for. We'll confirm the access route, scope the task, and tell you the hours before anything starts — no project minimums, no obligation.

FAQ

Staffing reporting questions, answered

Through the Bullhorn REST API using OAuth 2.0. Your administrator requests API credentials from Bullhorn, we authorise against your cluster's endpoints, exchange the authorisation code for tokens, and open a REST session that returns the base URL your instance actually lives on. If your agency already replicates Bullhorn into a database, we can model from that copy instead.

Use them for the daily desk view. A separate model earns its place when you need several years of comparable trend, metrics defined the way your leadership defines them, or Bullhorn data joined to payroll, timekeeping and accounting so recruiter margin reflects burden and real cost rather than the spread on the placement record.

From dated events on the job order and placement records, using whichever start and end points your agency agrees on. Most firms measure from the date a job order opens to the date the placed candidate starts, and separately track time-to-submit and time-to-offer. We write each definition as an explicit DAX measure rather than burying it in a query.

Yes. Row-level security scopes a report so a recruiter sees their own desk, a manager sees their branch or division, and leadership sees everything. We drive it from a mapping table of users to desks, so adding a recruiter is a data change rather than a redevelopment task and no one receives a separate file.

No. We are an independent US-based Power BI consultancy with no Bullhorn partnership to claim. We build using documented, supported API access under credentials your administrator owns, and everything we produce is published into your own Power BI workspace and belongs to you if we never speak again.

Related work

For the agency-wide metric set rather than the source-system plumbing, Power BI dashboards for staffing agencies is the page to read next. Recruiting firms share their underlying economics with other people-based businesses, so professional services dashboards goes deeper on utilization and realization, and service businesses running a PSA instead of an ATS should look at the ConnectWise Power BI dashboard build. Commercial pipeline held in Salesforce or HubSpot can be modelled alongside your placements, the accounting join for burden and AR is covered on our QuickBooks page, and the craft underneath is described in data modeling and DAX and dashboard development. Every task is scoped before work begins from your prepaid block of senior-led hours — no project minimums, no change-order surprises, and hours are deducted only for work you approve.

Book a free demo

Get senior Power BI help, on demand

Tell us the task. We scope it, you approve, and a senior consultant delivers — typically in 3–5 business days. Prepaid hours that never expire.

  • Prepaid hours from $100/hour — and they never expire
  • Senior-led delivery — 20+ years on the Microsoft platform
  • Typical 3–5 business day turnaround
  • Full refund if you’re unhappy in your first 4 hours

The fastest way to reach us is the form — tell us the task and we'll reply within one business day.

All fields are required.

We reply within one business day. No newsletters, no drip campaigns.

Book a Free Demo