› compliance_grid.aiCOMPLIANCEGRIDGOV · COMPLIANCE · INTELLIGENCE
Back to Docs

Firearms License Verification

Verify ATF Federal Firearms Licenses (FFL), validate license types and expiration, and screen holders against federal watchlists — all through the ComplianceGrid API.

Reading time: 6 minLast updated: Oct 2026

Use Cases

Marketplace Verification

Verify FFL status before allowing firearms-related listings or transactions on your platform.

Distributor Onboarding

Validate dealer FFLs before establishing wholesale accounts.

Transfer Compliance

Ensure the receiving FFL is valid and authorized for the specific firearm type before shipping.

Periodic Monitoring

Monitor FFL expiration dates and re-verify quarterly to catch revocations.

FFL License Types

ATF issues several types of Federal Firearms Licenses. The license type determines what activities the holder is authorized to perform.

TypeDescription
01Dealer in Firearms Other Than Destructive Devices (includes Gunsmith)
02Pawnbroker in Firearms Other Than Destructive Devices
03Collector of Curios and Relics
06Manufacturer of Ammunition
07Manufacturer of Firearms Other Than Destructive Devices
08Importer of Firearms Other Than Destructive Devices
09Dealer in Destructive Devices
10Manufacturer of Destructive Devices
11Importer of Destructive Devices

Verification Workflow

Step 1: FFL License Search

Search ATF's published Federal Firearms Licensee listing by name, state, city or license type. A licensee that is not on the listing is not currently licensed.

Step 2: License Validation

Verify the specific FFL number against the listing, read its license type (01–11) and expiration cycle from the number, and confirm the type covers the intended activity (dealing, manufacturing, importing).

Step 3: OFAC / Watchlist Screening

Screen the FFL holder and associated individuals against OFAC SDN, BIS Entity List, and other federal watchlists.

Step 4: Geographic Compliance

Verify the FFL's premise address matches the transaction location. ATF requires all firearms transactions to occur at the licensed premises.

Step 1: Search FFL Database

1-ffl-search.ts
const API = "https://api.compliancegrid.ai";
const headers = { "x-api-key": process.env.CG_API_KEY! };
const get = (path: string) => fetch(API + path, { headers }).then((r) => r.json());

// Search FFLs by state, city and license type (also: name, zip)
const ffls = await get("/v1/firearms/ffl/search?state=TX&city=Dallas&type=01&limit=10");

console.log("Found " + ffls.totalResults + " dealers in Dallas, TX");
for (const ffl of ffls.results) {
  console.log("  " + (ffl.businessName || ffl.licenseName));   // businessName is often empty: licenseName is the licensee
  console.log("    License: " + ffl.fflNumber);
  console.log("    Type: " + ffl.licenseType + " - " + ffl.licenseTypeName);
  console.log("    Premises: " + ffl.premiseStreet + ", " + ffl.premiseCity + " " + ffl.premiseState + " " + ffl.premiseZip);
}

// Search by business or licensee name (matches either)
const byName = await get("/v1/firearms/ffl/search?name=Champion&state=TX");
console.log(byName.totalResults + " licensees match");

Step 2: Validate Specific FFL

2-ffl-validate.ts
// Verify a specific FFL number against the ATF listing
const fflNumber = ffls.results[0].fflNumber;   // for example 5-75-113-01-7A-18504
const verification = await get("/v1/firearms/ffl/verify/" + fflNumber);

// valid is true only when the number is well formed AND on the listing; record is the licensee
console.log("On the ATF listing:", verification.valid);
if (verification.valid) {
  const ffl = verification.record;
  console.log("Licensee:", ffl.businessName || ffl.licenseName);
  console.log("Type:", ffl.licenseType, ffl.licenseTypeName);
  console.log("Region:", verification.parsed.regionName);
  console.log("Expiration cycle:", verification.parsed.expirationCycle, "month:", verification.parsed.expirationMonth);

  // The listing carries no status or expiry date, only licensees that are currently listed
  const isDealer = ["01", "02"].includes(ffl.licenseType);
  console.log(isDealer ? "License type allows retail dealing" : "License type does not allow retail dealing");
} else {
  console.error("Not on the ATF listing: do not treat this as a licensed dealer");
}

// Parse a number without looking it up (format check only)
const parsed = await get("/v1/firearms/ffl/parse/" + fflNumber);
console.log(parsed.valid, parsed.regionName, parsed.licenseTypeName);

Step 3: Watchlist Screening

3-screening.ts
// Screen the FFL holder against the U.S. restricted-party lists
const holder = verification.record.businessName || verification.record.licenseName;
const screening = await fetch(API + "/v1/compliance/restricted-party-screening", {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ parties: [{ name: holder, country: "US" }] }),
}).then((r) => r.json());

// overallResult is CLEAR or POTENTIAL_MATCH; a potential match needs human review
if (screening.data.overallResult === "POTENTIAL_MATCH") {
  console.warn("Possible list match: review before proceeding");
  for (const match of screening.data.results[0].matches.slice(0, 3)) {
    console.log("  " + match.listName + ": " + match.matchedName + " (score " + match.matchScore + ")");
  }
} else {
  console.log("Watchlist screening: no match");
}

Complete Verification Function

verify-ffl.ts
async function verifyFFL(fflNumber: string) {
  // Step 1: is the number on the ATF listing?
  const v = await get("/v1/firearms/ffl/verify/" + fflNumber);
  if (!v.valid) {
    return { valid: false, reason: "Not on the ATF listing (or not a valid FFL number)" };
  }
  const ffl = v.record;

  // Step 2: screen the licensee
  const holder = ffl.businessName || ffl.licenseName;
  const screening = await fetch(API + "/v1/compliance/restricted-party-screening", {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify({ parties: [{ name: holder, country: "US" }] }),
  }).then((r) => r.json());

  if (screening.data.overallResult === "POTENTIAL_MATCH") {
    return { valid: false, reason: "Possible watchlist match: review required", ffl, screeningResults: screening.data };
  }

  return { valid: true, ffl, screeningResults: screening.data, verifiedAt: new Date().toISOString() };
}

// Usage
const result = await verifyFFL(fflNumber);
if (result.valid) {
  console.log("FFL verified");
} else {
  console.error("FFL not accepted:", result.reason);
}

Regulatory Notes

  • • ATF regulations require all interstate firearm transfers to go through an FFL holder.
  • • FFL verification should be performed before every transaction, not just at onboarding.
  • • FFL data is ATF's public FFL listing as last loaded (about 85,000 licensees). It lists current licensees only: it has no status or expiry date, and a revocation after the last load is not reflected. For a time-critical decision check ATF eZ Check.
  • • This API does not replace the requirement to maintain a bound book (Form 4473) or conduct NICS checks.
  • • Always consult ATF regulations and your compliance team for specific requirements.
Export Compliance Guide

Party screening through AES filing

Firearms API Reference

Full endpoint documentation