Finding Cuba-Related Records with the ForeignAssistance.gov API

avatar
(Edited)

ForeignAssistance.gov

One of the challenges I keep running into while researching the U.S.-funded Cuba "democracy" program is that the public search interface of ForeignAssistance.gov is far more restrictive than the underlying dataset. This is not necessarily intentional, but the practical consequence is that it becomes impossible to discover every Cuba-related record through the official web interface alone.

ForeignAssistance.gov is "the U.S. government's flagship website for U.S. foreign assistance data." At some point, it absorbed the information previously available through Explorer.usaid.gov, making it an essential source that I cross-reference with USASpending.gov to track projects associated with this program established between 1995 and 1996 by the now-defunct USAID.

The problem is that the web interface does not allow searches across critical text fields such as Activity Name or Activity Description. Instead, most searches are centered around fields like the recipient country, the managing agencies, or the purpose of the funding —i.e., "Democratic participation and civil society". That sounds reasonable, until you realize that many Cuba-related activities are not reported under Cuba at all.

Some are reported as regional initiatives, others as global programs, and in a few particularly interesting cases, funding associated with Cuba has appeared under countries as unexpected as Afghanistan. In other words, searching for Country = Cuba inevitably misses part of the picture. So I decided to build a small Python utility that talks directly to the ForeignAssistance.gov API.

Instead of filtering by country, the application scans every available record looking for keywords such as

Cuba
Cuban
Cubans

inside the Activity Name and Activity Description fields, while excluding records whose associated country is actually Cuba.


The basic idea

The application retrieves paginated results from the API endpoint

/data-api/complete-data.json

and inspects two text fields from every record:

ACTIVITY_NAME_FIELD = "activity_name"
ACTIVITY_DESCRIPTION_FIELD = "activity_description"

Keyword detection is handled through a regular expression:

CUBA_PATTERN = re.compile(r"\bCuban?s?\b", re.IGNORECASE)

Ignoring records that actually belong to Cuba

The goal is not to find records that are easy to retrieve by filtering "Cuba" as the recipient country. Instead, the script deliberately filters them out by checking both the country name and the country code.

def is_cuba_country(record):
    country_name = safe_str(record.get("country_name")).lower()

    if country_name == "cuba":
        return True

    country_code = safe_str(record.get("country_code")).upper()

    if country_code in ("CUB", "CU"):
        return True

    return False

This allows the search to focus on mentions of Cuba occurring elsewhere in the database.


Useful filtering options

Once records have been collected, they can be filtered using multiple criteria without modifying the code.

Examples include:

  • recipient countries

  • fiscal years

  • funding agencies

  • managing agencies

  • implementing organizations

  • activity periods

For example:

python find_cuba_mismatches.py \
    --countries Spain \
    --funding-agency "Department of State" \
    --out spain.csv

or

python find_cuba_mismatches.py \
    --executing-org "Freedom House" \
    --fiscal-years 2022 2023 2024 \
    --out freedom_house.csv

This makes it possible to explore the dataset from several analytical perspectives.


CSV output

Every matching record is exported into a CSV file containing information such as:

  • matched field

  • matched text

  • country

  • activity name

  • activity description

  • fiscal year

  • funding amount

  • implementing organization

  • funding agency

  • project identifiers


What have I found so far?

Well, as I hinted above, I found five U.S. Department of State projects—all reporting activity in FY2016—that are officially associated with Afghanistan and Pakistan, yet whose activity_name fields leave little doubt about the actual target of the funding:

  1. Cuba Building a Foundation for Democratic Politic[s]

  2. Fostering Cuban Socio Cultural Dialogue FOCUS Pr[ogram]

  3. Internet Policy in Cuba I3PC

  4. Cuba Emergente: A Latin Immersion Program for Cuba

  5. Inclusive Cuba

In every one of these records, the activity_description field is redacted—thanks to the deliberately broad disclosure exemptions provided by the FATAA. In most cases, the implementing_partner field is also redacted. Where that information is available, however, it identifies an organization that has never, to my knowledge, been associated with Cuba-related democracy programs: Nationwide Supplies, L.P.

Is this simply a reporting error? Or does it reflect funds that were initially allocated to Afghanistan and Pakistan before being redirected elsewhere—i.e., Cuba? One project in particular caught my attention. Internet Policy in Cuba I3PC bears a remarkably similar name to the Internews Initiative for Internet Progress in Cuba (I3PC), a program launched in 2015 by Internews, a long-standing contractor for both USAID and the U.S. Department of State.

Back in 2014, following revelations about USAID's ill-fated ZunZuneo project, reports emerged explaining that similar social media technologies had also been tested in Afghanistan and Pakistan. Thus, these five projects found in ForeignAssistance.gov—and the one found in the federal audits involving Internews—postdate what became a major political scandal for the U.S. government.

I also found a USAID grant (7200AA23CA00030) awarded to Freedom House that is officially associated with Venezuela, yet whose description explicitly states:

"The activity supports activists from Guatemala, Nicaragua, Venezuela and Cuba in documenting and presenting evidence of their governments abuses to international organizations."

Without searching the description itself, associating this award with Cuba would require manually browsing Freedom House projects and finding it almost by serendipity. That is precisely why direct access to the ForeignAssistance.gov API is so valuable. Meanwhile, the corresponding USASpending page contains no reference to Cuba.

Another example is grant 7200AA20CA00037, awarded to the International Republican Institute, which is reported with a global scope. Finally, there is grant 7200AA23LA00002, awarded to Freedom House, which appears in ForeignAssistance.gov as a regional initiative ("Latin America and Caribbean Region"). Yet its description clearly states:

"USAID provides basic needs assistance to political prisoners, their families, and politically marginalized individuals in Cuba to alleviate the hardships they endure due to their political beliefs or efforts to exercise their fundamental freedoms."

In this particular case, the corresponding USASpending file does indicate that the grant is performed primarily—or mostly—in Cuba. However, another limitation emerges here: USASpending's keyword search does not index the "Place of Performance" field. Once again, this limitation disappears when querying the API directly, which is exactly what I already do in a separate Python application built specifically for USASpending.

Why this matters

If your research relies exclusively on the ForeignAssistance.gov website, you're effectively limited by the assumptions built into its search interface. Working directly against the API makes it possible to uncover records that would otherwise remain practically invisible. This could also be done by walking through the full dataset in CSV format, but I prefer working with APIs as the first source, so these CSV files operate as backup sources.



1 comments
avatar

Thanks for your contribution to the STEMsocial community. Feel free to join us on discord to get to know the rest of us!

Please consider delegating to the @stemsocial account (85% of the curation rewards are returned).

Thanks for including @stemsocial as a beneficiary of this post and your support for promoting science and education on Hive.