Skip to content

Bullhorn to Avionte Migration: APIs, Data Mapping & Limits

A CTO-level technical guide to migrating staffing data from Bullhorn to Avionte BOLD, covering API constraints, object mapping, rate limits, and real failure modes.

Raaj Raaj · · 19 min read
Bullhorn to Avionte Migration: APIs, Data Mapping & Limits
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,200+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

Migrating from Bullhorn to Avionte BOLD is a data-model translation problem, not a file-transfer exercise. Bullhorn structures staffing data around ClientCorporation → ClientContact → JobOrder → JobSubmission → Placement chains with deep relational associations and up to 35 custom object instances per entity type. Avionte BOLD uses a flatter, talent-centric Company → Contact → Job → Talent → Placement model with integrated back-office capabilities (payroll, billing, timekeeping) but significantly fewer extension points for custom data.

A naive CSV export from Bullhorn flattens these relational chains. It silently drops note associations, severs Candidate → Submission → Placement histories, and loses custom object data entirely. The core engineering challenge: Bullhorn's API enforces strict rate limits and complex pagination, while Avionte's native bulk import tools are designed for simple lists — not complex historical relationships. Moving data between these systems means merging Bullhorn Candidates into Avionte Talent, converting JobOrders into Jobs, serializing historical activities, and reconciling two fundamentally different ID systems.

This guide covers the architectural differences between both systems, every viable migration method with honest trade-offs, the API constraints that will bottleneck your ETL scripts, concrete object and field mapping, and the edge cases that break most DIY attempts.

For broader ATS migration pitfalls, see 5 "Gotchas" in ATS Migration. For a general assessment of CSV-based approaches, see Using CSVs for SaaS Data Migrations: Pros and Cons.

Why Staffing Agencies Migrate from Bullhorn to Avionte

The migration drivers are operational, not cosmetic:

  • Integrated back office: Avionte BOLD combines front-office ATS/CRM with payroll, billing, and tax management in a single platform. Bullhorn requires third-party back-office integrations (1Staff, Tempworks) that add cost and integration maintenance.
  • Light industrial and clerical focus: Avionte was purpose-built for high-volume temp staffing verticals — clerical, light industrial, IT staffing. Agencies in these verticals often find Avionte's workflows more aligned with their day-to-day operations.
  • Cost structure: Bullhorn's per-user pricing plus add-on costs for Automation, Marketplace integrations, and back-office connectors can push total cost of ownership significantly higher than Avionte's bundled model.
  • Simplicity over extensibility: Bullhorn offers deep customization (custom objects, Data Hub, extensive API). Some agencies don't need that complexity and prefer Avionte's more opinionated, streamlined workflow.

The trade-off is real: Avionte's simpler schema means you lose structural flexibility during migration. Custom objects, deep automation chains, and Bullhorn-specific integrations need to be rebuilt or retired.

The Data Model Gap: Bullhorn vs. Avionte BOLD

Understanding the architectural mismatch is the prerequisite for every migration decision.

Bullhorn models staffing data as a rich relational graph. The primary entities — ClientCorporation, ClientContact, Candidate, JobOrder, JobSubmission, Placement, Opportunity, Note, Appointment — are linked through one-to-one, one-to-many, and many-to-many associations. Custom objects (up to 35 per entity type for Person and ClientCorporation entities) extend this model further. Every entity carries customText, customInt, customFloat, and customDate fields.

Avionte BOLD uses a flatter, more opinionated model. The core entities are Company, Contact, Talent (the equivalent of Candidate), Job/Order, and Placement. Activities and notes are stored on the Talent record. The system has fewer custom field extension points and no equivalent to Bullhorn's custom object instances.

Concept Bullhorn Entity Avionte BOLD Equivalent Notes
Client company ClientCorporation Company Direct mapping; Bullhorn auto-creates an archived ClientContact when creating a ClientCorporation
Hiring manager ClientContact Contact Contacts in Avionte are tied to Companies
Candidate/worker Candidate Talent Avionte uses "Talent" for all candidate types
Job requisition JobOrder Job/Order Map status values manually (e.g., "Accepting Candidates" → "Open")
Submission JobSubmission Pipeline Stage Avionte pipelines candidates to jobs differently
Placement Placement Placement Back-office fields (pay rate, bill rate) map natively in integrated BOLD
Sales pipeline Opportunity No direct equivalent Must flatten to notes or custom fields
Notes Note Activity/Note Bullhorn Notes reference Candidate, ClientContact, JobOrder, or Placement; Avionte activities live on the Talent record
Appointments Appointment Activity Collapse into activity records
Custom objects PersonCustomObjectInstance1–35 No equivalent Data must be serialized into custom fields or discarded
File attachments CandidateFileAttachment Resume/Document Avionte supports resume parsing on import; other file types need API-level handling
Warning

