Whistle See plans

Whistle plugs into Clay and Loopster as the college-athletics source

Clay and Loopster orchestrate enrichment from many vendors; neither specialises in college athletics. Whistle is the source for that slice: 1,085 NCAA athletic departments read from their official staff directories, with hire and departure signals. One HTTP step calling POST /api/v1/people/match returns, for each person in your table, their current title, school, division and conference, whether they have left, and on Pro+, Enterprise their email and phone. REST API access is on every Whistle plan; people matching needs Pro or above.

Data as of 4 Nov 2026.

Source: Whistle API reference at /api/docs; Clay facts from its public pricing page, checked October 31, 2026; Loopster facts from its public pricing page, checked October 31, 2026.

What does the HTTP step look like?

Method and URL
POST https://gowhistle.io/api/v1/people/match
Headers
Authorization: Bearer <your Whistle API key> and Content-Type: application/json
Body
A JSON object with a people array (up to 500 per call). Each person: id (your row id, echoed back), and either email, or name (or first_name + last_name) plus school, domain or title. school is also accepted as company, organization or account.
Options
dry_run: true previews match counts and cost without billing or returning staff fields; min_confidence (0.5 to 1, default 0.7) drops weaker matches.
API key
Settings → API keys in Whistle, on any plan. Send it only in the Authorization header; keys in the query string are rejected.
Billing
Each distinct matched record is one row against the plan's monthly rows; a record returned in the last 90 days is free. Response headers X-Whistle-Rows-Charged and X-Whistle-Rows-Remaining report usage. Plans and rows: pricing.

Sample request

Placeholder people; nothing here is a real person or address.

{
  "people": [
    {
      "id": "row-1",
      "name": "Jane Example",
      "school": "Example State University",
      "title": "Director of Athletics Marketing"
    },
    {
      "id": "row-2",
      "email": "sample.person@example.edu"
    },
    {
      "id": "row-3",
      "first_name": "Sam",
      "last_name": "Placeholder",
      "domain": "examplestateathletics.com"
    }
  ],
  "dry_run": false,
  "min_confidence": 0.7
}

Sample response

Shape only. Email and phone are masked unless the key's plan includes contact data (Pro+, Enterprise); email_status appears only with contact data.

{
  "dry_run": false,
  "skipped_rows": 0,
  "summary": {
    "total": 3,
    "matched": 2,
    "unmatched": 1,
    "ambiguous": 0,
    "school_unresolved": 0,
    "match_rate": 67,
    "distinct_contacts": 2,
    "contact_data_included": true,
    "graced_rows": 0,
    "billable_rows": 2,
    "from_allowance": 2,
    "overage_rows": 0,
    "amount_cents": 0,
    "overage_paused": false,
    "rows_charged": 2,
    "rows_remaining": 4998
  },
  "results": [
    {
      "id": "row-1",
      "input": {
        "name": "Jane Example",
        "email": null,
        "school": "Example State University",
        "domain": null,
        "title": "Director of Athletics Marketing"
      },
      "matched": true,
      "confidence": 0.96,
      "level": "high",
      "reason": "name_exact",
      "school_mismatch": false,
      "resolved_school": {
        "id": "example-state",
        "name": "Example State University",
        "method": "alias"
      },
      "alternatives": [],
      "staff": {
        "id": 123456,
        "name": "Jane Example",
        "title": "Associate AD for Marketing & Fan Experience",
        "department": "External Relations",
        "office": null,
        "school_id": "example-state",
        "school_name": "Example State University",
        "division": "Division I",
        "conference": "Example Conference",
        "email": "jane.example@example.edu",
        "phone": "555-0100",
        "email_status": "verified",
        "linkedin_url": null,
        "bio_url": "https://examplestateathletics.com/staff-directory/jane-example/1",
        "functional_area": "external",
        "buyer_persona": null,
        "last_scraped_at": "2026-10-29T06:12:00.000Z",
        "departed": false,
        "departed_at": null,
        "departure_source": null
      }
    },
    {
      "id": "row-2",
      "input": {
        "name": null,
        "email": "sample.person@example.edu",
        "school": null,
        "domain": null,
        "title": null
      },
      "matched": true,
      "confidence": 1,
      "level": "high",
      "reason": "email_exact",
      "school_mismatch": false,
      "resolved_school": {
        "id": "example-state",
        "name": "Example State University",
        "method": "email_domain"
      },
      "alternatives": [],
      "staff": {
        "id": 123457,
        "name": "Sample Person",
        "title": "Director of Development",
        "department": "Athletics Development",
        "office": null,
        "school_id": "example-state",
        "school_name": "Example State University",
        "division": "Division I",
        "conference": "Example Conference",
        "email": "sample.person@example.edu",
        "phone": null,
        "email_status": "accept_all",
        "linkedin_url": null,
        "bio_url": null,
        "functional_area": "external",
        "buyer_persona": null,
        "last_scraped_at": "2026-10-29T06:12:00.000Z",
        "departed": true,
        "departed_at": "2026-09-14T03:05:00.000Z",
        "departure_source": "signal"
      }
    },
    {
      "id": "row-3",
      "input": {
        "name": "Sam Placeholder",
        "email": null,
        "school": null,
        "domain": "examplestateathletics.com",
        "title": null
      },
      "matched": false,
      "confidence": 0,
      "level": "none",
      "reason": "no_person_match",
      "school_mismatch": false,
      "resolved_school": {
        "id": "example-state",
        "name": "Example State University",
        "method": "domain"
      },
      "alternatives": [],
      "staff": null
    }
  ]
}

