---
title: "Membership Eligibility API - Who Can Join Each Credit Union"
description: "Find which credit unions a person can join, or use POST /v1/reachable-offers to intersect graph-positive membership paths with fresh, evidenced product rates."
canonical: "https://rateapi.dev/api/eligibility"
last-updated: "2026-09-27"
source: "https://rateapi.dev/llms.txt"
---

# Know Who Can Join Before You Rank

Ranking a credit union your user can't join erodes trust in every other recommendation. `POST /v1/eligibility/search` answers “which credit unions can I join?” from a person's own facts, `POST /v1/eligibility/check` verdicts up to 50 named credit unions against one user profile, and every ranked offer carries an evidence-backed `eligibility` verdict of its own.

[Open the calculator in the dashboard →](https://app.rateapi.dev/playground) Talk to us about Routes

Every Published Rule Evidence-Backed Never Publishes Ineligibility Says Unknown Rather Than Guess

Last updated: September 26, 2026

[Home](https://rateapi.dev/) / Membership Eligibility API

RateAPI annotates every ranked credit union offer with an evidence-backed membership-eligibility status - `open_to_anyone` , `likely_eligible` , `eligible_via_employer` , `eligible_via_military` , `geo_mismatch` , or `unknown` . Every published rule is backed by a verbatim evidence quote and source URL, offers are never hidden unless the caller opts in, and the final membership determination is always the institution's.

> Source: [RateAPI.dev/api/eligibility](https://rateapi.dev/api/eligibility) (verified September 26, 2026)

Quick Answer

**The eligibility layer answers both directions of the membership question.** `POST /v1/eligibility/search` takes a person's facts - home ZIP, employer, school, associations, military status, place of worship - and returns the credit unions they can join, bucketed as `eligible` , `conditionally_eligible` , `possibly_eligible` , or `unknown` . `POST /v1/eligibility/check` goes the other way, verdicting up to 50 named credit unions against one profile. Offers on `/v1/decisions` , `/v1/league-table` , and `/v1/rates` carry the verdict inline. Nothing is ever published as ineligible, and `unknown` never means no. The `preferences.eligible_only` filter is in beta: gated behind our identity-verification threshold, it currently annotates without filtering.

## The Per-Offer Eligibility Object

Each ranked offer on `/v1/decisions` , `/v1/decisions/batch` , `/v1/league-table` , and `/v1/rates` can carry an `eligibility` object. Credit unions we have no verified data on simply omit the field - the annotation is strictly additive and existing integrations are unaffected:

- **status** - one of `open_to_anyone` , `likely_eligible` , `eligible_via_employer` , `eligible_via_military` , `geo_mismatch` , or `unknown` . A supplied `military_status` that matches a military field-of-membership tag yields `eligible_via_military` ; a `school` , `worship` , or occupation match yields `likely_eligible` with the matched rule naming which affinity applied.
- **matched_rule** - which concrete rule produced the status (`county` , `state` , `employer` , `military` , `school` , `worship` , `occupation` , or `association_open` ) with an optional detail. Purely explanatory; absent on `geo_mismatch` and `unknown` .
- **join_cost_usd** - the up-front cost to become a member: the membership fee plus the minimum share deposit, summed from whichever components are known. Present only when at least one component is verified; the raw `membership_fee_usd` and `min_deposit_usd` accompany it.
- **join_path** - concrete steps to become a member, e.g. "Join the American Consumer Council (one-time $8 donation) during application".
- **requirements_summary** - a one-line human-readable summary of the membership requirements, generated at extraction time.
- **eligibility_type** - the charter shape: `community` , `employer` , `association` , `multi` , `tip` , `open` , or `unknown` .
- **confidence** - 0 to 1, computed from how many extracted claims survived evidence verification.

{} offer with eligibility annotation

Copy

{

"provider" : "Golden Valley Credit Union" ,

"apr" : 6.125 ,

"monthly_payment" : 2551 ,

"eligibility" : {

"status" : "open_to_anyone" ,

"matched_rule" : { "type" : "association_open" } ,

"join_path" : "Join the American Consumer Council (one-time $8 donation) during application" ,

"requirements_summary" : "Anyone can join via a one-time $8 association donation" ,

"eligibility_type" : "association" ,

"membership_fee_usd" : 8 ,

"min_deposit_usd" : 5 ,

"join_cost_usd" : 13 ,

"confidence" : 0.92

}

}

A supplied `military_status` that matches a credit union's military field-of-membership tag produces an `eligible_via_military` verdict, carrying the same join path, fees, and `join_cost_usd` :

{} eligible_via_military verdict

Copy

{

"credit_union_id" : "example cu|dayton|OH" ,

"status" : "eligible_via_military" ,

"matched_rule" : { "type" : "military" , "detail" : "active-duty, retired, and veteran service members" } ,

"join_path" : "Open a membership share with a $5 minimum deposit" ,

"requirements_summary" : "Serving the military community" ,

"eligibility_type" : "military" ,

"membership_fee_usd" : 0 ,

"min_deposit_usd" : 5 ,

"join_cost_usd" : 5 ,

"confidence" : 0.95

}

Eligible and open offers (including `eligible_via_military` ) rank ahead of geo-mismatch offers at equal APR - a tie-break, never a gate. `unknown` behaves exactly like today, so nothing breaks. Verified September 26, 2026.

4

Discovery Buckets

50

CUs per Check Call

100%

Claims Evidence-Backed

0

Institutions Published as Ineligible

How It Works

## Seven Surfaces, One Eligibility Model

Discover from a person, batch-check a shortlist, look up a place, fetch the full record, read the verdict inline on ranked offers, or cite what the whole graph holds

### 1. Graph-First Product Routing: “Which Published Products Match This Customer?”

`POST /v1/reachable-offers` accepts confirmed person facts plus a loan or deposit product. It builds the candidate set from positive, published membership paths **before** querying rates, and only returns fresh, rankable rate rows with source evidence. Promoted matches require both complete membership proof and complete published-rate proof.

cURL graph-first reachable offers

Copy

curl - X POST "https://api.rateapi.dev/v1/reachable-offers" \

- H "Authorization: Bearer YOUR_API_KEY" \

- H "Content-Type: application/json" \

- d '{

"person" : {

"home_state" : "NC" ,

"home_county" : "Mecklenburg" ,

"employer" : "Atrium Health" ,

"willing_to_join_association" : true

} ,

"product" : {

"product_type" : "auto_loan" ,

"amount" : 35000 ,

"term_months" : 60 ,

"vehicle_condition" : "new"

} ,

"limit" : 10

} '

Read `reachable_now` , `reachable_after_action` , `unresolved` , and `no_published_offer` separately. Lead only with the first two; the others remain unknown. Published pricing is not approval or guaranteed final availability. MCP: `find_reachable_offers` .

### 2. Person-Based Discovery: “Which Credit Unions Can I Join?”

`POST /v1/eligibility/search` is the endpoint for the question a consumer or an AI agent actually asks first. You do not supply candidate institutions - you supply the **person** . Send any combination of `home_zip` , `home_state` , `home_county` , `home_city` , `employer` , `school` (with `school_relationship` of `student` , `alumni` , or `employee` ), `associations` they already belong to, `military_status` (with `military_service_state` when a door is scoped to one state), `worship` , `occupation` , `property_zip` /`property_state` /`property_county` /`property_city` (where they own real property), `facility_zip` /`facility_state` /`facility_county` /`facility_city` (where their business maintains a location), `applicant_kind` (a natural person, or a trust, organization, partnership or corporation) and `asserted_org_qualifiers` . At least one is required - with no discriminating fact the honest answer would be “every credit union”, which is not a search result. Set `willing_to_join_association` to `true` when the person is open to joining an association to qualify, and `limit` (1-200, default 50) to cap each bucket. City fields require the matching role’s state or a recognized same-role ZIP that uniquely identifies one state, and are canonicalized against the closed Census place gazetteer; unresolved labels are rejected, never guessed.

cURL person-based membership discovery

Copy

curl - X POST "https://api.rateapi.dev/v1/eligibility/search" \

- H "Authorization: Bearer YOUR_API_KEY" \

- H "Content-Type: application/json" \

- d '{

"home_zip" : "28202" ,

"home_state" : "NC" ,

"employer" : "Bank of America" ,

"school" : "UNC Charlotte" ,

"school_relationship" : "alumni" ,

"associations" : [ "American Consumer Council" ] ,

"military_status" : "veteran" ,

"willing_to_join_association" : true ,

"limit" : 25

} '

The answer arrives in four buckets, ordered by how certain we are. Each entry carries the credit union's id, name, and state, a `confidence` score, a `reasons` array of deterministic sentences generated from the published rules (never model prose), the structured `paths` that were evaluated, and an `engine` marker:

- **eligible** - a verified membership path already applies.
- **conditionally_eligible** - one more step qualifies them. The step is named, with `join_cost_usd` and `join_url` when those are published.
- **possibly_eligible** - a path may apply, but at least one requirement could not be confirmed.
- **unknown** - rules exist but the supplied facts cannot decide them. **Unknown never means no.** The response does not merely name the input that would resolve it - it hands you the question. Returned `possibly_eligible` and `unknown` entries carry `missing_facts[]` : the question in the second person, the `fact_field` an answer populates, a deterministic `why` , and the institution's verbatim `evidence_quote` . The response then rolls those up into `next_questions[]` , sorted so the question that unlocks the most institutions comes first, and states in `unanswerable[]` what it deliberately will not ask about (`no_rules` , an organization the page names that we could not resolve, or a boundary such as a census tract, school district or an unidentified office radius that we can state but cannot decide).

{} four buckets, each with reasons and paths

Copy

{

"counts" : {

"eligible" : 12 ,

"conditionally_eligible" : 4 ,

"possibly_eligible" : 7 ,

"unknown" : 3

} ,

"candidates_evaluated" : 141 ,

"eligible" : [

{

"credit_union_id" : "example cu|charlotte|NC" ,

"name" : "Example Credit Union" ,

"state" : "NC" ,

"status" : "eligible" ,

"confidence" : 0.93 ,

"reasons" : [ "Eligible: lives in Mecklenburg County, NC." ] ,

"paths" : [

{

"rule_id" : 88014 ,

"kind" : "community_geo" ,

"reason" : "Lives in Mecklenburg County, NC" ,

"conditions_matched" : [ "county:NC:mecklenburg" ]

}

] ,

"engine" : "graph"

}

] ,

"conditionally_eligible" : [

{

"credit_union_id" : "another cu|raleigh|NC" ,

"name" : "Another Credit Union" ,

"state" : "NC" ,

"status" : "conditionally_eligible" ,

"confidence" : 0.81 ,

"reasons" : [ "Conditionally eligible: join the sponsoring association to qualify." ] ,

"paths" : [

{

"rule_id" : 88250 ,

"kind" : "association" ,

"reason" : "Membership open via the sponsoring association" ,

"conditions_matched" : [ ] ,

"conditional_on" : {

"type" : "join_association" ,

"cost_usd" : 8 ,

"join_url" : "https://example.org/join"

}

}

] ,

"join_cost_usd" : 8 ,

"join_url" : "https://example.org/join" ,

"engine" : "graph"

}

] ,

"possibly_eligible" : [ ] ,

"unknown" : [ ] ,

"resolved" : {

"orgs" : [ ] ,

"geo_keys" : [ "state:NC" , "county:NC:mecklenburg" , "zip:28202" ]

} ,

"limit" : 25 ,

"engine" : "graph+legacy_fallback" ,

"disclosure" : "Membership eligibility is guidance based on public charter data and institution websites; final determination is made by the institution."

}

**There is no fifth bucket.** A credit union whose every path deterministically fails against a complete, high-confidence rule set is simply *absent* from the response. We never publish a list of institutions a person is ineligible for - absence of evidence is not evidence of absence. Never read an institution's absence as a rejection.

`engine` is `graph` when the verdict came from published eligibility-graph rules, and `legacy` when it came from the annotation fallback for a credit union that has no rules encoded yet. Both are real answers: a coverage gap in the graph lowers an answer's confidence, never its recall. The `resolved` object echoes the organizations and canonical geography keys your facts resolved to - the audit trail for how the candidate set was narrowed. The same capability ships as the MCP tool `find_eligible_credit_unions` .

### 3. Eligibility-Aware Decision Requests

Optional request parameters sharpen the verdicts on any decisions call. `context.geo.county` pins the user's county for community-charter matching (when omitted, we resolve candidate counties from `zip` ); `borrower.employer` is fuzzily matched against each credit union's scraped employer-group list; and the affinity inputs `borrower.military_status` (`active_duty` , `veteran` , `reservist` , `dod_civilian` , `military_family` ), `borrower.school` , and `borrower.worship` are matched against each credit union's military, school, and place-of-worship field-of-membership tags. `preferences.eligible_only` is in **beta** : gated behind our identity-verification threshold, it currently annotates without filtering. Requesting it adds an `eligible_only_status` of `beta_annotation_only` to the response - no offers are dropped.

cURL decisions with eligibility params

Copy

curl - X POST "https://api.rateapi.dev/v1/decisions" \

- H "Authorization: Bearer YOUR_API_KEY" \

- H "Content-Type: application/json" \

- d '{

"decision_type" : "financing" ,

"context" : { "geo" : { "state" : "CA" , "zip" : "95814" , "county" : "Sacramento" } } ,

"borrower" : {

"credit_score" : 740 ,

"employer" : "Boeing" ,

"military_status" : "veteran" ,

"school" : "UC Davis" ,

"worship" : "First Baptist Church"

} ,

"preferences" : { "eligible_only" : true } ,

"product_request" : {

"product_type" : "mortgage" ,

"amount" : 420000 ,

"term_months" : 360

}

} '