Bullhorn's Opportunity entity has no direct equivalent in Avionte BOLD. If your agency uses Opportunities for sales pipeline tracking, that data must be flattened into notes, exported to a separate system, or abandoned. Plan this decision early. Similarly, if you heavily utilize Bullhorn's custom objects (e.g., tracking specialized certifications in a standalone table), you will need to flatten this data into custom fields on the Avionte Talent profile — or accept losing it.

Migration Approaches: CSV, API, Middleware, and Managed Service

Method 1: Native CSV Export/Import

How it works: Export data from Bullhorn's list views or Bullhorn Automation as CSV files. Clean and reformat the CSVs to match Avionte's import templates. Import into Avionte using the Talent Multi-Upload tool (for candidates) or the Bulk Import feature (for Jobs, Placements, and Companies).

When to use it: Small datasets (under 10,000 records), simple flat data with minimal relationships, or as a supplement to API-based migration for specific entity types.

Constraints:

  • Bullhorn Automation CSV exports are capped at 50,000 records per export.
  • Bullhorn's native list-view export is affected by column count — hyperlinked columns produce additional data and can cause the export to fail or time out. Including the Submissions column on a Candidate list view will export the five most recent submissions per record, potentially quintupling your result size.
  • Bullhorn's Custom Import tool only supports Candidates, Contacts, and Leads — up to 1,000 records per batch.
  • Avionte's Talent Multi-Upload accepts CSV files with thousands of records, but duplicate checking runs only against existing system data, not within the file itself.
  • Avionte's Bulk Import supports Jobs, Placements, and Companies — but does not handle relational data like historical activities, notes, or submission histories.
Pros Cons
No engineering required Flattens all relational data
Free / built-in Drops notes, activities, attachments
Good for quick data spot-checks 50K record cap on Bullhorn side
Manual field-mapping in spreadsheets
No custom object export

Complexity: Low | Risk: High for enterprise data | Scalability: Poor

For more on file-based migration limitations, see Using CSVs for SaaS Data Migrations: Pros and Cons.

Method 2: API-Based Custom ETL Pipeline

How it works: Build extraction scripts against the Bullhorn REST API to pull all entities with their full field sets and associations. Transform the data in a staging layer (normalize IDs, map picklists, restructure relationships). Load into Avionte using the Avionté Partner API (Talent Service, Company Service, Order Service).

When to use it: Enterprise datasets (50K+ records), when you need to preserve relational chains (Candidate → Submission → Placement), or when custom objects and attachments must migrate.

Constraints — Bullhorn side:

  • Authentication: Bullhorn uses a two-phase OAuth 2.0 flow. First, obtain an access token. Then, exchange it via a /login call for a BhRestToken and a dynamic restUrl. The BhRestToken expires after approximately 10 minutes of inactivity — your script must handle token refresh via the OAuth refresh token flow.
  • Rate limit: The maximum number of API calls is 1,500 per minute per API user. Exceeding this returns a 429 Too Many Requests response.
  • Pagination: Query and search results are capped at 500 records per request (default is 30). You must use start and count parameters to paginate through large result sets.
  • The restUrl is dynamic — it is returned at login time and must never be hardcoded.

Constraints — Avionte side:

  • The Avionté API program requires registration through the developer portal. Technology providers must apply to the API program and be approved.
  • The CreateTalent API enforces duplicate checking based on SSN → Email → First+Last Name (in that priority order). If SSN is provided, it's the only field used for dedup. If absent, Email is used. If neither is present, it falls back to name matching.
  • Not all fields configurable in BOLD's "New Talent Requirements" are available through the API.
  • Rate limits for the Avionte API are not publicly documented. You must contact your Avionte account manager for tenant-specific limits.