Which response fields should I map to columns?

PathColumnNotes
results[i].matchedMatched (true/false)Filter unmatched rows out of outreach
results[i].confidence and results[i].levelMatch confidencehigh ≥ 0.85, medium ≥ 0.7; reason explains the match (email_exact, name_exact, name_nickname, title_disambiguated, …)
results[i].staff.titleCurrent titleAs the department's directory lists it today
results[i].staff.school_name, division, conferenceSchool, division, conferenceAlso results[i].staff.school_id for joins to GET /api/v1/schools/{id}
results[i].staff.email, results[i].staff.phoneEmail, phonePresent only on Pro+, Enterprise; masked otherwise
results[i].staff.email_statusEmail statusverified, accept_all, invalid, unconfirmed or not_checked; contact-data plans only
results[i].staff.departed, departed_at, departure_sourceDeparted, departed onWhistle saw the person leave: a departure signal or an ended career record. Suppress or re-route these rows
results[i].staff.last_scraped_atLast verifiedWhen the directory was last read for this record
results[i].staff.bio_url, linkedin_urlBio page, LinkedInProvenance link to the school's own page where published
results[i].alternativesAlternativesSame-name candidates when a row is ambiguous (ids, names, titles only); add a title and retry
summary.distinct_contacts, summary.amount_centsRows billed, overageUse with dry_run: true to show the cost before the real run

How do I set it up in Clay or Loopster?

What are Clay and Loopster, and how does Whistle differ?

ClayLoopsterWhistle
What it isClay is a data-enrichment and outbound workspace: tables of accounts or people, enriched column by column from Clay's vendor marketplace and from any HTTP API. Clay siteLoopster is a GTM orchestration tool from the HeyReach team: tables, enrichment waterfalls across its own data and third-party vendors, functions and AI agents. Loopster siteWhistle (Whistle Athletics) is a collegiate athletics sales-intelligence platform: staff directories, hiring signals and contact data for vendors selling into NCAA athletic departments.
HTTP enrichment step“Integrate with any HTTP API” is listed on the Growth plan and above (the comparison table marks HTTP API integrations as not included on Free and Launch). Clay sourceNot stated on their public pricing pageWhistle is the API the step calls; it is not a table or workflow tool.
PricingFree plan (500 actions and 100 data credits a month, tables capped at 200 rows); Launch $167/month and Growth $446/month on the plan cards (the FAQ quotes $185 and $495 starting prices); Enterprise custom. Priced by actions and data credits. Clay pricingLaunch $179/month (50K rows per table), Scale $449/month (200K rows per table), Unlimited $1,299/month. Unlimited tables and seats on every plan; a starting wallet for vendor and AI spend; a 14-day free trial of Scale with no card. Loopster pricingBase $10/month (200 rows), Pro $50/month (2,000 rows), Pro+ $100/month (5,000 rows, includes emails and phones); Enterprise on request. Monthly billing, cancel anytime.
API / MCPNot stated on their public pricing pageAPI and MCP server included on every plan (50K to 200K API requests a day by plan). Loopster sourceREST API on every plan; hosted MCP server at /mcp and the gowhistle-mcp package on every plan. MCP setup
SignalsNot exposed as a data product on their public pagesNot exposed as a data product on their public pagesNew hires, departures and title changes per school, in the app, by webhook and over GET /api/v1/signals and the MCP server.

Frequently asked questions

Is Whistle a Clay or Loopster alternative?

No. Clay and Loopster are workspaces that run enrichment from many vendors; Whistle is one of those vendors, for US college athletics only. Use them together: the table lives in Clay or Loopster, the athletics step calls Whistle. If you only sell into athletic departments, Whistle's own staff search, lists and exports may be all you need.

Which Whistle plan do I need for the HTTP step?

People matching is on Pro ($50/month) and above; emails and phones come back on Pro+, Enterprise (Pro+ is $100/month). Every plan includes the REST API, and the row cost is shown in the response summary and headers. Plans.

What happens when a contact has left the school?

The matched record carries departed: true, departed_at and departure_source. Whistle keeps the person's row so the match still resolves; map departed to a column and exclude or re-route those rows before sending.

Can I enrich a whole school instead of a person?

Yes: POST /api/v1/enrich takes a domain, school name or school id and returns the department's staff list; GET /api/v1/staff filters by role, sport, title, state, conference and division. Both are documented at /api/docs.

Where does this contact data come from?

From the staff directories athletic departments publish on their official websites, read automatically on a rolling schedule (NCAA Division I roughly weekly, Division II and III every three to four weeks). Whistle never publishes names, emails or phone numbers on public pages; staff can remove their details at any time at gowhistle.io/remove-my-info.

Get an API key on any plan at pricing, read the full API reference, or connect an AI assistant through the MCP server.