[Cotlet](https://cotlet.dev/index.md) · [Integrations](https://cotlet.dev/integrations.md) · [How it works](https://cotlet.dev/how-it-works.md) · [Use cases](https://cotlet.dev/use-cases.md) · [Security](https://cotlet.dev/security.md) · [For developers](https://cotlet.dev/for-developers.md) · [For automation agencies](https://cotlet.dev/for-agencies.md) · [Blog](https://cotlet.dev/blog.md) · [API docs](https://cotlet.dev/docs.md) · [Help center](https://cotlet.dev/help.md) · [Changelog](https://cotlet.dev/changelog.md) · [Contact](https://cotlet.dev/contact.md) · [Pricing](https://cotlet.dev/pricing.md) · [Sign up](https://cotlet.dev/signup)

# Bullhorn API and MCP server

> Bullhorn has a REST API, but it is sold as a paid partner contract to technology vendors, not as a key for a recruiter or an agency (checked 23 Oct 2026). Bullhorn does not allow middleware or connector companies to build on it and has no official MCP server.

Applicant tracking and CRM for staffing and recruitment agencies: candidate and job records, notes, submissions and placements in one workflow.

## What is the Bullhorn API?

Cotlet's Bullhorn API exposes 9 endpoints for your own Bullhorn account: search candidates, get candidate, list candidate notes, get job, find matching candidates, list job submissions, add candidate note, submit candidates to a job and update submission status. The search_candidates endpoint returns candidates matching keywords in name, occupation, company, resume, work history and attachments. Each endpoint takes simple JSON inputs like job_id, cursor or candidate_id and works both as an operation of the bullhorn_read or bullhorn_write MCP tool for agents and as a REST call for scripts.

- **Category:** [HR & recruiting](https://cotlet.dev/integrations/category/hr-recruiting.md)
- **Endpoints:** 9 (6 read, 3 write)
- **Updated:** 2026-10-24

Bullhorn has a REST API, but it is sold as a paid partner contract to technology vendors, not as a key for a recruiter or an agency (checked 23 Oct 2026). Cotlet is a hosted MCP server and REST API for Bullhorn with 9 endpoints (6 read, 3 write): you sign in once in your own cloud browser, your AI agent does the work.

## Does Bullhorn have an official API?

Bullhorn has a REST API, but it is sold as a paid partner contract to technology vendors, not as a key for a recruiter or an agency (checked 23 Oct 2026). Bullhorn does not allow middleware or connector companies to build on it and has no official MCP server.

| Task | Bullhorn official | Cotlet |
|---|---|---|
| Search candidates by keyword | Partly: Only for contracted vendors, not for an agency's own agent | Yes |
| Find matching candidates for a job | Partly: Only for contracted vendors | Yes |
| Read a candidate record and its notes | Partly: Only for contracted vendors | Yes |
| Read a job and its submissions | Partly: Only for contracted vendors | Yes |
| Add a note to a candidate | Partly: Only for contracted vendors | Yes |
| Submit candidates to a job | Partly: Only for contracted vendors | Yes |
| Change a submission status | Partly: Only for contracted vendors | Yes |
| Work in your own agency account without a partner contract | No | Yes |

Sources: [Bullhorn: API access FAQs](https://www.bullhorn.com/bullhorn-api-access-faqs/), [Bullhorn Help: Managing Notes in Bullhorn ATS](https://kb.bullhorn.com/ats/Content/BHATS/Topics/NoteManagement.htm), [Bullhorn Help: Submitting a Candidate to a Job](https://kb.bullhorn.com/ats/Content/BHATS/Topics/submittingCandidateToJobInternalSubmission.htm), [Bullhorn Developer Guide: Creating a Submission](https://bullhorn.github.io/Creating-a-Submission/)

## Quick reference

```text
Bullhorn has a REST API, but it is sold as a paid partner contract to technology vendors, not as a key for a recruiter or an agency (checked 23 Oct 2026). Bullhorn does not allow middleware or connector companies to build on it and has no official MCP server.
Cotlet provides a hosted MCP server and REST API for Bullhorn: 9 tools (6 read, 3 write).
Access       Sign up at https://cotlet.dev/app/signup?app=bullhorn, then request the app and create API keys in the Cotlet console.

MCP server   https://cotlet.dev/mcp/v1
MCP tools    bullhorn_read, bullhorn_write, reads and writes apart; call one with {"operation": "<operation>", "arguments": {...}}
REST base    https://cotlet.dev/api/v1/bullhorn, each operation at its own route, e.g. POST /api/v1/bullhorn/jobs/{job_id}/submissions
Auth         Authorization: Bearer <COTLET_API_KEY>. Listing endpoints and schemas needs no key; calling an endpoint needs one. Over MCP the input schemas come with sign-in.
Operations   search_candidates, get_candidate, list_candidate_notes, get_job, find_matching_candidates, list_job_submissions, add_note, add_submission, update_submission_status
Confirm      add_note, add_submission, update_submission_status (by default the user approves each call; the user can switch this off per tool, e.g. for scheduled automations)
Markdown     https://cotlet.dev/integrations/bullhorn-api-mcp-server.md

How access works:
1. The user signs up at https://cotlet.dev/app/signup?app=bullhorn, requests Bullhorn in the Cotlet console and creates an API key there.
2. The user signs in to Bullhorn once in their Cotlet Cloud Browser (their own Chrome in the cloud, opened from the console) and enables Bullhorn for agents. An agent cannot do this step.
3. The API key goes into the MCP client or the REST call as a bearer token.

Fits: people who want a hosted Bullhorn server that someone else maintains, including non-developers.

Policy: Cotlet never stores passwords, never solves CAPTCHAs, never bypasses MFA.
Company: legal details in the Terms of service at https://cotlet.dev/terms. Contact contact@cotlet.dev.
Sign-in: the user signs in to Bullhorn in their own Cloud Browser, a Chrome Cotlet runs for them in the EU; password saving is off, the profile is AES-256-GCM encrypted, and agents get Bullhorn only after the user enables it. Calls are requests from that browser's IP with its cookies, each listed in the user's Background activity. Disable for agents, signing out in the browser or Reset browser cuts access. Cotlet is run by Take Group sp. z o.o. (EU VAT PL6342984273).
API key: holds no Bullhorn login or cookies, only asks Cotlet to run a tool. Each key is scoped to chosen apps and tools, read only or read and write. Actions that reach other people wait for the user's approval by default, so a leaked key cannot post or message as the user. Every call is in the activity log; deleting the key ends access at once.
Terms: the user stays responsible for following Bullhorn's terms; Cotlet is not affiliated with Bullhorn.
```

## What can an AI agent do in Bullhorn?

Cotlet is best for recruiters and small agencies who use Bullhorn and want an AI agent to match, note and submit candidates without running or fixing a server.

- **[Log screening notes on candidate records](https://cotlet.dev/integrations/bullhorn-api-mcp-server/log-screening-notes.md)** (runs: daily): "Here are my call notes from today. For each candidate, find the record in Bullhorn and add a Phone Call note with the summary. Skip anyone who already has a note from today." → `search_candidates`, `list_candidate_notes`, `add_note`
- **[Find and submit matching candidates for a job](https://cotlet.dev/integrations/bullhorn-api-mcp-server/submit-matching-candidates.md)**: "For job 77314, find matching candidates within 20 miles, read the top five records and tell me who fits. After my OK, submit the ones I pick." → `get_job`, `find_matching_candidates`, `get_candidate`, `add_submission`
- **[Clean up stale submissions](https://cotlet.dev/integrations/bullhorn-api-mcp-server/clean-up-stale-submissions.md)** (runs: weekly): "For my open jobs, list submissions still in Submitted for more than 14 days. Move the ones the job owner rejected to Sales Rep Rejected and list the rest for me." → `get_job`, `list_job_submissions`, `update_submission_status`
- **Weekly pipeline summary per job** (runs: weekly): "Every Monday, for jobs 77314, 77502 and 77610, tell me how many submissions sit in each stage and who moved since last week." → `get_job`, `list_job_submissions`
- **Find past candidates to re-engage**: "Search for candidates with "data engineer" in their resume, exclude anyone with a note from the last 60 days, and list the ten with the most recent work history." → `search_candidates`, `list_candidate_notes`, `get_candidate`

## Can Bullhorn automations run on a schedule in n8n, Make or Zapier?

Yes. Cotlet does not replace your automation platform: it gives it a Bullhorn connection it does not have, with the same API key as your agent. Write actions ask for your OK by default; switch that off in your dashboard for the tools you choose, for example to log screening notes on candidate records, and the schedule runs on its own. Cotlet runs in the cloud, so it keeps going while your computer is off.

| Where | How to connect | How to schedule |
|---|---|---|
| Your AI agent | Add https://cotlet.dev/mcp/v1 with your API key. | A scheduled agent run, for example a Claude Code routine. |
| n8n | MCP Client node with https://cotlet.dev/mcp/v1, or an HTTP Request node with the endpoint's method and URL, such as GET https://cotlet.dev/api/v1/bullhorn/candidates/search. | Schedule Trigger node. |
| Make | HTTP module: the endpoint's method and URL with an Authorization: Bearer header, and a JSON body for POST, PUT and PATCH. | Scenario schedule. |
| Zapier | Webhooks by Zapier, Custom Request: the same method, URL, header and body. | Schedule by Zapier trigger. |
| Your own script | GET https://cotlet.dev/api/v1/bullhorn/candidates/search with your API key. | cron or GitHub Actions. |

## Tools

**For AI agents:** Every endpoint and its schema is public. The 9 endpoints on this page, with parameters and example responses, can be listed without an account. Calling one returns 401 without an API key and 403 while the key has no access to Bullhorn.

### search_candidates

Candidates matching keywords in name, occupation, company, resume, work history and attachments. Access: read. REST: `GET /api/v1/bullhorn/candidates/search`. MCP: `bullhorn_read → search_candidates`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `keywords` | string[] | yes | Words or phrases to look for. |
| `match` | enum | no | all (And, default) or any (Or). |
| `exclude_keywords` | string[] | no | Candidates containing any of these are left out. |
| `limit` | integer | no | Candidates per page. |
| `cursor` | string | no | Next page cursor from the previous call. |

Searches the way the candidate list keyword search does: Candidate Name, Occupation, Current Company, Resume, Work History and File Attachments. Custom fields are not searched. Several keywords combine with and by default; match any uses or, and exclude_keywords removes candidates that contain them. Returns one page of candidates; pass next_cursor back as cursor for more. Use candidate_id in get_candidate and add_note.

Example response:

```json
{
  "total": 31,
  "candidates": [
    {
      "candidate_id": 4821907,
      "name": "Priya Raman",
      "occupation": "Data Analyst",
      "company": "Brightpath Retail",
      "status": "Active",
      "submission_count": 4
    },
    {
      "candidate_id": 4830112,
      "name": "Marcus Lee",
      "occupation": "BI Lead",
      "company": "Harbor Logistics",
      "status": "Active",
      "submission_count": 1
    }
  ],
  "next_cursor": null
}
```

### get_candidate

One candidate record with status, current company and the jobs they were submitted to. Access: read. REST: `GET /api/v1/bullhorn/candidates/{candidate_id}`. MCP: `bullhorn_read → get_candidate`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `candidate_id` | integer | yes | Candidate ID from search_candidates or find_matching_candidates. |

Returns the candidate's name, occupation, current company, status and contact fields, plus one row per submission with the job and its status. Notes are not included; list_candidate_notes reads the Notes tab. A candidate you cannot open in Bullhorn answers APP_PERMISSION_DENIED.

Example response:

```json
{
  "candidate_id": 4821907,
  "name": "Priya Raman",
  "occupation": "Data Analyst",
  "company": "Brightpath Retail",
  "status": "Active",
  "email": "priya.raman@example.com",
  "submissions": [
    {
      "submission_id": 905512,
      "job_id": 77314,
      "job_title": "Senior Data Analyst",
      "status": "Submitted"
    }
  ]
}
```

### list_candidate_notes

Notes on a candidate's Notes tab with Note Action, author and date, newest first. Access: read. REST: `GET /api/v1/bullhorn/candidate-notes`. MCP: `bullhorn_read → list_candidate_notes`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `candidate_id` | integer | yes | Candidate ID from search_candidates or find_matching_candidates. |
| `cursor` | string | no | Next page cursor from the previous call. |

Reads the Notes tab of one candidate, newest first. Each note has its Note Action, the Comments text, who added it and when, and the records it references. Use it before add_note to avoid doubling a note.

Example response:

```json
{
  "notes": [
    {
      "note_id": 6120044,
      "note_action": "Phone Call",
      "comments": "Open to contract. Free from 3 Nov.",
      "added_by": "Dana Whitfield",
      "added_at": "2026-10-22T15:40:00Z",
      "references": [
        {
          "type": "job",
          "id": 77314
        }
      ]
    }
  ],
  "next_cursor": null
}
```

### get_job

One job record with title, client, owner, location and submission count. Access: read. REST: `GET /api/v1/bullhorn/jobs/{job_id}`. MCP: `bullhorn_read → get_job`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | integer | yes | Job ID from get_job or the job record URL. |

Returns the job's title, client, job owner, employment type and location, and the number of submissions it has across all statuses. Use job_id in find_matching_candidates, list_job_submissions and add_submission.

Example response:

```json
{
  "job_id": 77314,
  "title": "Senior Data Analyst",
  "client": "Northwind Logistics",
  "owner": "Jonas Weber",
  "employment_type": "Contract",
  "location": "Chicago, IL",
  "submissions": 7
}
```

### find_matching_candidates

Candidates that match a job by its description and location, like Find Matching Candidates. Access: read. REST: `GET /api/v1/bullhorn/jobs/{job_id}/matching-candidates/find`. MCP: `bullhorn_read → find_matching_candidates`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | integer | yes | Job ID from get_job or the job record URL. |
| `keywords` | string[] | no | Replaces the keywords taken from the job description. |
| `radius_miles` | integer | no | Search radius around the job zip code. Default: 20. |
| `cursor` | string | no | Next page cursor from the previous call. |

Runs the app's Find Matching Candidates search for one job. When the description has more than 250 words, Bullhorn takes up to 10 keywords from it and uses the job zip code with a radius of 20 miles. Pass keywords or radius_miles to change that. Returns one page of candidates, best matches first as Bullhorn orders them.

Example response:

```json
{
  "total": 31,
  "candidates": [
    {
      "candidate_id": 4821907,
      "name": "Priya Raman",
      "occupation": "Data Analyst",
      "company": "Brightpath Retail",
      "status": "Active",
      "submission_count": 4
    }
  ],
  "next_cursor": "2"
}
```

### list_job_submissions

Submissions on a job by stage, with candidate, status and date. Access: read. REST: `GET /api/v1/bullhorn/job-submissions`. MCP: `bullhorn_read → list_job_submissions`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | integer | yes | Job ID from get_job or the job record URL. |
| `stage` | enum | no | all (default), submissions, interviewing, rejected or confirmed. |
| `cursor` | string | no | Next page cursor from the previous call. |

Reads the Submissions tab of one job. stage picks Submissions, Interviewing, Rejected or Confirmed; all returns the job's full history. Each row has the submission_id, the candidate, the current status and when it was created. Use submission_id in update_submission_status.

Example response:

```json
{
  "submissions": [
    {
      "submission_id": 905512,
      "candidate_id": 4821907,
      "name": "Priya Raman",
      "status": "Submitted",
      "stage": "submissions",
      "created_at": "2026-10-04T09:12:00Z"
    },
    {
      "submission_id": 905530,
      "candidate_id": 4830112,
      "name": "Marcus Lee",
      "status": "Submitted",
      "stage": "submissions",
      "created_at": "2026-10-05T10:03:00Z"
    }
  ],
  "next_cursor": null
}
```

### add_note

Adds a note with a Note Action to a candidate's Notes tab. Access: write, asks the user first. REST: `POST /api/v1/bullhorn/candidates/{candidate_id}/notes`. MCP: `bullhorn_write → add_note`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `candidate_id` | integer | yes | Candidate ID from search_candidates or find_matching_candidates. |
| `comments` | string | yes | Note text, plain text only. @name tags a user, #name references a record. |
| `note_action` | string | yes | Note Action value such as Phone Call, Email or Internal Memo, as set in your account. |
| `job_id` | integer | no | Job to reference in the note. |

Saves one plain-text note on the candidate, as Actions > Add Note does. note_action must be one of the values your admin set, at most 30 characters. A name typed after @ in comments emails that user when the note is saved, so the note can reach other people. Returns the note_id. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "note_id": 6120051,
  "candidate_id": 4821907,
  "note_action": "Phone Call",
  "added_at": "2026-10-23T16:05:00Z"
}
```

### add_submission

Submits one or more candidates to a job for the job owner to review. Access: write, asks the user first. REST: `POST /api/v1/bullhorn/jobs/{job_id}/submissions`. MCP: `bullhorn_write → add_submission`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | integer | yes | Job ID from get_job or the job record URL. |
| `candidate_ids` | integer[] | yes | Candidates to submit. |
| `comments` | string | no | Comment shown with the submission. |

Creates an internal submission per candidate, as Actions > Add Submission does on the job record. Bullhorn sets the status to Submitted and the submission goes to the job owner. Submitting several candidates at once works only if your company's policies allow it. Returns one submission_id per candidate. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "submissions": [
    {
      "submission_id": 905601,
      "candidate_id": 4821907,
      "status": "Submitted"
    },
    {
      "submission_id": 905602,
      "candidate_id": 4830112,
      "status": "Submitted"
    }
  ]
}
```

### update_submission_status

Moves one submission to another status in your hiring workflow. Access: write, asks the user first. REST: `PATCH /api/v1/bullhorn/submissions/{submission_id}/status`. MCP: `bullhorn_write → update_submission_status`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `submission_id` | integer | yes | Submission ID from list_job_submissions. |
| `status` | string | yes | Status name as it appears in your account. |

Sets the status of one submission, like clicking the status on the job's Submissions tab. status must exist in your account's list, for example Sales Rep Rejected, Candidate Interested or Offer Extended. Changing a candidate that is not yours needs the Change Any Candidate Submission Status entitlement. It never deletes a submission and does not place a candidate. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "submission_id": 905512,
  "previous_status": "Submitted",
  "status": "Sales Rep Rejected"
}
```

## How do I connect Bullhorn to Claude Code, Codex or Cursor?

Connecting Bullhorn takes three steps: sign up, sign in to Bullhorn once in your Cloud Browser and enable it for agents, then add one MCP server or call the REST API with the same key.

### Connect Bullhorn to your agent.

1. **Create an account** Sign up and add Bullhorn in the console. Your API key is there too.

2. **Sign in to Bullhorn in your Cloud Browser** Open your Cloud Browser in the console: your own Chrome in the cloud. Sign in to Bullhorn there yourself, the way you always do, then press Enable for agents, read only or read and write. We never save your password, and your agent keeps working even when your computer is off.

3. **Add Cotlet to your agent** Paste the snippet for your client. The same server and key serve every app you connect, so you do this once.

   Claude Code:

```
claude mcp add --transport http cotlet \
  https://cotlet.dev/mcp/v1 \
  --header "Authorization: Bearer $COTLET_API_KEY"
```

   Cursor:

```
{
  "mcpServers": {
    "cotlet": {
      "url": "https://cotlet.dev/mcp/v1",
      "headers": {
        "Authorization": "Bearer ${COTLET_API_KEY}"
      }
    }
  }
}
```

   Codex:

```
# ~/.codex/config.toml
[mcp_servers.cotlet]
url = "https://cotlet.dev/mcp/v1"
bearer_token_env_var = "COTLET_API_KEY"
```

4. **Ask your agent** Ask in plain words. Your agent finds the Bullhorn tools on the server and calls them for you; anything that reaches other people waits for your OK unless you switch that off for a tool.

```
Here are my call notes from today. For each candidate, find the record in Bullhorn and add a Phone Call note with the summary. Skip anyone who already has a note from today.
```

### Call Bullhorn from your scripts.

1. **Export your API key** Your scripts use the same API key as your agent. Keep it in an environment variable, never in your code.

```
export COTLET_API_KEY="cotlet_..."
```

2. **Call a tool** Every tool is an endpoint under /api/v1/bullhorn with its own method and path, listed with the endpoints above. Path parameters go in the URL; the other parameters go in the query for GET and DELETE and in a JSON body otherwise.

```
curl -X POST https://cotlet.dev/api/v1/bullhorn/jobs/77314/submissions \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"candidate_ids":[4821907,4830112],"comments":"Both have dbt and Snowflake and can start in November."}'
```

3. **Read the result** You get plain JSON back, ready for your script. A failed call costs nothing.

```
{
  "submissions": [
    {
      "submission_id": 905601,
      "candidate_id": 4821907,
      "status": "Submitted"
    },
    {
      "submission_id": 905602,
      "candidate_id": 4830112,
      "status": "Submitted"
    }
  ]
}
```

## Why use Cotlet for Bullhorn?

**Built for agents**

- One MCP server for every app you connect.
- The same tools as a REST API for scripts and cron jobs.
- Works with Claude Code, Codex and Cursor.

**Your login stays yours**

- You sign in to Bullhorn yourself, in your own Cloud Browser. We never save your password; the profile is encrypted with AES-256-GCM, the cipher 1Password uses.
- A+ on Qualys SSL Labs, securityheaders.com and Mozilla Observatory.
- The model never sees a login.
- No stored passwords, no CAPTCHA solving, no MFA bypass.

**You stay in control**

- Scope each API key: its apps, its tools, read only or read and write.
- Anything that reaches other people waits for your OK, so a leaked key cannot post or message as you.
- Every background request listed in your Background activity. Disable for agents in one click.

**Kept working for you**

- We test every integration every 6 hours.
- When Bullhorn changes, the tool pauses until we fix it.
- Failed calls cost nothing.

## Is it safe to connect Bullhorn to Cotlet?

Yes. You sign in to Bullhorn yourself, in your own Cloud Browser, and we never save your password. Your agents only get Bullhorn once you enable it, and every background request is listed. The browser profile is stored encrypted with AES-256-GCM, the same cipher 1Password uses for its vaults and Apple for iCloud Keychain. Independent public scanners grade cotlet.dev A+ and find it clean; click a result to rerun it yourself.

- **A+ on Qualys SSL Labs**: Encryption in transit: TLS setup and certificates, on all four server addresses. [Live result](https://www.ssllabs.com/ssltest/analyze.html?d=cotlet.dev)
- **A+ on securityheaders.com**: Browser protections sent with every page, all six headers present. [Live result](https://securityheaders.com/?q=cotlet.dev&followRedirects=on)
- **A+ on Mozilla Observatory**: Mozilla's web security baseline: score 120 of 100, 12 of 12 tests passed. [Live result](https://developer.mozilla.org/en-US/observatory/analyze?host=cotlet.dev)
- **Clean on Sucuri SiteCheck**: No malware, spam or defacement, and not on any of 9 blocklists, Google Safe Browsing included. [Live result](https://sitecheck.sucuri.net/results/cotlet.dev)

[How Cotlet protects your access](https://cotlet.dev/security.md)

### Common concerns

**Who runs Cotlet?**

Cotlet is run by Take Group, a Polish software company working since 2019. Take Group runs about 3,200 websites on its own systems and has its own DevOps team for infrastructure security. We built and used integrations like this inside the company for years before opening them as Cotlet.

**Is this an official Bullhorn integration?**

No, Cotlet is independent of Bullhorn. Bullhorn's own API is open only to approved partners. Cotlet works through your own Bullhorn account, the way you use Bullhorn in the browser, so you need no partner approval and no developer setup.

**What about client data and GDPR?**

Cotlet is run from the EU and follows the GDPR. Cloud Browsers run in Finland, a Tier 1 country in the ITU Global Cybersecurity Index 2024. Data passes through a call and is not kept after it.

**Can I start with read only?**

Yes. Enable the app for agents as read only, or make the API key read only, and anything that reaches other people waits for your OK unless you switch that off per tool.

**Is it reliable?**

Every Cotlet service is checked every 3 minutes from Europe, North America, Asia and Australia. The live results and any outage are public at status.cotlet.dev.

**How do I stop?**

Press Disable for agents next to Bullhorn in your console: your agents lose access at once and you stay signed in. Signing out of Bullhorn in the browser works too, and Reset browser deletes the whole profile.

## Is there a Bullhorn MCP server on GitHub?

You can build on the Bullhorn REST API, but only as a contracted technology vendor with an annual fee. A recruiter or a small agency cannot get a key for their own AI agent that way. Cotlet works in your own Bullhorn login instead and keeps the integration running for you.

|  | Bullhorn REST API | Cotlet |
|---|---|---|
| Setup | Sign a partner contract, pay the annual fee, pass a security assessment, then build an integration in-house | Sign up, sign in to Bullhorn once, add one MCP server or API key |
| When Bullhorn changes | You update your own code | Our team runs automatic checks and fixes the integration for you |
| Your Bullhorn session | Not used; the API has its own keys, issued to the vendor | In your own Cloud Browser in the EU, profile encrypted, only for the apps you enable, disabled for agents in one click |
| When the session expires | Not applicable | Your Cloud Browser keeps you signed in; if Bullhorn logs you out, your agent gets a link to sign in again |
| Upkeep | You host, monitor and debug it | Nothing to host or update |
| Where it runs | Your servers | Hosted: Claude Code, Codex, Cursor, n8n and scripts, also on a schedule |
| Price | Annual platform fee, paid upfront, set by Bullhorn | Free 7-day trial, then pay-as-you-go credit packs, no subscription |

### Which one fits you

**Pick Cotlet if**

- you are not a developer, or you do not want to maintain a server
- you need it to keep working when Bullhorn changes, without checking it yourself
- your agent or a script should run it on a schedule, also while your computer is off

**Pick an open-source server if**

- you are comfortable installing, updating and fixing it yourself
- you want your sign-in to stay on your own computer
- you only need it now and then, from one MCP client

## How much does the Bullhorn API cost?

Free 7-day trial with 2,000 credits, no card needed. After that, the Bullhorn API is pay as you go with no limit on apps: Credit packs from $29 for 5,000 credits, one-time, no subscription. A successful call uses 10 credits (about $0.04 to $0.06), your Cloud Browser uses 50 credits a day while it has an app enabled for agents, however many apps that is, and an agent driving the browser itself uses 5 credits a minute. Credit packs stay valid for 12 months and stack, so unused credits carry over.

| Credits | Price, one time | Calls at 10 credits | Per 1,000 credits |
|---|---|---|---|
| 5,000 | $29 | 500 | $5.80 |
| 15,000 | $79 | 1,500 | $5.27 |
| 32,000 | $149 | 3,200 | $4.66 |
| 60,000 | $249 | 6,000 | $4.15 |

Only successful calls use credits; failed calls and timeouts cost nothing. At a balance of 0 calls pause, never a surprise charge. Authenticate with the `Authorization: Bearer` header. [See full pricing](https://cotlet.dev/pricing.md)

## How Cotlet holds your access

Cotlet hosts MCP servers and REST APIs for apps with no usable API. Your agent works in your own Bullhorn account.

- **Company details:** Cotlet is run by Take Group sp. z o.o., a company registered in Poland. Its full address and registration numbers are in the Terms of service. [Terms of service](https://cotlet.dev/terms)
- **Your sign-in:** You sign in to Bullhorn yourself, in your own Cloud Browser: a Chrome we run for you in the EU, one per app. We never save your password (password saving is off), the profile is stored encrypted with AES-256-GCM, and your agents get Bullhorn only after you enable it. When Bullhorn signs you out, your agent gives you a link to sign in again. [Security](https://cotlet.dev/security.md)
- **Revoking access:** Press Disable for agents next to Bullhorn, sign out of Bullhorn in your Cloud Browser, or reset the browser. Every background request is listed in your Background activity. Actions that reach other people wait for your OK unless you switch that off per tool.
- **What we never do:** Store passwords, solve CAPTCHAs or bypass MFA.
- **Bullhorn's terms:** You use your own Bullhorn account and stay responsible for following Bullhorn's terms. Cotlet is independent and not affiliated with Bullhorn. [Terms](https://cotlet.dev/terms)
- **Contact:** Questions about the company, security or an app: [contact@cotlet.dev](mailto:contact@cotlet.dev)

## Frequently asked questions

**How do I get access?**

Sign up free, open Bullhorn in the console and press Request access. Then you create your API key and connect Bullhorn there.

**Do I need to be technical?**

No. You sign in to Bullhorn once in your Cloud Browser, a normal Chrome you open from the console, and paste one command into your agent, or one URL into n8n. Your agent can walk you through it. There is no server to install, update or fix.

**Is it safe to connect Bullhorn to Cotlet?**

Yes. You sign in to Bullhorn yourself, in your own Cloud Browser in the EU, and we never save your password. Your agents only get Bullhorn once you enable it, every background request is listed, and the browser profile is stored encrypted with AES-256-GCM, the cipher 1Password uses for its vaults. The AI model never sees a login, posts and messages wait for your OK, and Disable for agents cuts access in one click. Independent scanners grade cotlet.dev A+ on Qualys SSL Labs, securityheaders.com and Mozilla Observatory; live results are on https://cotlet.dev/security.

**Is a hosted server safer than a local one? My Bullhorn sign-in would leave my computer.**

On Cotlet you sign in inside your own Cloud Browser, which only you open, and its profile is stored encrypted with AES-256-GCM in the EU. Agents get only the apps you enable, and every background request is listed. A local server keeps your Bullhorn cookie in a plain file on your computer, readable by any program you run, and stops when your computer is off.

**Why does Cotlet send requests instead of clicking in my browser?**

To be fast, Cotlet doesn't click through Bullhorn's pages. It sends the same requests your browser would, from your browser's IP with its cookies, without opening a window. Bullhorn sees the same browser and IP you signed in with, and every request is listed in your Background activity.

**What if someone gets my Cotlet API key?**

The key holds no Bullhorn login or cookies, it only asks Cotlet to run a tool. It can call only the apps and tools you gave it, and a read-only key changes nothing. Anything that reaches other people, like posts, comments or messages, waits for your OK in the dashboard by default, so a leaked key cannot post or message as you. When you switch approval off for a scheduled job, give that job its own key limited to that one tool. Every call is in your activity log, and deleting the key ends access at once.

**Why a signed-in browser and not OAuth, like other integration platforms?**

Bullhorn offers no OAuth token you can simply grant for these tools: its official API leaves them out or needs a developer app, a plan or an approval first (see the official API section above). That is why Cotlet sets the limits itself: per key, per tool, with your approval before anything reaches other people. Cotlet is run by Take Group sp. z o.o., an EU company (VAT PL6342984273).

**Can my agency get a Bullhorn API key for its own agent?**

Bullhorn sells API access as a partner contract to technology vendors, with an upfront annual fee and a security assessment. Bullhorn also says customers do not get their key if they plan to hand it to a vendor without a contract. Cotlet does not use that API: your agent works in your own Bullhorn login in the Cloud Browser.

**Which Bullhorn role do I need?**

Your own user, with the rights it already has. Your agent can only open records and do actions that your user can do in Bullhorn. Changing the status of a candidate that is not yours needs the Change Any Candidate Submission Status entitlement, and a call without it fails.

**Can my agent post or send messages in Bullhorn without asking me?**

No. Every call to add_note, add_submission or update_submission_status waits for your OK by default. For scheduled automations you can switch confirmation off per tool in your dashboard, for example only for approvals.

**Can I use the Bullhorn API in n8n?**

Yes. Add https://cotlet.dev/mcp/v1 with your API key in n8n's MCP Client node, or call its endpoints under https://cotlet.dev/api/v1/bullhorn from the HTTP Request node.

---

Give your AI agents your signed-in browser.

**Product:** [Integrations](https://cotlet.dev/integrations.md) · [Use cases](https://cotlet.dev/use-cases.md) · [How it works](https://cotlet.dev/how-it-works.md) · [Pricing](https://cotlet.dev/pricing.md) · [Security](https://cotlet.dev/security.md)

**Resources:** [Blog](https://cotlet.dev/blog.md) · [API docs](https://cotlet.dev/docs.md) · [Help center](https://cotlet.dev/help.md) · [Changelog](https://cotlet.dev/changelog.md) · [GitHub](https://github.com/cotletdev/cotlet)

**Solutions:** [For developers](https://cotlet.dev/for-developers.md) · [For automation agencies](https://cotlet.dev/for-agencies.md)

**Company:** [About](https://cotlet.dev/about.md) · [AI info: company facts](https://cotlet.dev/ai-info.md) · [Contact](https://cotlet.dev/contact.md)

**Legal:** [Terms of service](https://cotlet.dev/terms) · [Privacy policy](https://cotlet.dev/privacy) · [Refund policy](https://cotlet.dev/refunds) · [Acceptable use](https://cotlet.dev/acceptable-use) · [Cookie policy](https://cotlet.dev/cookies) · [DPA](https://cotlet.dev/dpa) · [Subprocessors](https://cotlet.dev/subprocessors)

**Elsewhere:** [Status page](https://status.cotlet.dev) · [Cotlet on GitHub](https://github.com/cotletdev) · [Cotlet on X](https://x.com/cotletdev) · [Cotlet on LinkedIn](https://www.linkedin.com/company/cotletdev) · [Cotlet on Product Hunt](https://www.producthunt.com/products/cotlet) · [Cotlet on Crunchbase](https://www.crunchbase.com/organization/cotlet) · [Cotlet on SaaSHub](https://www.saashub.com/cotlet)

Cotlet.dev is built by Bart Krawczyk and Jake Slugocki, the founders of Take Group sp. z o.o., ul. Wincentego Janasa 4, 40-855 Katowice, Poland. KRS 0000871398, NIP 6342984273, VAT EU: PL6342984273. [About us](https://cotlet.dev/about.md)

Cotlet is an independent service. It is not affiliated with, endorsed by or sponsored by any of the products listed on this site. Product names are trademarks of their respective owners.