Pros Cons
Full control over relational data Requires dedicated engineering
Can preserve notes, activities, attachments Bullhorn rate limit requires throttling
Handles custom objects Avionte API access requires approval
Scriptable and repeatable Avionte rate limits undocumented

Complexity: High | Risk: Medium (with proper error handling) | Scalability: Excellent

If you are considering building your own pipeline, read The Data Migration Risk Model: Why DIY AI Scripts Fail.

Method 3: Middleware / Integration Platforms (Zapier, Make)

How it works: Use a no-code/low-code platform to connect Bullhorn triggers to Avionte actions. Typically used for ongoing sync rather than bulk historical migration.

When to use it: Only for ongoing sync of new records after the initial migration is complete. Not viable for bulk historical data.

Why it fails for migration: Middleware platforms process records one at a time. At 1,500 req/min on Bullhorn's side (and unknown limits on Avionte's), migrating 200K candidates would take days of continuous execution — assuming zero errors. These platforms also lack the transformation layer needed to restructure Bullhorn's relational model into Avionte's flatter structure.

Complexity: Low | Risk: High for bulk data | Scalability: Very Poor

Method 4: Managed Migration Service

How it works: A dedicated migration engineering team builds custom extraction, transformation, and loading scripts tailored to your specific Bullhorn configuration and Avionte target environment. They handle API authentication, rate limiting, relationship preservation, and validation.

When to use it: When you have 50K+ records, complex relational data, custom objects, or when your engineering team doesn't have bandwidth to build and maintain single-use migration scripts.

Pros Cons
Preserves relational chains Cost
Handles edge cases and error recovery Vendor selection required
No internal engineering time Less direct control
Typically includes validation and rollback planning

Complexity: Low (for you) | Risk: Low | Scalability: Excellent

Approach Comparison

Factor CSV Export/Import Custom API ETL Middleware Managed Service
Preserves relationships
Handles custom objects
Migrates attachments
Engineering effort None High Low None
Scalability < 50K records Unlimited < 1K records Unlimited
Risk of data loss High Medium High Low
Cost Free Engineering hours Subscription Service fee
Best for Quick checks, small datasets Enterprise with dev team Post-migration sync only Enterprise without dev bandwidth

Pre-Migration Planning & Data Audit

Before touching production data on either side, define the scope. A migration is the best time to purge legacy data.

Data Audit Checklist

  • Count records by entity type in Bullhorn: Candidates, ClientCorporations, ClientContacts, JobOrders, Submissions, Placements, Notes, Opportunities.
  • Identify custom objects in use: query Bullhorn's metadata API (/meta/Candidate?fields=*) to discover which customObject{#}s instances are active.
  • Catalog custom fields: map every customText, customInt, customFloat, customDate field to determine which carry real data vs. legacy/unused fields.
  • Map picklists: Bullhorn dropdowns often differ from Avionte's standard taxonomies. Document every picklist mapping.
  • Measure attachment volume: file attachments (resumes, signed documents) can be the largest data payload. Size this early.
  • Flag duplicate and stale records: Bullhorn does not hard-delete most entities by default — isDeleted soft-delete flags must be filtered before export.

Define Migration Scope

Not everything should migrate. Make explicit decisions:

  • Exclude candidates with isDeleted=true and no activity in 24+ months.
  • Exclude test records, training data, and placeholder companies (e.g., "TBD" companies created for contactless imports).
  • Decide on Opportunities: migrate as notes, export to a separate CRM, or discard.
  • Decide on custom objects: serialize to Avionte custom fields, export to a data warehouse, or discard.

Migration Strategy

Strategy Best For Risk
Big bang Small agencies (< 5K records), low complexity All-or-nothing; rollback is full revert
Phased by entity Mid-size agencies; migrate Companies → Contacts → Talent → Jobs → Placements in order Manageable; partial rollback possible
Incremental with cutover Enterprise; migrate historical data first, sync delta during parallel-run period, then cut over Lowest risk; highest engineering effort

For most staffing agencies with 50K+ records, the phased by entity approach works best. It respects dependency order (Companies must exist before Contacts can be linked) and allows validation checkpoints between phases.

Migration Architecture & API Constraints

Data Flow: Extract → Transform → Load