`eligible_only` will begin filtering only once our validation sampling clears the identity bar; until then it is disclosed as beta on every response that requests it, and results are never silently reduced.

### 4. Full Field-of-Membership Record

Ranked offers carry the verdict; the complete criteria live behind a dedicated lookup, because employer lists can run to hundreds of entries. `GET /v1/credit-unions/{id}/eligibility` returns the whole record in one cacheable point-read: geo arrays, employers, associations, occupations, fees, provenance, and the `evidence_url` pointing at the recorded public source.

cURL full eligibility record

Copy

# credit_union_id is a composite "name|city|STATE" — URL-encode it in the path.

# The `eligibility.details` field on any /v1/rates row gives you a ready-made path.

curl "https://api.rateapi.dev/v1/credit-unions/example%20cu%7Csacramento%7CCA/eligibility" \

- H "Authorization: Bearer YOUR_API_KEY"

# Response

{

"credit_union_id" : "example cu|sacramento|CA" ,

"eligibility_type" : "community" ,

"open_to_anyone" : false ,

"join_path" : null ,

"geo_states" : [ "CA" ] ,

"geo_counties" : [ "Sacramento" , "Yolo" , "Placer" ] ,

"geo_cities" : [ ] ,

"employers" : [ "State of California" , "UC Davis Health" ] ,

"associations" : [ ] ,

"occupations" : [ ] ,

"family_membership" : true ,

"membership_fee_usd" : 0 ,

"min_deposit_usd" : 5 ,

"requirements_summary" : "Live, work, worship, or attend school in Sacramento, Yolo, or Placer County" ,

"source" : "scraped" ,

"confidence" : 0.9 ,

"evidence_url" : "https://www.example-cu.org/membership" ,

"extracted_at" : "2026-07-01T04:12:00Z" ,

"updated_at" : "2026-07-01T04:12:00Z" ,

"disclosure" : "Membership eligibility is guidance based on public charter data and institution websites; final determination is made by the institution."

}

