API reference
Early access. The VeraGen API is not open yet: this reference shows what it will do, and keys cannot be created until it opens. Request early access.

API reference

FOIA Gen

FOIA Gen's directory of US government bodies that take public records requests, federal to local, and its library of public records laws (federal FOIA, the 50 states and DC), each rule with its citation and the date it was checked against the statute. The directory and the laws are the same for every account and read-only through the API. A contact detail that is being re-checked is left out (null) and named in held until it is confirmed. The rules are information with their sources, not legal advice. With the foia_requests:read scope, a key also reads the account's OWN requests, in every project: where each stands, its deadlines, its correspondence, and its history, the audit trail FOIA Gen keeps of everything that happened to it. Every message that left and every reply that came in is kept with its SHA-256 hash, and the history carries those hashes, so you can archive the trail in your own systems and show later that it was not changed. Requests are written and sent in FOIA Gen, never through the API, and reading one does not mark its replies as read for the people working on it.

List agencies

GET/v1/foia/agenciesfoia:read

The directory of US bodies that take public records requests, with the filters FOIA Gen offers in the hub. Confirmed agencies come first, then federal, state and local ones, then by name. Filters combine; level, type and channel take one value or several separated by commas (level=city,county), and an agency matching any of them is listed. A value that is not one of the listed ones is refused with 400 invalid_parameter, never ignored. Retired agencies are left out.

Parameters

NameTypeDescription
limit
query
integerHow many to return. 1 to 100. Default 25.
cursor
query
stringThe next_cursor from the previous page. Leave it out for the first page.
q
query
stringName, abbreviation, parent department, city or county contains this text, ignoring case (1 to 120 characters).
level
query
array of stringOnly agencies at these levels of government. One or more of federal, state, county, city, township, school, special, court, tribal, separated by commas.
state
query
stringOnly agencies in this state (two-letter code, case ignored), or US for federal agencies. One of US, AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY.
with_federal
query
booleanWith state: true adds the federal agencies, which take requests about every state. Default False.
county
query
stringOnly agencies in this county, without the word County, ignoring case (1 to 80 characters).
city
query
stringOnly agencies in this city or town, ignoring case (1 to 80 characters).
type
query
array of stringOnly these kinds of body. One or more of police, clerk, executive, corrections, education, transport, health, immigration, justice, courts, legislature, elections, environment, defense, finance, housing, labor, utilities, other, separated by commas.
channel
query
array of stringOnly agencies that take requests this way. An agency whose channel is being re-checked shows it as unknown. One or more of email, portal, mail, fax, unknown, separated by commas.
verified
query
booleantrue: only agencies whose contact details are confirmed. Default False.

Response 200