Bullhorn REST API ──► Staging DB / JSON Files ──► Transformation Layer ──► Avionte Partner API
       │                      │                          │                        │
   OAuth 2.0 +            ID mapping               Field mapping,           Bearer Token
   BhRestToken            tables                   picklist translation     authentication

Bullhorn Extraction

The Bullhorn REST API exposes entity data via /entity, /search, and /query endpoints.

  • /search uses Lucene syntax, returns up to 500 results per page. Best for full-text search across indexed fields.
  • /query uses SQL-like WHERE clauses, also capped at 500 per page. Best for structured extraction by date range or status.
  • /entity/{type}/{id} retrieves specific records by ID. Supports comma-separated IDs for batch gets.

For large-scale extraction, use /query with date-range windowing:

# Paginated extraction from Bullhorn
import requests
import time
 
BASE_URL = "{restUrl}"  # Dynamic, from login response
TOKEN = "{BhRestToken}"  # From login response
 
def extract_entity(entity_type, fields, where_clause):
    all_records = []
    start = 0
    count = 500  # Max per request
    total = None
    
    while total is None or start < total:
        params = {
            "where": where_clause,
            "fields": fields,
            "count": count,
            "start": start,
            "showTotalMatched": "true",
            "BhRestToken": TOKEN
        }
        
        resp = requests.get(f"{BASE_URL}/query/{entity_type}", params=params)
        
        if resp.status_code == 429:
            time.sleep(1)  # Back off on rate limit
            continue
        
        if resp.status_code == 401:
            refresh_token()  # BhRestToken expired
            continue
            
        data = resp.json()
        total = data.get("total", 0)
        all_records.extend(data.get("data", []))
        start += count
        
        # Throttle to stay under 1,500 req/min
        time.sleep(0.05)
    
    return all_records
 
# Extract all active candidates
candidates = extract_entity(
    "Candidate",
    "id,firstName,lastName,email,phone,status,dateAdded,customText1,customText2",
    "isDeleted=false AND status='Active'"
)
Info

Bullhorn's BhRestToken has a default idle timeout of approximately 10 minutes. For long-running extraction jobs, implement a background token-refresh loop rather than refreshing only on 401 responses. Generating a new token for every request will flag your account and throttle your API access.

Avionte Loading

Avionte exposes separate service APIs for each domain: Talent Service, Company Service, and Order Service. Authentication uses Bearer tokens obtained through the Avionté Security Token Service.

# Create Talent record in Avionte
import requests
 
AVIONTE_BASE = "https://api.avionte.com"  # Tenant-specific
BEARER_TOKEN = "{token_from_STS}"
 
def create_talent(talent_data):
    headers = {
        "Authorization": f"Bearer {BEARER_TOKEN}",
        "Content-Type": "application/json",
        "Origin": "MigrationScript"  # Must be consistent across all calls
    }
    
    payload = {
        "FirstName": talent_data["firstName"],
        "LastName": talent_data["lastName"],
        "Email": talent_data["email"],
        "Phone": talent_data.get("phone", ""),
        "Status": map_status(talent_data["status"]),
        "useNewTalentRequirements": False  # Bypass BOLD field requirements
    }
    
    resp = requests.post(
        f"{AVIONTE_BASE}/talent/v1/CreateTalent",
        json=payload,
        headers=headers
    )
    
    return resp.json()
Warning

The Avionte CreateTalent API checks for duplicates using SSN first, then Email, then First+Last Name. If you're migrating records that share email addresses (common in staffing when a candidate re-applies through different channels), plan your dedup strategy before loading.

Step-by-Step Migration Process

Phase 1: Extract from Bullhorn

  1. Authenticate — complete the OAuth 2.0 flow, obtain BhRestToken and restUrl.
  2. Extract reference data first — Skills, BusinessSectors, Categories, Sources. These are lookup entities needed to resolve foreign keys.
  3. Extract Companies — query ClientCorporation with isDeleted=false. Include address, status, custom fields.
  4. Extract Contacts — query ClientContact, include the clientCorporation.id foreign key.
  5. Extract Candidates — query Candidate, include skills (via association endpoint), custom fields, custom objects.
  6. Extract JobOrders — include clientCorporation.id, status, start/end dates.
  7. Extract SubmissionsJobSubmission records link Candidates to JobOrders.
  8. Extract Placements — include pay rate, bill rate, dates, associated Candidate and JobOrder IDs.
  9. Extract Notes — Bullhorn Notes can reference Candidates, ClientContacts, JobOrders, or Placements via personReference, jobOrder, and placements fields.
  10. Extract File Attachments — use /entity/{entityType}/{id}/fileAttachments to get metadata, then download each file.