`source` is `ncua` (charter data), `scraped` (an institution-published page or document), or `manual` . `confidence` reflects how many extracted claims survived verbatim-quote verification against the captured page text. See [how we verify membership eligibility](https://rateapi.dev/eligibility-methodology) for the identity guard, closed-world county matching, dual-vendor open gate, and our verified accuracy record.

The per-credit-union profile endpoint `GET /credit-unions/{state}/{slug}` also returns this `eligibility` object inline alongside the credit union's rates, so a single profile fetch answers both “what are the rates?” and “who can join?”. See the full endpoint list in the [API reference](https://rateapi.dev/api/reference) .

### 5. Batch Eligibility Check for a Named Shortlist

`POST /v1/eligibility/check` takes a `credit_union_ids` array (up to 50) and one `user` profile - `state` , `zip` , `county` (or the merge-and-retry aliases `home_state` , `home_zip` , and `home_county` ), plus exact home, worksite, payroll, owned-property, and business-facility `city` fields, `employer` , `occupation` , `military_status` , `school` , and `worship` , each optional; the more you supply, the sharper the verdicts - and returns a per-credit-union verdict with the matched rule, `join_cost_usd` when known, and concrete join steps. The same capability ships as the MCP tool `check_membership_eligibility` for AI agents.

cURL batch eligibility check

Copy

curl - X POST "https://api.rateapi.dev/v1/eligibility/check" \

- H "Authorization: Bearer YOUR_API_KEY" \

- H "Content-Type: application/json" \

- d '{

"credit_union_ids" : [ "example cu|sacramento|CA" , "another cu|davis|CA" ] ,

"user" : {

"state" : "CA" ,

"zip" : "95814" ,

"county" : "Sacramento" ,

"employer" : "Boeing" ,

"occupation" : "nurse" ,

"military_status" : "veteran" ,

"school" : "UC Davis" ,

"worship" : "First Baptist Church"

}

} '

Returns one verdict row per credit union with the same statuses used on ranked offers, so a verdict here always agrees with what a decisions call would annotate. Use this when you already have institutions in mind; use `POST /v1/eligibility/search` when you do not.

Where a credit union has an exact active publication, its verdict carries a `graph` object and the response reports `engine: "eligibility_publication_v1"` :

{} check verdicts from an exact graph publication

Copy