FieldTypeDescription
dataarray of object
data[].idstringThe agency's id: lower-case letters, digits and hyphens, such as us-doj-fbi. It does not change.
data[].namestring
data[].abbreviationstring or null
data[].parentstring or nullThe department or government it belongs to.
data[].levelstring
data[].statestringTwo-letter state code, or US for a federal agency.
data[].countystring or null
data[].citystring or null
data[].typestringThe kind of body.
data[].topicsarray of stringKinds of records it is known to hold, such as bodycam or contracts.
data[].channelstringHow it takes requests. unknown when that is not known, or is being re-checked.
data[].emailstring or nullWhere requests go by email.
data[].portal_urlstring or nullIts request portal.
data[].portal_vendorstring or nullWho runs the portal, when known.
data[].addressstring or nullIts mailing address for requests.
data[].phonestring or null
data[].faxstring or null
data[].websitestring or null
data[].reading_roomstring or nullWhere it publishes records already released. Worth checking before asking.
data[].median_simplenumber or nullIts median days to answer a simple request, as reported to FOIA.gov. Federal agencies only; null when not published.
data[].median_complexnumber or nullThe same for a complex request.
data[].data_yearinteger or nullThe fiscal year those figures are from.
data[].nuancesarray of objectWhat to know before filing with this agency, each with where it was read.
data[].nuances[].textstring
data[].nuances[].sourcestring or null
data[].sourcesarray of objectWhere the details came from.
data[].sources[].labelstring
data[].sources[].urlstring or null
data[].confidencestringverified: confirmed by VeraGen or by a real request. synced: from FOIA.gov. crawled: found on the agency's website, not yet confirmed. unknown: not yet checked.
data[].verified_atstring or null (date-time)
data[].synced_atstring or null (date-time)When it was last read from FOIA.gov.
data[].heldarray of stringContact details being re-checked. Each one named here is null in this answer (channel is unknown) until it is confirmed, rather than risk sending a request to the wrong place.
has_moreboolean
next_cursorstring or null

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 No endpoint at that path.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/agencies?limit=25&state=TX&with_federal=False&verified=False" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/agencies?limit=25&state=TX&with_federal=False&verified=False", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/agencies",
    params={"limit": 25, "state": "TX", "with_federal": false, "verified": false},
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "data": [
    {
      "id": "us-cfpb-cfpb",
      "name": "Consumer Financial Protection Bureau",
      "abbreviation": "CFPB",
      "parent": "Consumer Financial Protection Bureau",
      "level": "federal",
      "state": "US",
      "county": null,
      "city": null,
      "type": "executive",
      "topics": [],
      "channel": "email",
      "email": null,
      "portal_url": "https://www.foia.gov/request/agency-component/833a2183-02d4-4a87-a961-b79ed8d5d8a2/",
      "portal_vendor": "FOIA.gov",
      "address": "CFPB, Attn: Chief FOIA Officer, 445 12th Street, SW, Washington DC 20024",
      "phone": "855-444-3642",
      "fax": null,
      "website": "http://www.consumerfinance.gov/foia/",
      "reading_room": "https://www.consumerfinance.gov/foia-requests/foia-electronic-reading-room/",
      "median_simple": 1,
      "median_complex": 52.5,
      "data_year": 2025,
      "nuances": [],
      "sources": [
        {
          "label": "FOIA.gov component record",
          "url": "https://www.foia.gov/?id=833a2183-02d4-4a87-a961-b79ed8d5d8a2"
        }
      ],
      "confidence": "synced",
      "verified_at": null,
      "synced_at": "2026-10-05T04:02:11.000Z",
      "held": [
        "email"
      ]
    },
    {
      "id": "us-doj-eoir",
      "name": "Executive Office for Immigration Review",
      "abbreviation": "EOIR",
      "parent": "Department of Justice",
      "level": "federal",
      "state": "US",
      "county": null,
      "city": null,
      "type": "justice",
      "topics": [],
      "channel": "portal",
      "email": null,
      "portal_url": "https://www.foia.gov/request/agency-component/bd36709d-06f3-4503-a9d9-8e5f54002ca9/",
      "portal_vendor": "FOIA.gov",
      "address": "Executive Office for Immigration Review, FOIA Service Center, 5107 Leesburg Pike, Suite 2150, Falls Church VA 22041",
      "phone": "703-605-1297",
      "fax": null,
      "website": "https://www.justice.gov/eoir/freedom-information-act-foia",
      "reading_room": "https://www.justice.gov/eoir/foia-library-0",
      "median_simple": 9,
      "median_complex": 7,
      "data_year": 2025,
      "nuances": [],
      "sources": [
        {
          "label": "FOIA.gov component record",
          "url": "https://www.foia.gov/?id=bd36709d-06f3-4503-a9d9-8e5f54002ca9"
        }
      ],
      "confidence": "synced",
      "verified_at": null,
      "synced_at": "2026-10-05T04:02:11.000Z",
      "held": []
    }
  ],
  "has_more": true,
  "next_cursor": "WzEsMCwiRXhlY3V0aXZlIE9mZmljZSBmb3IgSW1taWdyYXRpb24gUmV2aWV3IiwidXMtZG9qLWVvaXIiXQ"
}

Get an agency

GET/v1/foia/agencies/{id}foia:read

One agency, with a summary of the public records law it follows: federal law for a federal agency, its state's law otherwise (jurisdiction says which). Read the whole rule set with Get a jurisdiction's rules.

Parameters

NameTypeDescription
id
path, required
stringThe agency's id, from List agencies.

Response 200