Store all raw JSON payloads in a staging database (PostgreSQL or MongoDB). Do not transform data in memory during extraction — if the script crashes, you lose your place.

Phase 2: Transform

  1. Build an ID mapping table — Bullhorn integer IDs → Avionte IDs (populated during load). This is the backbone of the entire migration.
  2. Map picklist/status values — Bullhorn's candidate statuses, job statuses, and sources won't match Avionte's. Create an explicit mapping dictionary.
  3. Flatten custom objects — serialize Bullhorn PersonCustomObjectInstance data into Avionte custom fields. If Avionte doesn't have enough custom field slots, decide what to drop.
  4. Restructure Notes — Bullhorn Notes are entity-agnostic (linked via personReference/jobOrder/placement). Avionte Activities live on the Talent record. Map Note → Talent Activity, preserving the original timestamp and author.
  5. Normalize addresses — Bullhorn stores addresses as nested objects. Avionte expects flat fields.
  6. Cleanse HTML from text fields and rich-text notes.
  7. Handle multi-value fields — Bullhorn Skills are many-to-many associations. Avionte uses tag-based competencies (Category + Skill). Map the skill taxonomy explicitly.

Phase 3: Load into Avionte

Load in strict dependency order:

  1. Companies — create Company records, capture Avionte Company IDs, update the mapping table.
  2. Contacts — link to Companies using the mapping table.
  3. Talent — create Talent records with mapped statuses and skills.
  4. Jobs — link to Companies.
  5. Placements — link to Talent and Jobs.
  6. Activities/Notes — attach to Talent records.
  7. Attachments — resumes and documents.

Phase 4: Validate

  1. Record count comparison — total records per entity type in Bullhorn vs. Avionte.
  2. Field-level sampling — randomly select 50–100 records per entity type and compare field values.
  3. Relationship validation — verify that Contact → Company, Talent → Placement, and Placement → Job links are intact.
  4. Attachment verification — spot-check that resumes and documents are accessible in Avionte.

Common Failure Modes & Edge Cases

Broken Multi-Level Relationships

The chain ClientCorporation → ClientContact → JobOrder → JobSubmission → Placement is the core of staffing data. If you load entities out of order, or if a Company fails to create and you proceed to load its Contacts, you end up with orphaned records. Always load in dependency order and halt on parent-entity failures.

Custom Objects with No Home

Bullhorn supports up to 35 PersonCustomObjectInstances and 10 per JobOrder, Placement, Opportunity, and ClientCorporation. Avionte has no equivalent structure. Your options:

  • Serialize critical custom object data into Avionte's available custom fields (limited slots)
  • Export to a separate data warehouse for reference
  • Accept data loss and document what was dropped

Duplicate Records in Avionte

Avionte's CreateTalent API duplicate checking is aggressive. If two Bullhorn Candidates share an email address (common when the same person applied through different channels), the second create will be flagged as a duplicate and rejected. Pre-deduplicate on the Bullhorn side, or use the useNewTalentRequirements: false flag and handle dedup manually.

Orphaned Notes and Records

If a Bullhorn Note is tied to a Candidate that was deleted, the API might still export the Note. Avionte will reject it during import because the parent ID does not exist. Filter orphaned records during the transform phase.

Attachment Volume

Bullhorn file attachments are associated with Candidates, ClientContacts, ClientCorporations, JobOrders, Opportunities, or Placements. Avionte's Bulk Import does not handle file attachments — these must go through the API. Budget separately for attachment migration; for agencies with 100K+ candidate files, this can be the longest phase.

API Rate Limit Exhaustion

Bullhorn's 1,500 req/min limit sounds generous, but extracting a full dataset with associated entities, notes, and files burns through it fast. A single Candidate with skills (1 request), notes (1 request), files (1 request), and custom objects (1 request) costs 4 API calls. For 100K candidates, that's 400K requests — roughly 4.5 hours of continuous extraction at max throughput, assuming zero retries.