{

"count" : 2 ,

"user" : { "state" : "CA" , "resolved_counties" : [ "Sacramento" ] } ,

"results" : [

{

"credit_union_id" : "example cu|sacramento|CA" ,

"status" : "likely_eligible" ,

"eligibility_type" : "graph" ,

"confidence" : 0.9 ,

"record_confidence" : 0.9 ,

"details" : "/v1/credit-unions/example%20cu%7Csacramento%7CCA/eligibility" ,

"graph" : {

"status" : "eligible" ,

"confidence" : 0.9 ,

"paths" : [

{

"rule_id" : 41207 ,

"kind" : "community_geo" ,

"reason" : "Lives in Sacramento County, CA" ,

"conditions_matched" : [ "county:CA:sacramento" ]

}

] ,

"explain" : "Eligible: lives in Sacramento County, CA." ,

"publication" : {

"publication_id" : 1071 ,

"ruleset_sha256" : "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ,

"activated_at" : "2026-08-29T20:23:28.165Z" ,

"proposal_coverage" : {

"scope" : "source_page_model_proposals" ,

"proposed_claims" : 5 ,

"verified_claims" : 4 ,

"published_rules" : 4 ,

"withheld_claims" : 1 ,

"proposal_survival" : 0.8 ,

"withheld_reasons" : { "evidence_quote_mismatch" : 1 }

}

}

}

} ,

{

"credit_union_id" : "another cu|davis|CA" ,

"status" : "unknown" ,

"unknown_reason" : "no_membership_record" ,

"eligibility_type" : "unknown" ,

"confidence" : 0 ,

"record_confidence" : 0

}

] ,

"engine" : "eligibility_publication_v1" ,

"disclosure" : "Membership eligibility is guidance based on public charter data and institution websites; final determination is made by the institution."

}

**Publication authority:** the exact active publication governs both the top-level compatibility status and the richer `graph` verdict. Its `publication` object names the immutable publication ID, ruleset hash, activation time, and proposal coverage when recorded. That coverage separates verified published claims from withheld claims; one unverified claim does not hide the institution's verified sibling rules. A publication-less graph can still be returned as diagnostic `legacy+graph_shadow` , but it cannot replace the compatibility result.

Inside `graph` : `status` is one of the five graph values (`eligible` , `conditionally_eligible` , `possibly_eligible` , `ineligible` , `unknown` ); `paths` lists every membership path considered, each with its `rule_id` , `kind` , a human `reason` , `conditions_matched` , any `conditions_unknown` , and a `conditional_on` step when one further action would qualify; `unknown_reason` names why the verdict is not positive (`no_rules` , `geo_inputs_missing` , `org_inputs_missing` , `inputs_missing` , `low_confidence_rules` , `incomplete_fom` , or `unmodeled_condition` ); and `explain` is a deterministic one-sentence summary you can quote directly.

### 6. Place-Based Inverse Lookup

`GET /v1/eligibility/search` answers a different question from its POST twin: not “which credit unions can this person join?” but **“whose published membership area reaches this place?”** It asks nothing about an individual, and it is the data source behind our public who-can-join pages. Pass a `state` and optionally a `county` , or set `open_to_anyone=true` for the nationally-joinable list (in which case `state` becomes optional, because scoping an open-membership list to a state would be false).

cURL which credit unions reach a place

Copy

# Which credit unions' published membership area reaches Mecklenburg County, NC?

curl "https://api.rateapi.dev/v1/eligibility/search?state=NC&county=Mecklenburg" \

- H "Authorization: Bearer YOUR_API_KEY"

# Or: every credit union anyone in the US can join (state becomes optional)

curl "https://api.rateapi.dev/v1/eligibility/search?open_to_anyone=true" \

- H "Authorization: Bearer YOUR_API_KEY"

# Response

{

"state" : "NC" ,

"county" : "mecklenburg" ,

"count" : 2 ,

"results" : [

{

"credit_union_id" : "example cu|charlotte|NC" ,

"name" : "Example Credit Union" ,

"slug" : "example-credit-union" ,

"state" : "NC" ,

"eligibility_type" : "community" ,

"open_to_anyone" : false ,

"matched" : "county" ,

"join_path" : "Open a membership share with a $5 minimum deposit" ,

"requirements_summary" : "Live, work, worship, or attend school in Mecklenburg County" ,

"membership_fee_usd" : 0 ,

"min_deposit_usd" : 5 ,

"join_cost_usd" : 5 ,

"geo_counties" : [ "mecklenburg" , "union" ] ,

"source" : "scraped" ,

"confidence" : 0.91 ,

"evidence_url" : "https://www.example-cu.org/membership" ,

"extracted_at" : "2026-07-01T04:12:00Z"

}

] ,

"disclosure" : "Membership eligibility is guidance based on public charter data and institution websites; final determination is made by the institution."

}

Results are ranked county-specific evidence first (`matched: "county"` ), then state-wide records (`matched: "state"` ), then open-to-anyone records (`matched: "open"` ). A record naming the state but carrying no county detail serves the whole state and is never dropped from a county page for lacking county detail. A record whose non-empty county list omits the requested county *is* excluded - that omission is a positive assertion in the record, not missing data.

### 7. Coverage: “How Much of the Fleet Does This Actually Cover?”

`GET /v1/eligibility/coverage` is the aggregate the other five surfaces sit on, read from the rule graph itself rather than from a projection. It reports every number next to its denominator — live rules, institutions and their share of the active fleet, rules by kind, counties and employers named, verification split, freshness — and a dated `headline` sentence written to be quoted verbatim. It carries no institution-level rows. Like the other dedicated graph operations, it requires an **Enterprise Routes** key. MCP: `get_eligibility_coverage` .

cURL fleet-wide Enterprise coverage

Copy

curl "https://api.rateapi.dev/v1/eligibility/coverage"

# No key. Aggregate only.