FieldTypeDescription
idstringThe agency's id: lower-case letters, digits and hyphens, such as us-doj-fbi. It does not change.
namestring
abbreviationstring or null
parentstring or nullThe department or government it belongs to.
levelstring
statestringTwo-letter state code, or US for a federal agency.
countystring or null
citystring or null
typestringThe kind of body.
topicsarray of stringKinds of records it is known to hold, such as bodycam or contracts.
channelstringHow it takes requests. unknown when that is not known, or is being re-checked.
emailstring or nullWhere requests go by email.
portal_urlstring or nullIts request portal.
portal_vendorstring or nullWho runs the portal, when known.
addressstring or nullIts mailing address for requests.
phonestring or null
faxstring or null
websitestring or null
reading_roomstring or nullWhere it publishes records already released. Worth checking before asking.
median_simplenumber or nullIts median days to answer a simple request, as reported to FOIA.gov. Federal agencies only; null when not published.
median_complexnumber or nullThe same for a complex request.
data_yearinteger or nullThe fiscal year those figures are from.
nuancesarray of objectWhat to know before filing with this agency, each with where it was read.
nuances[].textstring
nuances[].sourcestring or null
sourcesarray of objectWhere the details came from.
sources[].labelstring
sources[].urlstring or null
confidencestringverified: confirmed by VeraGen or by a real request. synced: from FOIA.gov. crawled: found on the agency's website, not yet confirmed. unknown: not yet checked.
verified_atstring or null (date-time)
synced_atstring or null (date-time)When it was last read from FOIA.gov.
heldarray of stringContact details being re-checked. Each one named here is null in this answer (channel is unknown) until it is confirmed, rather than risk sending a request to the wrong place.
jurisdictionstringWhose public records law the agency follows: US, or its state.
rulesobject or nullThat law, in short; null if the library has no rule set for it.
rules.codestringUS for federal law, or the state's two-letter code.
rules.namestring
rules.lawstringThe name of the law.
rules.citestring or null
rules.statute_urlstring or nullThe statute's text.
rules.deadlinesarray of objectWhat the agency must do by when. Business and working days skip weekends and that jurisdiction's holidays.
rules.deadlines[].kindstringWhat the deadline is for, such as acknowledge, determine, produce, extension or deemed_denial.
rules.deadlines[].daysnumber or nullHow many days; null when the law says "promptly" or sets no number.
rules.deadlines[].unitstringbusiness, working, calendar or none.
rules.deadlines[].textstring
rules.deadlines[].citestring or null
rules.deadlines[].sourcestring or null
rules.statusstringverified: checked against the statute on checked_on. needs_checking: not yet checked; read the statute before relying on it.
rules.checked_onstring or null (date)When it was last checked against the statute.
rules.versionintegerGoes up each time the rule set changes.

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 No agency with that id.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/agencies/{id}" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/agencies/{id}", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/agencies/{id}",
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "id": "us-doj-eoir",
  "name": "Executive Office for Immigration Review",
  "abbreviation": "EOIR",
  "parent": "Department of Justice",
  "level": "federal",
  "state": "US",
  "county": null,
  "city": null,
  "type": "justice",
  "topics": [],
  "channel": "portal",
  "email": null,
  "portal_url": "https://www.foia.gov/request/agency-component/bd36709d-06f3-4503-a9d9-8e5f54002ca9/",
  "portal_vendor": "FOIA.gov",
  "address": "Executive Office for Immigration Review, FOIA Service Center, 5107 Leesburg Pike, Suite 2150, Falls Church VA 22041",
  "phone": "703-605-1297",
  "fax": null,
  "website": "https://www.justice.gov/eoir/freedom-information-act-foia",
  "reading_room": "https://www.justice.gov/eoir/foia-library-0",
  "median_simple": 9,
  "median_complex": 7,
  "data_year": 2025,
  "nuances": [],
  "sources": [
    {
      "label": "FOIA.gov component record",
      "url": "https://www.foia.gov/?id=bd36709d-06f3-4503-a9d9-8e5f54002ca9"
    }
  ],
  "confidence": "synced",
  "verified_at": null,
  "synced_at": "2026-10-05T04:02:11.000Z",
  "held": [],
  "jurisdiction": "US",
  "rules": {
    "code": "US",
    "name": "United States (federal)",
    "law": "Freedom of Information Act",
    "cite": "5 U.S.C. § 552",
    "statute_url": "https://www.law.cornell.edu/uscode/text/5/552",
    "deadlines": [
      {
        "kind": "determine",
        "days": 20,
        "unit": "business",
        "text": "The agency must decide whether it will comply within 20 working days (not counting weekends and federal holidays) and tell you its decision, your right to help from its FOIA Public Liaison, and, if adverse, your right to appeal and to dispute-resolution help from OGIS. It may pause the clock once to ask you for reasonably needed information, and again as needed to clarify fees.",
        "cite": "5 U.S.C. § 552(a)(6)(A)(i)",
        "source": "https://www.law.cornell.edu/uscode/text/5/552"
      },
      {
        "kind": "extension",
        "days": 10,
        "unit": "working",
        "text": "In unusual circumstances (records in field offices, a voluminous request, or consultation with another agency), the agency may extend by up to 10 working days with written notice. If it needs longer, it must offer you a chance to narrow the request or agree on another timeline.",
        "cite": "5 U.S.C. § 552(a)(6)(B)",
        "source": "https://www.law.cornell.edu/uscode/text/5/552"
      }
    ],
    "status": "verified",
    "checked_on": "2026-10-05",
    "version": 1
  }
}

Get a jurisdiction's rules

GET/v1/foia/rules/{code}foia:read

A jurisdiction's public records law as FOIA Gen applies it: who may ask, whether a reason, writing or a form is required, the deadlines, fees, how to appeal, and notes. Every rule carries its citation and the page it was read from. status says whether the set has been checked against the statute, and checked_on when. This is information with its sources, not legal advice.

Parameters

NameTypeDescription
code
path, required
stringUS for federal law, or a state's two-letter code (case ignored). One of US, AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY.

Response 200