Multi-Level Company Hierarchies

Bullhorn allows deeply nested parent-child company hierarchies. Avionte handles this differently, often requiring you to flatten the hierarchy or use custom tagging.

Limitations & Data Loss Scenarios

Be explicit with stakeholders about what cannot make the trip:

Data Can It Migrate? Notes
Candidate/Talent core fields Direct mapping
Company and Contact records Direct mapping
Job Orders Status values need mapping
Placements Back-office fields map natively in integrated BOLD
Notes and Activities ⚠️ Requires API; loses multi-entity association (flattens to Talent)
Custom Objects Must serialize to custom fields or discard
Opportunities No Avionte equivalent
File Attachments ⚠️ API only; Bulk Import doesn't support
Automation rules & workflows Must be rebuilt in Avionte
Email history ⚠️ Partial; depends on what Bullhorn stored vs. email provider
Submission history ⚠️ Must be restructured into Avionte's pipeline model
Bullhorn Data Hub custom schemas No equivalent in Avionte

Validation & Testing Protocol

Before go-live, run this protocol:

  1. Test migration on sandbox — both Bullhorn and Avionte offer sandbox/test environments. Run the full migration pipeline against test data first.
  2. Record count reconciliation — automated comparison of source counts vs. target counts per entity type. Aim for 100% on core entities.
  3. Field-level spot check — randomly sample 2% of records (minimum 100) per entity type. Compare every field value.
  4. Relationship integrity check — for sampled records, verify that linked entities resolve correctly in Avionte.
  5. User Acceptance Testing (UAT) — have 3–5 recruiters perform their normal workflows in Avionte using migrated data. Ask them to find specific candidates, verify placement histories, and check that notes appear correctly.
  6. Rollback plan — Avionte doesn't have a one-click rollback. Your rollback plan is your Bullhorn instance, which should remain active and unchanged until validation is complete. Do not decommission Bullhorn until UAT passes.

Post-Migration Tasks

  • Rebuild automations — Bullhorn Automation workflows do not export. Recreate equivalent workflows in Avionte.
  • Reconfigure integrations — job board feeds, VMS connections, background check providers, and onboarding tools need to be reconnected to Avionte.
  • User training — Avionte BOLD has a different UI paradigm. Budget 1–2 weeks for recruiter training before cutting over.
  • Monitor for data drift — if you ran a parallel period, verify that any records created in Bullhorn during migration were captured in the final sync.
  • Archive Bullhorn — maintain read-only access to Bullhorn for at least 90 days post-cutover for reference and compliance purposes.

Sample Field Mapping Reference

Bullhorn Field Bullhorn Entity Avionte BOLD Field Avionte Entity Transform Notes
id Candidate N/A (internal) Talent Store in mapping table
firstName Candidate FirstName Talent Direct
lastName Candidate LastName Talent Direct
email Candidate Email Talent Direct; used for dedup
phone Candidate Phone Talent Strip formatting
status Candidate Status / StatusId Talent Picklist mapping required
address.address1 Candidate Address1 Talent Flatten nested object
address.city Candidate City Talent Direct
address.state Candidate State Talent Direct
address.zip Candidate Zip Talent Direct
customText1customText20 Candidate Custom fields (limited) Talent Map selectively
name ClientCorporation CompanyName Company Direct
clientContacts ClientCorporation Contacts (linked) Contact Rebuild association via mapping table
title JobOrder JobTitle Job Direct
startDate JobOrder StartDate Job Date format conversion
clientCorporation.id JobOrder CompanyId Job Resolve via mapping table
comments Note ActivityNotes Activity Flatten; lose multi-entity linkage
dateAdded Note ActivityDate Activity Preserve timestamp
payRate Placement PayRate Placement Direct
clientBillRate Placement BillRate Placement Direct

