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.
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.
| Type | Description |
|---|---|
| 01 | Dealer in Firearms Other Than Destructive Devices (includes Gunsmith) |
| 02 | Pawnbroker in Firearms Other Than Destructive Devices |
| 03 | Collector of Curios and Relics |
| 06 | Manufacturer of Ammunition |
| 07 | Manufacturer of Firearms Other Than Destructive Devices |
| 08 | Importer of Firearms Other Than Destructive Devices |
| 09 | Dealer in Destructive Devices |
| 10 | Manufacturer of Destructive Devices |
| 11 | Importer 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
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
// 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
// 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
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.
Party screening through AES filing
Full endpoint documentation