pyncua
Python client for the NCUA Credit Union Mapping API. Search credit union offices by name, charter number, or address; retrieve full institutional profiles; run advanced filtered searches; download call reports and profiles as PDF.
Provides both synchronous and asynchronous clients with typed Pydantic v2 response models.
Inspired by ContinuityControl/ncua, a Ruby gem that wrapped NCUA's now-retired ASP.NET endpoint. pyncua is not a fork — it is a complete rewrite in Python targeting NCUA's current JSON API at
mapping.ncua.gov/api.
Install
pip install pyncua
Requires Python 3.10+.
Quick Start
from pyncua import NCUAClient
with NCUAClient() as client:
# Search offices by name
result = client.find_offices_by_name("Navy Federal")
for office in result.offices:
print(f"{office.credit_union_name} — {office.city}, {office.state}")
# Get full credit union details
details = client.get_credit_union(5536)
print(
f"{details.name}: {details.assets_formatted} in assets, {details.members_formatted} members"
)
# Advanced filtered search
from pyncua import CUType, CUStatus
results = client.search_credit_unions(
cu_type=CUType.FEDERAL,
status=CUStatus.ACTIVE,
state="VA",
)
for cu in results.results:
print(f" {cu.name} (#{cu.charter_number}) — {cu.city}, {cu.state}")
API Coverage
| Method | Description |
|---|---|
find_offices_by_name(name) |
Search office locations by credit union name |
find_offices_by_charter(charter) |
Search office locations by charter number |
find_offices_by_address(address, radius) |
Search offices near an address/zip |
get_credit_union(charter) |
Full institutional profile by charter number |
search_names(name) |
Lightweight name autocomplete |
search_credit_unions(...) |
Advanced filtered search (type, status, region, state, etc.) |
get_online_credit_unions() |
List online-only credit unions |
download_call_report(charter, cycle_date) |
Download call report PDF |
download_profile(charter, cycle_date) |
Download profile PDF |
get_api_version() |
NCUA API version string |
get_current_cycle() |
Current reporting cycle date |
get_cycle_years() |
Available years for event data |
get_merger_query_years() |
Available years for merger data |
find_offices_by_* methods accept boolean filter kwargs (atm, drive_thru, bilingual, etc.).
Choosing a search method
find_offices_by_address geocodes server-side and returns branch locations near a point.
search_credit_unions filters on the credit union's headquarters city. These give
materially different answers: a search for city="Pittsburgh" misses Clearview
(#9007, $2.2B in assets) because its charter address is Moon Township, even though it
operates numerous Pittsburgh branches. For "who serves this area," use the office search.
Pagination
All search methods take skip/take. take is capped at 100 — the NCUA API
silently truncates anything larger while still reporting the true count in
total_result_count, so pyncua raises NCUAValidationError rather than hand back a
short result set you might mistake for the whole answer. Page with skip:
from pyncua import NCUAClient
with NCUAClient() as client:
first = client.search_credit_unions(state="PA", take=100)
rows = list(first.results)
while len(rows) < first.total_result_count:
page = client.search_credit_unions(state="PA", skip=len(rows), take=100)
if not page.results:
break
rows.extend(page.results)
Async
from pyncua import AsyncNCUAClient
async with AsyncNCUAClient() as client:
result = await client.find_offices_by_name("Navy Federal")
The async client mirrors the sync API exactly.
Error Handling
from pyncua import NCUAClient, NCUANotFoundError, NCUAValidationError
with NCUAClient() as client:
try:
details = client.get_credit_union(9999999)
except NCUANotFoundError:
print("Charter number not found")
except NCUAValidationError:
print("Invalid request")
NCUAValidationError also covers client-side guards that fire before any request is
made — an out-of-range radius or a take above 100.
A search that matches nothing is not an error. NCUA returns valid=True with an
empty list for an address it cannot resolve, so check the results rather than relying
on an exception:
result = client.find_offices_by_address("Pittsburgh, PA", radius=10)
if not result.offices:
print("No offices found")
Acknowledgments
This project was inspired by ContinuityControl/ncua, a Ruby gem by ContinuityControl that provided the original idea for wrapping the NCUA's credit union data API. While pyncua is an independent, ground-up implementation in Python (not a fork or port), the ContinuityControl team's work demonstrated the value of a clean client library for this data and motivated this project.
License
Metadata
Release files for pyncua 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyncua-1.0.2.tar.gz | 67.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyncua-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 80.2 kB
Release files / pyncua-1.0.2.tar.gz
| Download URL | pyncua-1.0.2.tar.gz |
|---|---|
| Size | 67.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4599aa8a0ed31589ec0839472779073524c4bbc1ffe93b01278635c6344a92a0
|
|
BLAKE2b-256 checksum How to use checksums |
6f986aa97594236f877cb9589872cf80c17e6ad937b9f30169f18304a2fb390f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / pyncua-1.0.2-py3-none-any.whl
| Download URL | pyncua-1.0.2-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
156dccfdd74429001ca48a4f0739d7c96a02902fbc1c30a9b779630dd980eeed
|
|
BLAKE2b-256 checksum How to use checksums |
59d530e6bc28c82be4e2dd30b14e06863f45f199d23abd02b8780092118d0ad2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log