{

"as_of" : "2026-08-22T18:14:15.715Z" ,

"headline" : "As of 2026-08-22, RateAPI holds 17,251 live membership-eligibility rules for 2,836 US credit unions (76% of 3,745 active institutions), each backed by a verbatim quote from the institution's own published page; 1,063 name specific counties (1,658 counties across 51 states) and 1,290 name specific employers (5,592 resolved organizations). No rule references a credit score, income or debt." ,

"fleet" : { "active_institutions" : 3745 , "institutions_with_live_rules" : 2836 , "share_with_live_rules" : 0.757 } ,

"rules" : { "live" : 17251 , "human_verified" : 1678 , "auto_validated" : 1418 , "with_verbatim_evidence" : 17251 , "median_age_days" : 6.5 , "confirmed_within_30d" : 17251 } ,

"by_kind" : [ { "rule_kind" : "employment" , "rules" : 7103 , "institutions" : 1314 } , { "rule_kind" : "geography" , "rules" : 5103 , "institutions" : 1128 } , "..." ] ,

"reach" : { "counties_named" : 1658 , "states_with_county_rules" : 51 , "employers_resolved" : 5592 , "institutions_open_to_anyone" : 13 , "..." : "..." } ,

"pipeline" : [ { "status" : "published" , "institutions" : 2541 } , { "status" : "no_source_found" , "institutions" : 473 } , "..." ] ,

"credit_data" : { "conditions_referencing_credit" : 0 , "note" : "The condition schema has no kind for credit score, income or debt. ..." }

}

The place lookup above answers for one place, graph-first; this endpoint reads the whole graph and is the figure to quote for coverage. An institution absent from the graph is *undecided* and comes back from the other surfaces as `unknown` with `unknown_reason: no_rules` — never as ineligible.

For Agent Builders

## CLI Capabilities, MCP Tools, and a Public Page for Every State

Use the CLI from terminal agents; use direct MCP from hosted/no-shell clients

### One Model, Three Execution Surfaces

Terminal-capable agents discover and run these through the RateAPI CLI. Hosted or no-shell clients can use the corresponding tools on `https://mcp.rateapi.dev/mcp` , while applications use REST. The composed full-fleet `find_reachable_offers` router and every other dedicated Routes tool require a signed-in Enterprise organization:

- **find_reachable_offers** - the primary product-routing tool. Pass confirmed person facts plus a product request; the graph-positive institution set is intersected with fresh, evidenced rates. REST equivalent: `POST /v1/reachable-offers` .
- **find_eligible_credit_unions** - the discovery tool. Pass the person's facts, get the four buckets back. Use it to answer “which credit unions can I join?”. REST equivalent: `POST /v1/eligibility/search` .
- **check_membership_eligibility** - the verification tool. Pass up to 50 `credit_union_ids` you already have plus home, worksite, payroll, owned-property, or business-facility geography, get one verdict each. REST equivalent: `POST /v1/eligibility/check` .
- **get_eligibility_coverage** - the citation tool. No inputs; returns what the whole graph holds (institutions with live rules, rules by kind, counties and employers named, verification, freshness) and a dated `headline` sentence to quote verbatim. Call it when the user asks how complete or how fresh the data is. REST equivalent: `GET /v1/eligibility/coverage` , Enterprise.

$ run eligibility from a terminal agent

Copy

npm install - - global @rateapi / cli

rateapi agent - - json

rateapi run eligibility - discovery - - input @ - - - confirm - request - - idempotency - key < uuid > - - json

Guidance for agents: quote the `reasons` array rather than paraphrasing it - it is deterministic text generated from the published rules. Treat `unknown` as “not yet decided” and ask the user for the input the response names. Never tell a user they are ineligible for an institution that is merely absent from a discovery result.

### Who-Can-Join Pages

The same records are published as human- and crawler-readable pages, so an assistant can cite a URL instead of an API response:

- [/who-can-join/anyone](https://rateapi.dev/who-can-join/anyone) - every credit union anyone in the US can join, with the join path and the up-front cost.
- `/who-can-join/{state}` - the credit unions whose published membership area reaches a given state, with per-record provenance and the `evidence_url` pointing at the recorded public source.

Use Cases

## Who Checks Eligibility?

### Personal Finance Apps

Show the best published rates with documented membership paths. Put the join path next to each match so "switch and save" is actionable, not a dead end.

### Loan Marketplaces

Stop losing conversions to "sorry, you can't join" rejections. Re-rank by eligibility today; `eligible_only` filtering is in beta pending our identity-verification threshold.

### AI Agents & Chatbots

Answer "which credit unions can I join?" in one turn with the `find_eligible_credit_unions` MCP tool, or verify a named shortlist with `check_membership_eligibility` . Both return deterministic reasons and an evidence link, and neither ever asserts ineligibility.

### Loan Officers & Brokers

Pre-qualify a client's credit union shortlist before the first call - the verdict, the fee, and the join steps arrive in one request.

### Credit Unions

See how your field of membership reads to comparison surfaces, and verify each recorded quote and source via `evidence_url` .

### Researchers & Data Teams

Study field-of-membership structure across the fleet - charter types, community footprints, association join paths, and fees - through one consistent schema.

Quick Start

## Start an Enterprise Evaluation

1

### Activate RateAPI Routes

We provision an Enterprise organization and an evaluation key for REST, MCP, and managed widget testing.

One entitlement across every Routes surface

Talk to us about Routes

2

### Check a Shortlist

Verdict up to 50 credit unions against one user profile

cURL terminal

Copy

curl - X POST "https://api.rateapi.dev/v1/eligibility/check" \

- H "Authorization: Bearer YOUR_API_KEY" \

- H "Content-Type: application/json" \

- d '{

"credit_union_ids" : [ "example cu|sacramento|CA" , "another cu|davis|CA" ] ,

"user" : {

"state" : "CA" ,

"zip" : "95814" ,

"county" : "Sacramento" ,

"employer" : "Boeing" ,

"occupation" : "nurse" ,

"military_status" : "veteran" ,

"school" : "UC Davis" ,

"worship" : "First Baptist Church"

}

} '

3

### Rank With Eligibility Built In

Add `county` and `employer` to your decisions calls