FieldTypeDescription
codestringUS for federal law, or the state's two-letter code.
namestring
lawstringThe name of the law.
citestring or null
statute_urlstring or nullThe statute's text.
deadlinesarray of objectWhat the agency must do by when. Business and working days skip weekends and that jurisdiction's holidays.
deadlines[].kindstringWhat the deadline is for, such as acknowledge, determine, produce, extension or deemed_denial.
deadlines[].daysnumber or nullHow many days; null when the law says "promptly" or sets no number.
deadlines[].unitstringbusiness, working, calendar or none.
deadlines[].textstring
deadlines[].citestring or null
deadlines[].sourcestring or null
statusstringverified: checked against the statute on checked_on. needs_checking: not yet checked; read the statute before relying on it.
checked_onstring or null (date)When it was last checked against the statute.
versionintegerGoes up each time the rule set changes.
who_may_requestobject or nullWho may ask. A few states give the right only to their own residents or citizens.
who_may_request.textstringThe rule in plain English.
who_may_request.citestring or nullThe citation in the statute.
who_may_request.sourcestring or nullThe page it was read from.
who_may_request.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
who_may_request.rulestring or nullFor who may request: anyone, or a limit such as residents.
purpose_requiredobject or nullWhether you must say why you want the records.
purpose_required.textstringThe rule in plain English.
purpose_required.citestring or nullThe citation in the statute.
purpose_required.sourcestring or nullThe page it was read from.
purpose_required.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
purpose_required.rulestring or nullFor who may request: anyone, or a limit such as residents.
writing_requiredobject or nullWhether the request must be in writing.
writing_required.textstringThe rule in plain English.
writing_required.citestring or nullThe citation in the statute.
writing_required.sourcestring or nullThe page it was read from.
writing_required.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
writing_required.rulestring or nullFor who may request: anyone, or a limit such as residents.
form_requiredobject or nullWhether a particular form must be used.
form_required.textstringThe rule in plain English.
form_required.citestring or nullThe citation in the statute.
form_required.sourcestring or nullThe page it was read from.
form_required.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
form_required.rulestring or nullFor who may request: anyone, or a limit such as residents.
feesobject or nullWhat may be charged.
fees.textstringThe rule in plain English.
fees.citestring or nullThe citation in the statute.
fees.sourcestring or nullThe page it was read from.
fees.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
fees.rulestring or nullFor who may request: anyone, or a limit such as residents.
appealobject or nullWhat to do if the answer is no.
appeal.textstringThe rule in plain English.
appeal.citestring or nullThe citation in the statute.
appeal.sourcestring or nullThe page it was read from.
appeal.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
appeal.rulestring or nullFor who may request: anyone, or a limit such as residents.
appeal.routestring or nullWhere an appeal or complaint goes.
appeal.deadline_daysnumber or nullHow long you have to appeal, in unit; null when the law sets no deadline.
appeal.unitstring or nullbusiness, working, calendar or none.
commercial_certificationobject or nullWhether you must certify the records are not for commercial use.
commercial_certification.textstringThe rule in plain English.
commercial_certification.citestring or nullThe citation in the statute.
commercial_certification.sourcestring or nullThe page it was read from.
commercial_certification.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
commercial_certification.rulestring or nullFor who may request: anyone, or a limit such as residents.
courts_coveredobject or nullWhether the courts' records are covered.
courts_covered.textstringThe rule in plain English.
courts_covered.citestring or nullThe citation in the statute.
courts_covered.sourcestring or nullThe page it was read from.
courts_covered.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
courts_covered.rulestring or nullFor who may request: anyone, or a limit such as residents.
legislature_coveredobject or nullWhether the legislature's records are covered.
legislature_covered.textstringThe rule in plain English.
legislature_covered.citestring or nullThe citation in the statute.
legislature_covered.sourcestring or nullThe page it was read from.
legislature_covered.valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
legislature_covered.rulestring or nullFor who may request: anyone, or a limit such as residents.
notesarray of objectOther things worth knowing.
notes[].textstringThe rule in plain English.
notes[].citestring or nullThe citation in the statute.
notes[].sourcestring or nullThe page it was read from.
notes[].valueboolean or nullFor a yes-or-no rule (is a reason, writing or a form required; are the courts or the legislature covered): the answer. null when it does not apply or is not settled.
notes[].rulestring or nullFor who may request: anyone, or a limit such as residents.

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 No rules for that code.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/rules/{code}" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/rules/{code}", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/rules/{code}",
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "code": "TX",
  "name": "Texas",
  "law": "Texas Public Information Act",
  "cite": "Tex. Gov't Code ch. 552",
  "statute_url": "https://statutes.capitol.texas.gov/Docs/GV/htm/GV.552.htm",
  "who_may_request": {
    "text": "Any person may ask. The agency may check identification but may not ask why you want the records. An agency does not have to accept requests from people in prison or jail (or their non-attorney agents), though it may release records about that person.",
    "cite": "Tex. Gov't Code §§ 552.221(a), 552.222(a)-(b), 552.028",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": null,
    "rule": "anyone"
  },
  "purpose_required": {
    "text": "You do not have to give a reason. The agency may ask you to clarify or narrow a large request, but it may not ask what you will use the records for.",
    "cite": "Tex. Gov't Code § 552.222(b)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": false,
    "rule": null
  },
  "writing_required": {
    "text": "Put the request in writing. The deadlines and the attorney general ruling process apply to written requests, delivered by mail, email, hand delivery, or another method the agency has approved (such as fax or its website). If the agency has posted one designated mailing address and one email address, it only has to answer requests sent there, hand-delivered, or sent by a method it has approved.",
    "cite": "Tex. Gov't Code §§ 552.234, 552.301(a)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": true,
    "rule": null
  },
  "form_required": {
    "text": "No particular form is required. Send the request to the agency's officer for public information, at its designated address if it has one.",
    "cite": "Tex. Gov't Code § 552.234",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": false,
    "rule": null
  },
  "deadlines": [
    {
      "kind": "produce",
      "days": null,
      "unit": "none",
      "text": "The agency must produce public information promptly, meaning as soon as possible within a reasonable time and without delay.",
      "cite": "Tex. Gov't Code § 552.221(a)",
      "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm"
    },
    {
      "kind": "extension",
      "days": 10,
      "unit": "business",
      "text": "If the agency cannot produce the records within 10 business days, it must tell you so in writing and set a date and hour within a reasonable time when they will be available.",
      "cite": "Tex. Gov't Code § 552.221(d)",
      "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm"
    }
  ],
  "fees": {
    "text": "Charges may not exceed the actual cost and follow rules set by the Attorney General. For 50 or fewer pages of paper records, only a per-page charge is allowed, unless the pages are in two or more separate buildings or remote storage. If the charges will be over $40, the agency must first send you a written itemized estimate; you must answer in writing within 10 business days (accept, narrow the request, or say you have complained to the Attorney General) or the request is treated as withdrawn. The agency must waive or reduce charges when release primarily benefits the general public. Agencies may set monthly and yearly limits on free staff time per requester (at least 15 hours a month and 36 hours a year).",
    "cite": "Tex. Gov't Code §§ 552.261(a), 552.262(a), 552.2615, 552.267(a), 552.275(a)-(b)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": null,
    "rule": null
  },
  "appeal": {
    "text": "Texas has no internal appeal. If the agency does not comply, you can file a signed written complaint with the district or county attorney where the agency is located (for state agencies, the Travis County district attorney), who must decide within 30 days whether to act; complain to the Attorney General about overcharges; or sue for a writ of mandamus in district court in the county of the agency's main office. No filing deadline for these is set in the Act.",
    "cite": "Tex. Gov't Code §§ 552.3215(e)-(i), 552.269(a), 552.321",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": null,
    "rule": null,
    "route": "No administrative appeal. Complaint to the county or district attorney (or Attorney General); overcharge complaint to the Attorney General; mandamus suit in district court",
    "deadline_days": null,
    "unit": "none"
  },
  "commercial_certification": {
    "text": "The Act has no general commercial-use certification. The agency may not ask how you will use the records.",
    "cite": "Tex. Gov't Code § 552.222(a)-(b)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": false,
    "rule": null
  },
  "courts_covered": {
    "text": "The judiciary is not a governmental body under the Act, so court records are not requested under it.",
    "cite": "Tex. Gov't Code § 552.003(1)(B)(i)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": false,
    "rule": null
  },
  "legislature_covered": {
    "text": "Boards, committees, agencies and offices within or created by the legislative branch are governmental bodies under the Act. Some legislative records may still fall under exceptions.",
    "cite": "Tex. Gov't Code § 552.003(1)(A)(i)",
    "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
    "value": true,
    "rule": null
  },
  "notes": [
    {
      "text": "Every governmental body must report its designated request mailing address and email address to the Attorney General by October 1 each year, and the Attorney General publishes them in a public online database. Use that address.",
      "cite": "Tex. Gov't Code § 552.234(c)-(f)",
      "source": "https://tcss.legis.texas.gov/resources/GV/htm/GV.552.htm",
      "value": null,
      "rule": null
    }
  ],
  "status": "verified",
  "checked_on": "2026-10-05",
  "version": 1
}