Best Practices Summary

  • Back up everything before starting. Export Bullhorn data to a separate archive, not just the migration staging area.
  • Run test migrations against sandbox environments. At least two full dry runs before touching production.
  • Load in dependency order: Companies → Contacts → Talent → Jobs → Placements → Notes → Attachments.
  • Maintain an ID mapping table throughout. Bullhorn integer IDs to Avionte IDs is the single most important artifact of the migration.
  • Validate incrementally — don't wait until the end to discover that 10K records failed.
  • Plan for data you'll lose — custom objects, Opportunities, and complex automation rules won't survive. Document these decisions for stakeholders before migration begins.
  • Keep Bullhorn active for at least 90 days post-cutover as a read-only reference.

When to Use a Managed Migration Service

Build in-house if:

  • You have < 10K total records with flat data (no custom objects, minimal notes)
  • You have a dedicated developer who can spend 3–6 weeks on the project
  • You're comfortable with Avionte's API program application process and undocumented rate limits

Don't build in-house if:

  • You have 50K+ records with deep relational chains
  • Custom objects carry business-critical data that needs to survive
  • You need zero downtime — recruiters can't stop working during migration
  • Your engineering team is already at capacity
  • You've never worked with either API before

The hidden cost of DIY migration isn't the initial build — it's the debugging. Bullhorn's API returns partial successes silently, Avionte's duplicate checking rejects records without clear remediation paths, and relationship breakages only surface when a recruiter can't find a placement three weeks after go-live.

At ClonePartner, we've handled ATS migrations with hundreds of thousands of records where relational integrity was non-negotiable. Our approach: extract with full association traversal, transform in a staging layer with complete ID mapping, load in dependency order with per-record error capture, and validate before cutover. We handle the Bullhorn rate-limit throttling, Avionte API enrollment, and the edge cases documented above so your team can keep recruiting.

For more on our approach to zero-downtime migration, see Zero Downtime Guaranteed. For a deeper look at why AI-generated migration scripts fail at scale, see Why DIY AI Scripts Fail and How to Engineer Accountability.

Frequently Asked Questions

Can I export data from Bullhorn to Avionte using CSV?
Yes, but with major limitations. Bullhorn Automation exports cap at 50,000 records, and CSV flattens all relational data. Avionte's Bulk Import handles Jobs, Placements, and Companies but not notes, activities, or attachments. For anything beyond simple flat data, you need the API.
What is the Bullhorn API rate limit?
Bullhorn enforces a maximum of 1,500 API calls per minute per API user. Exceeding this returns a 429 Too Many Requests error. The BhRestToken also expires after approximately 10 minutes of idle time, requiring a refresh token flow.
Does Avionte BOLD support custom objects like Bullhorn?
No. Bullhorn supports up to 35 PersonCustomObjectInstances and 10 per JobOrder, Placement, and ClientCorporation. Avionte BOLD has no equivalent structure. Custom object data must be serialized into available custom fields or exported to a separate system.
How long does a Bullhorn to Avionte migration take?
For small agencies (under 10K records) using CSV, a few days. For enterprise datasets (50K+ records) using API-based migration with full relational preservation, expect 2–6 weeks including test migrations, validation, and UAT. The Bullhorn extraction phase alone can take 4+ hours for 100K candidates due to rate limits.
What data is lost when migrating from Bullhorn to Avionte?
Bullhorn Opportunities have no Avionte equivalent and cannot migrate directly. Custom object instances must be flattened or discarded. Automation workflows must be rebuilt. Notes lose their multi-entity associations (they flatten to Talent-level activities). Submission history must be restructured into Avionte's pipeline model.

More from our Blog

5
ATS

5 "Gotchas" in ATS Migration: Tackling Custom Fields, Integrations, and Compliance

Don't get derailed by hidden surprises. This guide uncovers the 5 critical "gotchas" that derail most projects, from mapping tricky custom fields and preventing broken integrations to navigating complex data compliance rules. Learn how to tackle these common challenges before they start and ensure your migration is a seamless success, not a costly failure.

Raaj Raaj · · 14 min read
Zero Downtime Guaranteed: Why You Won't Have to
General

Zero Downtime Guaranteed: Why You Won't Have to "Pause" Your Business

Discover why "maintenance mode" is obsolete for modern businesses. ClonePartner guarantees zero downtime data migrations by replacing rigid automated tools with engineer-led, continuous synchronization bridges. Our custom approach allows for unlimited sample migrations and ensures your CRM, help desk, HRIS, E-commerce, etc remains fully operational throughout the entire transition.

Raaj Raaj · · 13 min read