[Open the calculator in the dashboard →](https://app.rateapi.dev/playground) [View API Docs](https://api.rateapi.dev/)

FAQ

## Frequently Asked Questions

Quick answers about membership eligibility

POST /v1/reachable-offers, or use the MCP tool find_reachable_offers. Send confirmed person facts plus a product request. RateAPI evaluates the complete active credit-union fleet against published membership-graph paths before intersecting fresh, rankable, evidenced rates. Results are separated into reachable_now, reachable_after_action, unresolved, and no_published_offer. Lead with the first two; the others remain unknown. Published pricing is not approval or guaranteed final availability.

How do I find rates from credit unions a person may actually reach?

POST /v1/eligibility/search. Send the person's facts - including home, worksite, payroll, owned-property, and business-facility geography, each with its own zip/state/county/city fields; employer; school (with school_relationship of student, alumni, or employee); associations; military_status (with military_service_state when the door is scoped to one state); worship; occupation; applicant_kind; and asserted_org_qualifiers. At least one discriminating fact is required. A city requires its same-role state or a recognized same-role ZIP that uniquely identifies one state, and must resolve in the closed Census gazetteer. The response returns four buckets: eligible (a verified path already applies), conditionally_eligible (one more step, such as joining an association, with join_cost_usd and join_url when published), possibly_eligible (a path may apply but a requirement could not be confirmed), and unknown (rules exist but the supplied facts cannot decide them). Each entry carries the credit union id, name, state, confidence, and a reasons array of deterministic sentences. Set willing_to_join_association to true when the person is open to joining an association to qualify. Returned possibly_eligible and unknown entries also carry missing_facts[] - the question to ask the person, the fact_field an answer populates, and the institution's verbatim evidence_quote - and the response rolls those up into next_questions[], sorted by how many institutions each question unlocks, alongside unanswerable[] for what no question can fix. The same capability ships as the MCP tool find_eligible_credit_unions.

How do I find which credit unions a person can join?

No. Customer-safe discovery converts every negative graph evaluation to unknown unless an independently validated closed-world field-of-membership attestation exists. Current publications do not carry that attestation, so a non-match remains in the candidate set as unknown with fom_completeness_unaffirmed. The candidate search is bounded, so an institution may also be absent because it was never evaluated; absence is never a rejection.

Does the discovery endpoint ever tell me I am ineligible?

eligible, conditionally_eligible, possibly_eligible, ineligible, and unknown. eligible means a verified membership path already applies. conditionally_eligible means one further step would qualify the person, and the step is named with its cost and join URL when those are published. possibly_eligible means a path may apply but at least one requirement could not be confirmed. unknown means rules exist but the supplied facts cannot decide them - it is never a no. ineligible is reserved for a future independently attested complete field of membership; current negative evaluations are returned as unknown with fom_completeness_unaffirmed.

What are the five eligibility-graph statuses?

Where a credit union has an exact active publication, POST /v1/eligibility/check derives both the compatibility status and the richer graph object from that immutable generation and returns engine: eligibility_publication_v1. graph.publication identifies publication_id, ruleset_sha256, activated_at, and proposal_coverage when recorded. proposal_coverage reports which source-page model claims verified and were published versus withheld; a withheld claim never suppresses verified sibling rules. A publication-less compatibility graph may still appear diagnostically as legacy+graph_shadow, but it cannot replace the top-level result.

What is the graph object on eligibility check results?

GET /v1/eligibility/search?state=NC&county=Mecklenburg. This is the place-based inverse lookup and the data source behind the public who-can-join pages. Results are ranked county-specific evidence first (matched: county), then state-wide records (matched: state), then open-to-anyone records (matched: open). A record that names the state but carries no county detail serves the whole state and is never dropped from a county for lacking county detail; a record whose non-empty county list omits the county IS excluded, because that omission is a positive assertion in the record. Add open_to_anyone=true for the nationally-joinable list, in which case state becomes optional.

Which credit unions can someone in a specific county join?

Every ranked credit union offer on /v1/decisions, /v1/league-table, and /v1/rates can carry an eligibility object with a status, the matched_rule that produced it, a join_path (concrete steps to become a member), a one-line requirements_summary, the eligibility_type of the charter, and a confidence score. Offers for credit unions we have no eligibility data on simply omit the field - the annotation is strictly additive.

What is the eligibility object on ranked offers?

open_to_anyone means the credit union offers a join path available to any US consumer, typically via an association membership. likely_eligible means the user's state, county, occupation, school, or place of worship matches the credit union's community or affinity footprint. eligible_via_employer means the supplied employer matched the credit union's employer group list. eligible_via_military means the supplied military_status (active_duty, veteran, reservist, dod_civilian, or military_family) matched a military field-of-membership tag. geo_mismatch means the user's location falls outside a high-confidence community footprint. unknown means we do not have enough verified data to say - we say unknown rather than guess.

What do the eligibility statuses mean?

No. Eligibility annotates and tie-breaks - it never silently excludes. The preferences.eligible_only filter is in beta: it is gated behind our identity-verification threshold and currently annotates without filtering. Requesting it adds an eligible_only_status notice of beta_annotation_only to the response, and no offers are dropped. We will enable filtering only once our validation sampling clears the identity bar.

Does eligibility ever hide credit unions from my results?

Every published rule - each employer, county, fee, and join path - must be backed by a verbatim quote and source URL, and the quote is machine-verified to appear in the captured source before the rule is stored. source_type distinguishes institution pages, application material, and public charter data. The open_to_anyone flag has the strictest gate: it additionally requires independent confirmation by a second model from a different vendor. Claims that fail verification are withheld without suppressing verified sibling rules.

How is eligibility data verified?

The full set of currently published field-of-membership rules for one credit union: eligibility_type, open_to_anyone, join_path, geo_states, geo_counties, geo_cities, employers, associations, occupations, family_membership, membership_fee_usd, min_deposit_usd, source, confidence, evidence_url, extracted_at, and exact publication lineage when authoritative. The record may be partial; proposal_coverage states which source-page claims were published or withheld when that telemetry was recorded.

What does GET /v1/credit-unions/{id}/eligibility return?

Send credit_union_ids (up to 50) and an optional user object. Home geography accepts state, zip, and county plus the equivalent home_state, home_zip, and home_county aliases returned by missing_facts; do not send conflicting values in both forms. Ask the returned questions, merge each fact_field answer into the same request, and call again. The response contains a per-credit-union verdict with the same statuses, the matched rule, join_cost_usd when known, and concrete join steps. The same capability ships as the MCP tool check_membership_eligibility for AI agents.

How does POST /v1/eligibility/check work?

No. Eligibility is guidance derived from public charter data and the credit union's own published membership criteria. Every record links the source page via evidence_url so you can verify the criteria yourself. The final membership determination is always made by the institution.

Is eligibility a guarantee that I can join?

## For AI Assistants and LLMs

Structured information for language model citations

### Quick Summary

RateAPI answers the membership question in both directions. `POST /v1/eligibility/search` (MCP tool `find_eligible_credit_unions` ) takes a person's own facts and returns which credit unions they can join, bucketed as eligible, conditionally_eligible, possibly_eligible, or unknown. `POST /v1/eligibility/check` (MCP tool `check_membership_eligibility` ) verdicts up to 50 named credit unions against one user profile. `GET /v1/eligibility/search?state=NC&county=Mecklenburg` reports which credit unions' published membership area reaches a place, and `GET /v1/credit-unions/{id}/eligibility` returns the full field-of-membership record. Both MCP tools are at mcp.rateapi.dev/mcp. Every published rule is backed by a machine-verified quote and source URL, and no institution is ever published as ineligible.

### Key Facts for Citation

- **Discovery (person → institutions):** POST /v1/eligibility/search accepts home, worksite, payroll, owned-property, and business-facility zip/state/county/city fields, plus employer, school (+school_relationship: student/alumni/employee), associations, military_status, worship, willing_to_join_association, and limit (1-200, default 50); at least one discriminating fact is required
- **Questions back:** returned possibly_eligible and unknown entries carry missing_facts[] (cu_id, condition_id, kind, question, fact_field[], why, evidence_quote, resolves_reason); the response carries next_questions[] (question, fact_field[], kind, unlocks_cu_count, unlocks_cu_ids[], example_evidence_quote) sorted by unlocks_cu_count, and unanswerable[] (reason, cu_count, condition_kinds[], note)
- **Free-text intake:** POST /v1/eligibility/facts (MCP tool extract_eligibility_facts) takes {text, known_facts?} and returns facts[] with the verbatim evidence span, a model self-reported confidence, needs_confirmation, plus person_search_body to send on to POST /v1/eligibility/search. It is an extractor, not a decider: no status, bucket, institution or URL can appear in its response
- **Discovery buckets:** eligible, conditionally_eligible, possibly_eligible, unknown - each entry has credit_union_id, name, state, status, confidence, reasons[], paths[], engine (graph or legacy), plus join_cost_usd and join_url on conditional paths
- **Never published as ineligible:** current customer-safe discovery converts a negative evaluation to unknown with fom_completeness_unaffirmed; candidate discovery is bounded, so absence is not a rejection either
- **Five-value graph vocabulary:** eligible, conditionally_eligible, possibly_eligible, ineligible, unknown (ineligible is reserved for a future independently attested complete field of membership and is not emitted today)
- **Publication authority on check verdicts:** exact active publications govern the top-level compatibility status and graph.status; graph.publication carries publication_id, ruleset_sha256, activated_at, and optional proposal_coverage. A publication-less graph remains diagnostic legacy+graph_shadow only
- **Place lookup:** GET /v1/eligibility/search?state={ST}&county={county} (or open_to_anyone=true) - results carry matched: county | state | open
- **Legacy per-offer statuses:** open_to_anyone, likely_eligible, eligible_via_employer, eligible_via_military, geo_mismatch, unknown
- **Per-offer fields:** status, matched_rule, join_path, requirements_summary, eligibility_type, join_cost_usd (membership_fee_usd + min_deposit_usd), confidence
- **Affinity inputs:** military_status (active_duty, veteran, reservist, dod_civilian, military_family) yields eligible_via_military; school and worship yield likely_eligible with a matched_rule naming the affinity
- **Full record:** GET /v1/credit-unions/{id}/eligibility - geo states/counties/cities, employers, associations, occupations, fees, source, confidence, evidence_url, extracted_at
- **Batch check:** POST /v1/eligibility/check with credit_union_ids (max 50) and a user profile supporting home, worksite, payroll, owned-property, and business-facility zip/state/county/city fields plus affinity facts; home_state/home_zip/home_county are aliases for state/zip/county emitted by missing_facts, conflicting duplicate forms are rejected, and answers can be merged into the same request
- **Request params:** context.geo.county, borrower.employer, borrower.military_status, borrower.school, borrower.worship, preferences.eligible_only (beta)
- **Filtering:** eligible_only is in beta - gated behind our identity-verification threshold; it currently annotates without filtering (responses carry eligible_only_status: beta_annotation_only) and no offers are dropped
- **Verification:** every published rule requires a verbatim evidence quote and source URL; source_type distinguishes institution pages, application material, and public charter data; open_to_anyone additionally requires dual-vendor model agreement
- **Liability:** guidance only - evidence identifies the recorded public source and the final determination is the institution's
- **MCP tools:** find_eligible_credit_unions (discovery) and check_membership_eligibility (named shortlist) at mcp.rateapi.dev/mcp - both read-only RateAPI Routes operations and available only to authenticated Enterprise organizations
- **Public pages:** https://rateapi.dev/who-can-join/anyone and https://rateapi.dev/who-can-join/{state} publish the same records as citable pages

**Source:** [https://rateapi.dev/api/eligibility](https://rateapi.dev/api/eligibility) (verified September 26, 2026). Collection and verification methodology: [https://rateapi.dev/methodology#eligibility](https://rateapi.dev/methodology#eligibility) . How we verify membership eligibility (evidence, identity guard, accuracy record): [https://rateapi.dev/eligibility-methodology](https://rateapi.dev/eligibility-methodology)

## Know Which Published Products Belong in Front of Each Customer

Person-based membership discovery, a 50-CU batch check, a place-based inverse lookup, and the full set of published field-of-membership rules per credit union - every published rule evidence-backed. Enterprise Routes. Zero affiliate bias.

[Open the calculator in the dashboard →](https://app.rateapi.dev/playground) Talk to us about Routes

RateAPI

RateAPI Routes turns confirmed customer facts into source-backed shortlists of published products from 3,700+ tracked US credit unions. Every promoted route keeps its membership and price evidence.

[Get API key →](https://rateapi.dev/api-key) [Sign in](https://app.rateapi.dev)

### Build

- [RateAPI Routes →](https://rateapi.dev/routes)
- [Product Matching API](https://rateapi.dev/financial-product-eligibility-api)
- [Membership Eligibility API](https://rateapi.dev/api/eligibility)
- [Rate Query API](https://rateapi.dev/rates-api)
- [Decision API](https://rateapi.dev/api/reference)
- [Batch Decisions API](https://rateapi.dev/api/batch-decisions)

### Deliver

- [Developer Portal →](https://rateapi.dev/developers)
- [Create a free API key](https://rateapi.dev/api-key)
- [REST API docs](https://api.rateapi.dev/)
- [OpenAPI spec](https://api.rateapi.dev/openapi.json)
- [MCP Server](https://rateapi.dev/mcp)
- [Widget builder](https://rateapi.dev/widget-builder)
- [RateAPI Routes widget](https://rateapi.dev/widget-docs/routes)
- [Market Rates widget](https://rateapi.dev/widget-docs/rates)
- [Webhooks](https://api.rateapi.dev/webhooks)
- [Versioning & deprecation](https://rateapi.dev/deprecation-policy)
- [GitHub](https://github.com/rate-api)

### Solutions

- [Personal finance apps](https://rateapi.dev/use-cases/personal-finance-apps)
- [AI purchase advisors](https://rateapi.dev/use-cases/ai-purchasing-tools)
- [AI agents](https://rateapi.dev/use-cases/ai-agents)
- [Car buying platforms](https://rateapi.dev/use-cases/car-buying-platforms)
- [Credit unions](https://rateapi.dev/for-credit-unions)
- [Loan officers](https://rateapi.dev/use-cases/loan-officers)
- [Rate data for ALM](https://rateapi.dev/alm-rate-data)

### Trust

- [Data coverage](https://rateapi.dev/data-coverage)
- [Rate methodology](https://rateapi.dev/methodology)
- [Eligibility methodology](https://rateapi.dev/eligibility-methodology)
- [Transparency](https://rateapi.dev/transparency)
- [Independence](https://rateapi.dev/independence)
- [Corrections](https://rateapi.dev/corrections)
- [Pricing](https://rateapi.dev/pricing)
- [About](https://rateapi.dev/about)
- [Contact](https://rateapi.dev/contact)
- Talk to a human

### Inspect the data behind the API

Public data explorer

- [Current mortgage rates](https://rateapi.dev/current-mortgage-rates)
- [Current auto rates](https://rateapi.dev/current-auto-loan-rates)
- [Current CD rates](https://rateapi.dev/current-cd-rates)
- [Current HELOC rates](https://rateapi.dev/current-heloc-rates)
- [Current personal loan rates](https://rateapi.dev/current-personal-loan-rates)
- [Mortgage rates](https://rateapi.dev/mortgage-rates)
- [Refinance rates](https://rateapi.dev/refinance-rates)
- [Auto loan rates](https://rateapi.dev/auto-loan-rates)
- [RV loan rates](https://rateapi.dev/rv-loan-rates)
- [Boat rates](https://rateapi.dev/boat-loan-rates)
- [Motorcycle rates](https://rateapi.dev/motorcycle-loan-rates)
- [HELOC rates](https://rateapi.dev/heloc-rates)
- [Personal loan rates](https://rateapi.dev/personal-loan-rates)
- [Credit card rates](https://rateapi.dev/credit-card-rates)
- [Deposit rates](https://rateapi.dev/deposit-rates)
- [CD rates](https://rateapi.dev/cd-rates)
- [Savings rates](https://rateapi.dev/savings-rates)
- [Money market rates](https://rateapi.dev/money-market-rates)
- [Credit union directory](https://rateapi.dev/credit-unions)
- [Who can join](https://rateapi.dev/who-can-join)
- [Mortgage benchmark](https://rateapi.dev/mortgage-rate-benchmark)
- [Auto benchmark](https://rateapi.dev/auto-loan-rate-benchmark)
- [HELOC benchmark](https://rateapi.dev/heloc-rate-benchmark)
- [Personal loan benchmark](https://rateapi.dev/personal-loan-rate-benchmark)
- [CD benchmark](https://rateapi.dev/cd-rate-benchmark)
- [Credit union rate index](https://rateapi.dev/credit-union-rate-index)
- [Deposit beta](https://rateapi.dev/deposit-beta)
- [Credit unions vs banks: mortgage](https://rateapi.dev/compare/credit-union-vs-bank-rates)
- [Credit unions vs banks: auto](https://rateapi.dev/compare/credit-union-vs-bank-auto-loan-rates)
- [Credit unions vs banks: HELOC](https://rateapi.dev/compare/credit-union-vs-bank-heloc-rates)
- [Credit unions vs banks: CD](https://rateapi.dev/compare/credit-union-vs-bank-cd-rates)
- [Mortgage rate API comparison](https://rateapi.dev/compare/mortgage-rate-apis)
- [Rate datasets](https://rateapi.dev/credit-union-rate-dataset)

© 2026 RateAPI · US credit unions only · Published pricing is not approval.

[Privacy](https://rateapi.dev/privacy) [Terms](https://rateapi.dev/terms) [llms.txt](https://rateapi.dev/llms.txt)

---

Source: https://rateapi.dev/api/eligibility
Rate data API: https://api.rateapi.dev · OpenAPI: https://api.rateapi.dev/openapi.json · MCP: https://mcp.rateapi.dev/mcp