List requests

GET/v1/foia/requestsfoia_requests:read

The account's FOIA Gen requests in every project, most recently changed first. Deleted requests are left out. Filters combine: view picks the same groups as the tabs in FOIA Gen (needs_you: a draft, a fee letter or question to answer, or a denial whose appeal window is open; waiting: with the agency; overdue: a deadline has passed; closed), status one exact status, project_id one project, and updated_since only requests changed at or after a time, for keeping another system in step. A value that is not one of the listed ones is refused with 400 invalid_parameter, never ignored.

Parameters

NameTypeDescription
limit
query
integerHow many to return. 1 to 100. Default 25.
cursor
query
stringThe next_cursor from the previous page. Leave it out for the first page.
project_id
query
string (uuid)Only requests in this project.
status
query
stringOnly requests with exactly this status. One of draft, sending, sent, acknowledged, in_progress, fee_needs_you, needs_reply, partly_released, released, denied, no_records, appealed, closed, withdrawn.
view
query
stringOnly requests in this group, as FOIA Gen's tabs show them. One of needs_you, waiting, closed, overdue, all. Default all.
updated_since
query
stringOnly requests changed at or after this time: a date (YYYY-MM-DD, UTC) or an ISO-8601 date and time with a zone.

Response 200

FieldTypeDescription
dataarray of object
data[].idstring (uuid)
data[].project_idstring (uuid)The project the request is in.
data[].titlestring
data[].statusstringWhere the request stands, as FOIA Gen shows it. sending that has lasted more than a few minutes is flagged by send_unconfirmed.
data[].send_unconfirmedbooleantrue when a send started but could not be confirmed: check with the agency before sending again. A person resolves it in FOIA Gen.
data[].agencyobject or nullThe agency it is addressed to, as it was when the request was written; null before one is chosen.
data[].agency.idstringThe agency's id in the directory (Get an agency).
data[].agency.namestring
data[].agency.levelstring or null
data[].agency.statestring or nullTwo-letter state code, or US.
data[].jurisdictionstring or nullWhose law applies: US, or the state's two-letter code.
data[].channelstring or nullHow it goes to the agency.
data[].tracking_numberstring or nullThe agency's own reference for it, once known.
data[].next_deadlineobject or nullThe soonest open (or missed) deadline, or null.
data[].next_deadline.kindstring
data[].next_deadline.due_onstring or null (date)
data[].sent_atstring or null (date-time)
data[].created_atstring (date-time)
data[].updated_atstring (date-time)When anything about it last changed. Lists are ordered by it, newest first.
has_moreboolean
next_cursorstring or null

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 Not found in this account.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/requests?limit=25&view=all" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/requests?limit=25&view=all", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/requests",
    params={"limit": 25, "view": "all"},
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "data": [
    {
      "id": "7e3a9c41-2b6d-4f80-9a15-c3d4e5f60718",
      "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "title": "Use-of-force reports, 2024 to 2025",
      "status": "acknowledged",
      "send_unconfirmed": false,
      "agency": {
        "id": "tx-austin-police-3f9a1c",
        "name": "Austin Police Department",
        "level": "city",
        "state": "TX"
      },
      "jurisdiction": "TX",
      "channel": "email",
      "tracking_number": "R012345-100526",
      "next_deadline": {
        "kind": "decide",
        "due_on": "2026-10-19"
      },
      "sent_at": "2026-10-05T14:02:11.482Z",
      "created_at": "2026-10-05T13:40:02.115Z",
      "updated_at": "2026-10-06T09:15:44.903Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Get a request

GET/v1/foia/requests/{id}foia_requests:read

One request: the letter, the agency it went to, its deadlines with the rule each comes from, and its correspondence, oldest first. Each message carries its text as plain text (never the agency's HTML), its attachments' names, sizes and hashes, and the SHA-256 of the exact message stored. The latest 50 messages are included; messages_truncated says when there are more, and the history has every one.

Parameters

NameTypeDescription
id
path, required
string (uuid)The request's id, from List requests.

Response 200

FieldTypeDescription
idstring (uuid)
project_idstring (uuid)The project the request is in.
titlestring
statusstringWhere the request stands, as FOIA Gen shows it. sending that has lasted more than a few minutes is flagged by send_unconfirmed.
send_unconfirmedbooleantrue when a send started but could not be confirmed: check with the agency before sending again. A person resolves it in FOIA Gen.
agencyobject or nullThe agency it is addressed to, with the contact details it was written for; null before one is chosen.
agency.idstring
agency.namestring
agency.levelstring or null
agency.statestring or null
agency.parentstring or null
agency.emailstring or null
agency.portal_urlstring or null
agency.addressstring or null
jurisdictionstring or nullWhose law applies: US, or the state's two-letter code.
channelstring or nullHow it goes to the agency.
tracking_numberstring or nullThe agency's own reference for it, once known.
sent_atstring or null (date-time)
created_atstring (date-time)
updated_atstring (date-time)When anything about it last changed. Lists are ordered by it, newest first.
descriptionstringThe records asked for, in the requester's words.
subjectstring
bodystringThe letter, as plain text.
certified_nostring or nullThe certified-mail number, for a request sent by post.
submitted_atstring or null (date-time)When it was recorded as filed on the agency's portal.
mailed_atstring or null (date-time)When it was recorded as posted.
acknowledged_atstring or null (date-time)
closed_atstring or null (date-time)
deadlinesarray of objectIts deadlines, soonest first, each with the rule it comes from.
deadlines[].idstring (uuid)
deadlines[].kindstringWhose move it is by then: the agency's (acknowledge, decide, extended) or yours (fee_reply, clarify_reply, still_interested, appeal, court).
deadlines[].due_onstring or null (date)null while it is paused or has no fixed date.
deadlines[].basisstringHow the date was worked out.
deadlines[].citestring or nullThe statute it comes from.
deadlines[].sourcestring or null
deadlines[].statusstring
messagesarray of objectThe correspondence, oldest first: the latest 50 messages.
messages[].idstring (uuid)
messages[].directionstringout: sent from FOIA Gen. in: a reply that came in.
messages[].channelstring
messages[].fromstring or null
messages[].tostring or null
messages[].subjectstring
messages[].textstringThe message as plain text. An agency's HTML email is turned into text; HTML is never returned.
messages[].statusstringsent or failed for a message out; received for a reply.
messages[].sha256string or nullThe SHA-256 of the exact message as stored.
messages[].attachmentsarray of object
messages[].attachments[].namestring
messages[].attachments[].content_typestring or null
messages[].attachments[].sizeinteger or nullIn bytes.
messages[].attachments[].sha256string or nullThe SHA-256 of the file as kept.
messages[].attachments[].storedbooleanfalse when the file could not be kept (too large, or sent inline).
messages[].received_atstring or null (date-time)
messages[].created_atstring (date-time)
messages_truncatedbooleantrue when there are more than 50 messages and the earliest are not in messages. The history (List a request's history) has every one.

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 Not found in this account.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/requests/{id}" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/requests/{id}", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/requests/{id}",
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "id": "7e3a9c41-2b6d-4f80-9a15-c3d4e5f60718",
  "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "title": "Use-of-force reports, 2024 to 2025",
  "status": "acknowledged",
  "send_unconfirmed": false,
  "agency": {
    "id": "tx-austin-police-3f9a1c",
    "name": "Austin Police Department",
    "level": "city",
    "state": "TX",
    "parent": "City of Austin",
    "email": "apdrecords@austin.example",
    "portal_url": null,
    "address": null
  },
  "jurisdiction": "TX",
  "channel": "email",
  "tracking_number": "R012345-100526",
  "sent_at": "2026-10-05T14:02:11.482Z",
  "created_at": "2026-10-05T13:40:02.115Z",
  "updated_at": "2026-10-06T09:15:44.903Z",
  "description": "Every use-of-force report filed by officers from 1 January 2024 to 31 December 2025, with the supervisor review attached to each.",
  "subject": "Public Information Act request: use-of-force reports, 2024 to 2025",
  "body": "Dear Public Information Officer,\n\nUnder the Texas Public Information Act, Tex. Gov't Code ch. 552, I request copies of every use-of-force report filed from 1 January 2024 to 31 December 2025...\n\nThank you,\nJordan Reyes",
  "certified_no": null,
  "submitted_at": null,
  "mailed_at": null,
  "acknowledged_at": "2026-10-06T09:15:44.903Z",
  "closed_at": null,
  "deadlines": [
    {
      "id": "b2c3d4e5-f607-4819-8a2b-3c4d5e6f7081",
      "kind": "decide",
      "due_on": "2026-10-19",
      "basis": "10 business days from receipt to produce the records or say when they will be ready.",
      "cite": "Tex. Gov't Code § 552.221(d)",
      "source": "https://statutes.capitol.texas.gov/Docs/GV/htm/GV.552.htm",
      "status": "open"
    }
  ],
  "messages": [
    {
      "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
      "direction": "out",
      "channel": "email",
      "from": "r-k3v9q2m7x1c8w4z6p0t5b2n8@requests.veragen.ai",
      "to": "apdrecords@austin.example",
      "subject": "Public Information Act request: use-of-force reports, 2024 to 2025",
      "text": "Dear Public Information Officer,\n\nUnder the Texas Public Information Act...",
      "status": "sent",
      "sha256": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d",
      "attachments": [],
      "received_at": null,
      "created_at": "2026-10-05T14:02:11.482Z"
    },
    {
      "id": "d2e3f4a5-b6c7-4d8e-9fa0-1b2c3d4e5f60",
      "direction": "in",
      "channel": "email",
      "from": "apdrecords@austin.example",
      "to": "r-k3v9q2m7x1c8w4z6p0t5b2n8@requests.veragen.ai",
      "subject": "RE: Public Information Act request [R012345-100526]",
      "text": "Your request has been received and assigned reference R012345-100526.",
      "status": "received",
      "sha256": "1a3c5e7f9b2d4f6a8c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f2a4c6e8b0d1f3a",
      "attachments": [
        {
          "name": "acknowledgement.pdf",
          "content_type": "application/pdf",
          "size": 48213,
          "sha256": "5d7f9a1c3e5b7d9f0a2c4e6b8d0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f",
          "stored": true
        }
      ],
      "received_at": "2026-10-06T09:15:40.000Z",
      "created_at": "2026-10-06T09:15:40.000Z"
    }
  ],
  "messages_truncated": false
}

List a request's history

GET/v1/foia/requests/{id}/eventsfoia_requests:read

Everything that happened to a request, OLDEST first: created, drafted, sent, replies in, status changes, deadlines, documents, notes. The history is append-only: nothing in it is ever changed or removed, so a page you have read stays true. When an event kept a copy of what was sent or received (stored), sha256 is the SHA-256 of that exact copy. Because the history only grows, an archive can read it to the end once and, on later reads, keep only the events whose id it does not have yet.

Parameters

NameTypeDescription
id
path, required
string (uuid)The request's id, from List requests.
limit
query
integerHow many to return. 1 to 100. Default 25.
cursor
query
stringThe next_cursor from the previous page. Leave it out for the first page.

Response 200

FieldTypeDescription
dataarray of object
data[].idstring (uuid)
data[].atstring (date-time)
data[].actorstringWho did it: a member of the account, the agency (a reply from its own address), an unconfirmed sender (a message from any other address, filed but changing nothing; detail.from has the address), or FOIA Gen itself (deadlines, reminders).
data[].actor_emailstring or nullThe member's sign-in email; null for the agency, FOIA Gen, or someone no longer in the account.
data[].kindstring
data[].summarystringOne line, as the history in FOIA Gen shows it.
data[].detailobjectFacts particular to the kind, such as to and message_id for a send or from and to for a status change. The keys vary by kind and more may be added.
data[].sha256string or nullFor a stored event: the SHA-256 of the exact copy kept.
data[].storedbooleantrue when a copy of what was sent or received was kept with this event.
has_moreboolean
next_cursorstring or null

Errors

  • 400 The request is not valid.
  • 401 No valid API key.
  • 403 The key may not do this.
  • 404 Not found in this account.
  • 429 Too many requests.
  • 500 Something went wrong on our side.

The codes are listed under Errors.

cURL
curl "https://api.veragen.ai/v1/foia/requests/{id}/events?limit=25" \
  -H "Authorization: Bearer $VERAGEN_API_KEY"
JavaScript
const res = await fetch("https://api.veragen.ai/v1/foia/requests/{id}/events?limit=25", {
  headers: { Authorization: `Bearer ${process.env.VERAGEN_API_KEY}` },
});
const data = await res.json();
Python
import os, requests

res = requests.get(
    "https://api.veragen.ai/v1/foia/requests/{id}/events",
    params={"limit": 25},
    headers={"Authorization": f"Bearer {os.environ['VERAGEN_API_KEY']}"},
)
data = res.json()
Response 200
{
  "data": [
    {
      "id": "e1f2a3b4-c5d6-4e7f-8091-a2b3c4d5e6f7",
      "at": "2026-10-05T13:40:02.115Z",
      "actor": "member",
      "actor_email": "jordan@newsroom.example",
      "kind": "created",
      "summary": "Started this request to Austin Police Department.",
      "detail": {
        "agency_id": "tx-austin-police-3f9a1c",
        "template_id": null
      },
      "sha256": null,
      "stored": false
    },
    {
      "id": "f2a3b4c5-d6e7-4f80-91a2-b3c4d5e6f708",
      "at": "2026-10-05T14:02:11.482Z",
      "actor": "member",
      "actor_email": "jordan@newsroom.example",
      "kind": "sent",
      "summary": "Sent by email to apdrecords@austin.example.",
      "detail": {
        "to": "apdrecords@austin.example",
        "channel": "email",
        "message_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
      },
      "sha256": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d",
      "stored": true
    },
    {
      "id": "a3b4c5d6-e7f8-4091-a2b3-c4d5e6f70819",
      "at": "2026-10-06T09:15:40.311Z",
      "actor": "agency",
      "actor_email": null,
      "kind": "message_in",
      "summary": "Reply from apdrecords@austin.example.",
      "detail": {
        "from": "apdrecords@austin.example"
      },
      "sha256": "1a3c5e7f9b2d4f6a8c0e1b3d5f7a9c2e4b6d8f0a1c3e5b7d9f2a4c6e8b0d1f3a",
      "stored": true
    }
  ],
  "has_more": false,
  "next_cursor": null
}