Address Verification Guide
Last updated: 2026-05-13
This guide covers address verification providers, configuration, and how the verification system works.
Overview
Address verification standardizes and validates addresses against postal service databases. The package supports multiple verification providers with automatic selection based on country.
Verification Providers
USPS (United States Postal Service)
Best for: US addresses only Cost: FREE (rate limited to 60 requests/hour by default) Accuracy: Excellent for US addresses
Setup
- Register at USPS Developer Portal
- Get Consumer Key and Secret
- Add to
.env:
USPS_CONSUMER_KEY=your_consumer_key
USPS_CONSUMER_SECRET=your_consumer_secret
ADDRESS_VERIFICATION_PROVIDER=uspsWhat USPS Does
- ✅ Standardizes street abbreviations (Ave → AVE, Street → ST)
- ✅ Adds ZIP+4 codes
- ✅ Validates deliverability (DPV confirmation)
- ✅ Removes special characters (O'Brien → OBRIEN)
- ✅ Uppercases addresses for postal standards (normalized to Title Case before display and storage)
Rate Limiting
Free tier: 60 requests/hour. The package includes rate limiting:
USPS_RATE_LIMIT_ENABLED=true
USPS_RATE_LIMIT=60
USPS_LIMIT_BEHAVIOR=queue # queue, fail, or fallbackBehaviors:
queue: Queues requests when limit reached (recommended)fail: Returns error when limit reachedfallback: Falls back to Google verification
⚠️ Queue worker required for
queuebehavior: IfUSPS_LIMIT_BEHAVIOR=queue, a Laravel queue worker must be running or queued requests will never process. Runphp artisan queue:worklocally, or configure a process supervisor in production. See FAQ — Bulk operations run but nothing happens.
Smarty International Street API
Best for: Global coverage including countries Google does not support Cost: ~$0.006 per request Coverage: 240+ countries (US via US Street API, all others via International Street API)
Setup
- Register at smarty.com
- Get Auth ID and Auth Token from your account
- Add to
.env:
SMARTY_AUTH_ID=your_auth_id
SMARTY_AUTH_TOKEN=your_auth_token
ADDRESS_VERIFICATION_PROVIDER=autoTwo licenses are required for full coverage:
us-core-cloud— US Street API (default for US addresses)international-cloud— International Street API (default; check your Smarty account for the exact value)
What Smarty Does
- ✅ Full US DPV confirmation (same data as USPS)
- ✅ 240+ country international coverage
- ✅
verification_status: Verified / Partial / Ambiguous / None - ✅ Geocoordinates included in response
- ✅ Rooftop-level precision for supported countries
Partialresults (street-level only) setneeds_review = true
Google Address Validation API
Best for: International addresses in ~40 supported countries Cost: $0.005 per request (~$5 per 1,000 addresses) Coverage: ~40 countries (AR, AU, AT, BE, BR, CA, CL, CO, CZ, DK, EE, FI, FR, DE, HU, IE, IL, IT, JP, KR, LV, LT, MX, NL, NZ, NO, PL, PT, PR, RO, SG, SK, SI, ZA, ES, SE, CH, TW, GB, US)
Note: China (CN), India (IN), and South Korea (KR) are not reliably supported in practice. CN and IN return "No Provider" cleanly. KR is listed in Google's coverage docs but the API may return an error — the package handles this gracefully and shows "Address verification is not available for this country." Use
autoprovider to route these countries to Smarty automatically.
Setup
- Enable "Address Validation API" in Google Cloud Console
- Add to
.env:
GOOGLE_MAPS_SERVER_KEY=your_server_key # Address Validation API + Geocoding API
ADDRESS_VERIFICATION_PROVIDER=googleWhat Google Does
- ✅ International address formatting
- ✅ Address component extraction
- ✅ Coordinate geocoding included
- ✅ Supports local language formats
- ✅ Less aggressive standardization than USPS
Auto Provider Selection (Recommended)
Automatically chooses the best available provider based on country:
ADDRESS_VERIFICATION_PROVIDER=autoSelection Order
For each address, the system works through three layers in order:
1. Country pins (country_providers config) — hard-wired overrides for specific countries:
// config/addresses.php
'country_providers' => [
'US' => 'usps', // Always use USPS for US
],2. Smart routing — when both Smarty and Google are configured and the country is not pinned, the system selects the better provider based on Smarty's published coverage tiers:
- Countries where Smarty has DeliveryPoint precision (CA, AU, GB, FR, DE, BR, and 150+ others) → Smarty tried first
- All other countries (JP, and others where Smarty precision is lower or empirically unreliable) → Google tried first
Within each group, the losing provider is still tried as a technical fallback. If Google has a billing lapse, Smarty takes over — and vice versa. Technical failures (auth error, billing inactive, rate limit) cause automatic failover to the next provider. Address-level failures (address not found, DPV=N) stop the chain — a different provider won't fix a bad address.
3. No provider available → verification skipped (Verify button hidden in UI).
Default Behavior (all three providers configured)
| Country | Provider | Reason |
|---|---|---|
| US | USPS | Pinned in country_providers |
| CA, AU, GB, FR, DE, BR, IL, SG… | Smarty | Smart routing: Smarty has DeliveryPoint precision |
| JP | Smart routing: Smarty listed as DeliveryPoint but unreliable in practice | |
| CN, IN, RU… | Smarty | Google doesn't cover these; Smarty does |
| Any uncovered | — | No provider available |
Common Customizations
// US clients only — no international needed
'provider_priority' => ['usps'],
// International-first, no USPS
'provider_priority' => ['smarty', 'google'],
// Premium provider for key markets, cheaper elsewhere
'country_providers' => [
'US' => 'usps', // Free and authoritative
'GB' => 'smarty', // Rooftop precision for UK office
'DE' => 'smarty', // German market priority
],
'provider_priority' => ['google', 'smarty'], // Google as default fallbackProvider Comparison
USPS vs Smarty for US Addresses
Both providers produce functionally identical results for US addresses. Either is a sound choice.
| Behavior | USPS | Smarty |
|---|---|---|
| Address normalization | Identical | Identical |
| ZIP+4 | Always added | Added when available |
DPV needs_review | ✅ S/D codes flagged | ✅ S/D codes flagged |
| State format returned | Full name ("California") | Abbreviation ("CA") — fuzzy-matched to full name |
| Cost | Free (rate limited 60/hr) | ~$0.006/request |
Recommendation: Use USPS for US-only deployments — it's free and equally accurate. Use Smarty if you need international coverage, to avoid managing two separate providers.
Google vs Smarty for International Addresses
| Behavior | Smarty | |
|---|---|---|
| Coverage | ~40 countries | 240+ countries |
| China (CN), India (IN) | ❌ Not supported — clean "No Provider" path | ✅ Supported |
| South Korea (KR) | ❌ Removed from supported list — API errors in practice | ✅ Supported |
| Landmark addresses (no street number) | ❌ Fails consistently | ❌ Also fails (same root cause) |
| Intersection formats (e.g. "St A & St B") | ✅ Resolves to primary street | ❌ Rejects format |
| Street name normalization | May abbreviate or expand per local convention | Expands abbreviations; may correct to official name |
| Administrative area extrapolation | ✅ Inferred from city/postal (FR, AU, DE city-states) | Only from API response |
| Postal code corrections | Corrects frequently; may over-correct | Corrects against postal database |
| State name format (MX) | May abbreviate ("Jal.") | Returns full name ("Jalisco") |
| Administrative area level (FR) | Région ("Île-de-France") — stored in administrative_area | Département ("Paris") — stored in administrative_area at level 2 |
| JP block number in chōme addresses | Retained ("1 2-chōme Shibuya") | Dropped ("1 Chome Shibuya") |
address_line_2 content | Unit/landmark fragment only | Delivery-line packing (CA, FR, DE) stripped: values containing the postal code or locality are discarded; MX colonia and JP/CN building values preserved |
| Diacritics / accented characters | ✅ Preserved in UTF-8 ("Rue de la République") | ⚠️ Follows postal authority standard — many countries (FR, ES, IT, PT…) use uppercase ASCII without diacritics ("RUE DE LA REPUBLIQUE"). See Special Character Handling. |
Recommendation: Use auto provider (the default). It routes US to USPS (free), international to Smarty (240+ countries). Google alone has gaps at CN/IN/KR and fails landmark addresses; Smarty alone costs money for US addresses that USPS handles for free.
Country-Specific Behavior Notes
| Country | Notes |
|---|---|
| US | USPS and Smarty are equivalent. USPS is free. |
| GB | Both work for street addresses ✅. Postcodes may be corrected — review via standardization dialog. Smarty has been observed matching to the wrong city for addresses where the street name exists in multiple locations (e.g. "Downing Street" → wrong postcode). |
| CA | Both work ✅. Postal code format preserved (A1A 1A1). Both providers independently corroborate postal corrections. |
| MX | Both work ✅. Smarty returns full state name; Google may abbreviate ("Jal." for Jalisco). Smarty extracts the colonia (neighborhood) into address_line_2 — useful secondary data. |
| FR | Both work ✅. France uses administrative_area_level=2 — the département is stored in administrative_area (101 departments seeded). Google previously returned the région; it now matches the département via fuzzy match. Smarty has always returned the département — no change needed. Entering a postal code auto-populates the département (also works for DE, ES, IT, and NL). The région (level 1) is not stored on the record but is derivable via the département's parent_id for reporting. City is free-text locality. Google may substitute the official postal address for landmarks (e.g. Eiffel Tower → Av. Gustave Eiffel). Accented characters: Smarty returns French addresses per La Poste standard — uppercase ASCII without diacritics (e.g. RUE DE LA REPUBLIQUE, not Rue de la République). Google preserves accents. If diacritic preservation matters, use Google or choose "Keep My Version" in the standardization dialog. |
| DE | Both work ✅. Blur geocoding requires the state field (Bundesland) to be filled first for non-city-states. Berlin works without it (city-state). Entering a postal code auto-populates the Bundesland. |
| AU | Street addresses work ✅. Landmarks and intersections: Google resolves intersections to a street; Smarty rejects them. Landmark names without street numbers fail both. |
| JP | Both work for standard addresses ✅. Romanization is preserved — chōme format offered in standardization dialog, not written directly. Google retains the block number; Smarty may drop it. |
| CN | Google Address Validation not supported. Without Smarty: ROOFTOP/RANGE_INTERPOLATED geocoding results are promoted to google_geocoding verified — badge shows "✓ Verified by Google Geocoding". With Smarty ✅: Smarty covers CN but may match common street names to the wrong city (e.g. "Jianguo Road" matched to wrong province) — always review the standardization dialog for CN addresses. |
| IN | Google not supported — clean "No Provider". Smarty covers IN for street addresses ✅. Landmark-only addresses (no street number) fail verification — enter a street address with a house number. |
| KR | Google excluded from KR support (API errors in practice). auto routes to Smarty automatically. |
Landmark Addresses
Named landmarks without a street number (e.g. "Opera House", "Buckingham Palace") consistently fail both Google and Smarty. The geocoder cannot extract a street component, so the verification provider receives an incomplete address and rejects it.
Workaround: Enter the street address and house number instead of the landmark name. The standardization dialog will show the provider's canonical form — for well-known landmarks Google may return an official postal address (e.g. the Eiffel Tower's address is "Av. Gustave Eiffel, 75007 Paris").
Geocoding Confidence and Sanity Checks
Even when verification succeeds, the package applies additional quality checks:
Geocoding confidence scoring: The Google Geocoding API returns a location_type indicating precision. Results with GEOMETRIC_CENTER or APPROXIMATE location types automatically set needs_review = true — the address saved but should be confirmed by a human. ROOFTOP and RANGE_INTERPOLATED results are accepted without flagging.
Geocoding-as-verification fallback: For countries not covered by any configured postal provider (e.g. CN, most of Africa/Central Asia), a ROOFTOP or RANGE_INTERPOLATED geocoding result is promoted to verified status — is_verified = true, verification_provider = 'google_geocoding'. This reflects that the address is genuinely well-located; it is not unverified because of bad data, but because no postal provider architecturally covers the country. The badge shows "✓ Verified by Google Geocoding". Low-confidence results (GEOMETRIC_CENTER, APPROXIMATE) are not promoted.
Verification sanity checks: Before accepting a verified result, the package checks for:
- Blank
address_line_1— if the provider returns an empty street, the original user input is preserved - Empty city — if the provider returns no city, the user's city is kept
- Cross-country postal code — if the postal code belongs to a different country than selected, the result is rejected
These checks run automatically on every verification and require no configuration.
None (Disable Verification)
ADDRESS_VERIFICATION_ENABLED=false
# OR
ADDRESS_VERIFICATION_PROVIDER=noneAddresses are saved as entered without verification. Useful for:
- Development/testing
- Addresses that don't need validation
- Reducing API costs
How Verification Works
User Flow
- User enters address (manually or via map/autocomplete)
- System verifies address on save using configured provider
- If differences found → Shows verification choice dialog
- User chooses → "Use Standardized" or "Keep My Version"
- Address saved with verification metadata
Verification Metadata
Stored in address record:
is_verified(boolean)verification_provider(usps,smarty,google,google_places;nullwhen not verified)verified_at(timestamp)verification_metadata(JSON with full response)
Verification Choice Dialog
When it appears:
- Verification found differences that might change meaning
- User needs to decide which version to use
When it does NOT appear:
- ✅ Address verified successfully with no differences
- ✅ Address matches verification exactly
- ✅ This is the optimal UX - seamless verification!
You may ask: "Why don't I see the verification dialog?"
Answer: The dialog only appears when needed. If verification succeeds seamlessly, you won't see it. This is intentional and means everything worked perfectly!
Understanding the Verification Comparison
Why It Exists
The comparison appears when there are meaningful differences between what you entered and what the postal service database shows. You need to decide which version to keep.
What It Looks Like
The comparison is not a modal — it appears inline within the form, below the address fields, and scrolls into view automatically. It has an amber top accent and a warning icon in the header.
Header: "Address Standardized by {Provider}" (e.g. "Address Standardized by USPS")
Two side-by-side cards:
| Your Input | Standardized Version |
|---|---|
| Original badge (gray) | Recommended badge (green) |
| Changed fields highlighted in amber | Changed fields highlighted in green |
| Unchanged fields in normal text | Unchanged fields in normal text |
Only fields with non-empty values are shown. Empty fields (e.g. address_line_2 if blank) are omitted from both cards.
Changes bar: Below the cards, a summary line lists which fields differ — e.g. "Changes detected: address line 1, locality, postal code"
Buttons:
- Keep My Version — gray outlined button; applies your original input and marks the address as verified (the provider confirmed it was deliverable, even if you prefer your formatting)
- Use Standardized — green button with a checkmark icon; applies the provider's standardized version
When to Use Standardized
Use standardized in most cases:
- Provider corrected a street name, city, or postal code → accept it
- ZIP+4 was added → accept it (improves mail routing, no downside)
- Street abbreviations expanded or normalized → accept it
When to Keep Your Version
- Your suite/unit format is required by your organization and the provider's version differs only in formatting
- Address is new construction not yet in the postal database
- Provider has mapped to the wrong street (rare, but possible — especially for common street names in dense areas)
Verification Without Seeing the Dialog
How to Confirm It's Working
If you don't see the verification dialog, here's how to confirm verification is happening:
Method 1: Check the UI
- Save an address
- View in address table
- Look for ✅ green checkmark icon in "Verified" column
- Hover over checkmark → See "Verified by USPS on Feb 15, 2026"
Method 2: Check the Database
php artisan tinkeruse Viewflex\FilamentAddress\Models\Address;
// Check recent addresses
$recent = Address::orderBy('created_at', 'desc')->take(5)->get();
foreach ($recent as $addr) {
echo $addr->address_line_1 . PHP_EOL;
echo ' Verified: ' . ($addr->is_verified ? 'YES' : 'NO') . PHP_EOL;
echo ' Provider: ' . ($addr->verification_provider ?: 'none') . PHP_EOL;
echo ' At: ' . ($addr->verified_at ? $addr->verified_at->format('Y-m-d H:i') : 'never') . PHP_EOL;
}
// Count verified addresses
echo "\nTotal verified: " . Address::where('is_verified', true)->count();Method 3: Check Laravel Logs
tail -f storage/logs/laravel.log | grep -i verifLook for:
[info] Address verified by USPS: 123 Main St
[info] Verification successful, no differencesIntegration with Blur Geocoding
The package integrates verification with blur geocoding seamlessly:
What Happens
- User types address in
address_line_1field - User tabs out (blur event)
- Geocoding runs → Gets full address from Google
- Verification runs → Validates/standardizes address
- Form auto-fills → All fields populated with verified data
- No dialog shown → Because it all happened automatically!
Why This is Better UX
Traditional verification:
- User fills all fields manually
- Clicks save
- Dialog appears → User must review differences
- User clicks "Use Standardized"
- Form reloads with new data
Our integrated approach:
- User types partial address
- Tabs out
- ✨ Everything happens automatically
- User sees final verified address immediately
- Can make adjustments before saving
Result: Faster, fewer clicks, less cognitive load.
Verification Best Practices
For New Addresses
There are three ways to enter an address. Choose based on what your users are doing:
Autocomplete (Places search box)
Best when the user is looking up an address they can recognize in a dropdown — customer-facing forms, CRM entry from known contacts, anything where the user can search and select.
- User types into the search box; Google Places suggestions appear
- One selection fills all fields — street, city, state, postal code, coordinates
- Marked as verified automatically (
google_places); no Verify button press needed - API cost: one session-billed Places request per selection (not per keystroke)
If you need postal deliverability confirmation (DPV, ZIP+4) beyond what Places provides, click Verify after autocomplete to run USPS or Smarty on top of the Places-filled data. This is worth doing for US addresses where deliverability matters.
Blur geocoding (type into Address Line 1, tab out)
Best for staff entering addresses from a document, letter, or label — where the user is reading and typing, not searching. Also handles paste-and-tab workflows.
- User types (or pastes) a street address into Address Line 1, then tabs out
- Geocoding runs automatically and fills remaining fields (city, state, postal code, coordinates)
- User then clicks Verify to run the configured provider and see the comparison if differences exist
- API cost: one Geocoding API call + one verification API call
The geocoding step handles partial input well — a street address with just a city is often enough to fill the rest. Configuring ADDRESS_BLUR_REQUIRE_COMPLETENESS=basic prevents wasted API calls on incomplete input.
Manual entry
Use only when the address is not in Google's database — new construction, rural routes, or addresses that consistently fail geocoding. Every field must be filled by hand, and verification is the only quality check.
❌ Avoid regardless of mode:
- Saving without clicking Verify (or confirming the autocomplete result is correct)
- Always choosing "Keep My Version" without reading what changed
- Disabling verification to save time — the cost of bad addresses in your database is higher than the API cost
For Existing Addresses
✅ Recommended:
- Use bulk verification action for batches
- Review flagged addresses needing attention
- Keep verified status up-to-date
❌ Avoid:
- Manually editing verified addresses (loses verification status)
- Importing unverified data over verified data
For Bulk Operations
✅ Recommended:
- Import with
verify: false(faster initial import) - Use bulk verify action after import
- Review addresses that need review (
needs_review = true)
❌ Avoid:
- Verifying during import (slow, expensive)
- Ignoring addresses that need review
Special Character Handling
What Verification Does to Special Characters
USPS behavior:
- Apostrophes removed:
O'Brien→Obrien - Hyphens in unit designators standardized:
#5-B→Apt 5b - Parentheses removed:
(Rear)→ removed - USPS returns all-uppercase internally; the package normalizes to Title Case before displaying in the dialog or storing in the database
Google behavior:
- Less aggressive
- Preserves more formatting
- Title Case typical
- Diacritics (accents, umlauts, etc.) preserved in UTF-8
Smarty International behavior:
- Returns addresses following each country's postal authority standard
- Many postal authorities (France La Poste, Spain Correos, Italy Poste Italiane, Portugal CTT, Brazil ECT, and others) mandate uppercase ASCII without diacritics — this is what appears on physical mail
- Examples:
Rue de la République→RUE DE LA REPUBLIQUE,Calle Alcalá→CALLE ALCALA,Piazza dell'Unità→PIAZZA DELL'UNITA - Germany (Deutsche Post) and some Northern European postal authorities preserve case and diacritics
- The standardization dialog shows both your input and the Smarty-standardized form side by side — if preserving accents matters for your use case, choose "Keep My Version"
Example
Input:
123 O'Brien's Ave, Apt #5-B (Rear)
Washington, DC 20500As displayed in the standardization dialog:
address_line_1: 123 Obriens Cir
address_line_2: Apt 5b
Winchester, VA 22602Why the differences?
- Street type changed (Ave → Cir): USPS database shows this is actually a Circle, not Avenue
- Special characters removed and unit normalized: Apostrophes and parentheses stripped; unit designator moved to
address_line_2in standardized form - City changed: Address was actually in Winchester, not Washington
This is correct! USPS found the real address and corrected user mistakes.
Verification Costs
Cost Comparison
| Provider | Cost per Request | Coverage | Free Tier |
|---|---|---|---|
| USPS | FREE | US only | 60/hour (no paid tier) |
| Smarty | ~$0.006 | 240+ countries | Plan-based |
| $0.005 | Global | None |
Smarty and Google costs are estimates — check current pricing on their respective sites.
Cost Optimization
- Use auto provider → Free USPS for US addresses, paid provider only for international
- Cache results → Enabled by default (30-day TTL); repeated verifications of the same address are free
- Bulk operations → Verify after import rather than during, to avoid redundant API calls
- Rate limiting → USPS rate limiter prevents accidental overage
Example Costs
1,000 US addresses:
- With USPS: $0 (within rate limit)
- With Google: $5
1,000 international addresses:
- With Smarty: ~$6
- With Google: $5
10,000 mixed addresses (auto provider):
- 5,000 US via USPS: $0
- 5,000 international via Smarty: ~$30
- Total: ~$30 (vs $50 if all Google)
Troubleshooting
Verification Not Working
Check configuration:
php artisan tinker// Check verification enabled
config('addresses.verification.enabled') // should be true
// Check provider
config('addresses.verification.provider') // auto, usps, google, or none
// Check API keys
config('addresses.google_maps_server_key') // should have value (used for Google verification)
config('addresses.verification.usps.consumer_key') // should have valueCheck Laravel logs:
tail -f storage/logs/laravel.log | grep -i verifUSPS Returns Errors
Common errors:
"USPS API Error: Invalid API Key"
- Double-check Consumer Key/Secret in
.env - Verify keys are activated in USPS account
"Rate limit exceeded"
- Wait for hourly reset, OR
- Change to
USPS_LIMIT_BEHAVIOR=fallbackto use Google when limited
"Address not found"
- Address might not exist in USPS database
- Try "Keep My Version" or use Google instead
Google Returns Errors
"API key not valid"
- Check API key in
.env - Verify Address Validation API is enabled in Google Cloud Console
- Check API key restrictions
"You have exceeded your daily quota"
- Check Google Cloud Console for quota limits
- Increase quota or wait for reset
Dialog Not Appearing (Normal!)
This is usually correct behavior. See Verification Without Seeing the Dialog above.
Verification Fields Reference
These fields on the Address model track verification state:
| Field | Type | Description |
|---|---|---|
is_verified | boolean | true when an external service has confirmed the address |
needs_review | boolean | true when verification found meaningful differences awaiting user review |
verification_provider | string|null | Which service verified: usps, smarty, google, google_places, google_geocoding; null when not verified |
verified_at | timestamp|null | When verification occurred |
verification_metadata | JSON|null | Raw provider response plus a context key |
Verification Status Badge
The form displays a badge below the address fields reflecting the current verification state:
| Badge | Meaning |
|---|---|
| 🟢 ✓ Verified by {Provider} | Postal-verified (USPS, Smarty, Google, Google Geocoding) |
| 🔵 ✓ Accepted by user | Manually accepted — user dismissed a review prompt |
| 🔵 ✓ Accepted — Location Verified | Google Places selection with postal verification pending |
| 🟡 ⚠ Needs Review | Verification found differences or a POI was selected |
| 🟡 Not Verified | No verification has been run yet |
Clickable badge popover: The green and blue accepted badges are clickable. Clicking opens a popover showing the provider name, verification date, and a Re-verify Address button. This gives staff a clean entry point for re-running verification on already-verified addresses without exposing a permanent Re-verify button on the form. The Re-verify button is omitted when verification is not available for the current country or when no provider is configured.
needs_review Lifecycle
Set to true in these situations:
- Bulk verification — the standardized version differs meaningfully from the stored address. The address manager shows a warning badge; the user resolves each by choosing "Use Standardized" or "Keep My Version".
- Google Places selection of a POI (no street address) — the selected place is a landmark or business with no civic address; the user should confirm the street before saving.
- Low-confidence geocoding — Google returned
GEOMETRIC_CENTERorAPPROXIMATElocation type, indicating the coordinates may not be precise. - Silent verification failure — in
silentmode, a failed verification setsneeds_review = truefor staff review in the admin panel.
Set to false:
- When the user resolves a bulk-verification conflict ("Use Standardized" or "Keep My Version").
- When the user clicks "Accept Address" — shown for Places-verified addresses in countries where no verification provider is configured (no API call, just clears the flag).
- When the user clicks Verify (or Re-verify) and verification succeeds.
- On country change (resets all verification state).
Street mismatch between Places and reverse geocode is recorded in verification_metadata['street_mismatch'] for auditing but does not set needs_review. The user's Places selection is the authoritative street; the reverse geocode is used only to populate administrative subdivisions.
DPV=S and quality scoring: USPS and Smarty return DPV=S when the primary address matches but the secondary unit is missing or uses a different designator than USPS has on file ("2B" vs "APT 2B"). When needs_review is set as a result, the quality score treats the address as partially confirmed (lower score). When the user accepts the USPS-standardized form — clearing needs_review — the concern is resolved and the quality score reflects a fully confirmed address. The verification_metadata retains the original DPV code for auditing regardless.
Quality scoring for countries with no provider coverage: Unverified addresses in countries not covered by any configured postal provider (e.g. CN without Smarty, most of Africa/Central Asia) receive a neutral verification score (20 pts, same as google verified) rather than a zero penalty. The address is unverified because no provider covers the country — not because of bad data. This guard only applies when at least one provider is configured globally; environments with no API keys score 0 as normal.
verification_metadata Structure
The JSON object contains provider-specific data merged with two common keys added by the package:
context— how the verification was triggered (see values below)verified_at_timestamp— ISO 8601 timestamp of verification
The provider-specific keys differ by provider:
USPS:
{
"usps_response": { "streetAddress": "123 Main St", "city": "Springfield" },
"additional_info": { "deliveryPoint": "12", "checkDigit": "1" },
"dpv_confirmation": "Y",
"needs_review": false,
"original_input": { "address_line_1": "123 main st", "locality": "springfield" },
"context": "manual_entry",
"verified_at_timestamp": "2026-04-03T12:00:00+00:00"
}When needs_review is true, a review_reason key is also present explaining the DPV code (e.g. missing secondary information).
Smarty (US Street API):
{
"dpv_match_code": "Y",
"dpv_footnotes": "AABB",
"dpv_vacant": "N",
"rdi": "Residential",
"precision": "Zip9",
"context": "manual_entry",
"verified_at_timestamp": "2026-04-03T12:00:00+00:00"
}Smarty (International Street API):
{
"verification_status": "Verified",
"address_precision": "Premise",
"geocode_precision": "Rooftop",
"needs_review": false,
"context": "manual_entry",
"verified_at_timestamp": "2026-04-03T12:00:00+00:00"
}Google Places selection (not a provider verification — set when user selects from autocomplete):
{
"source": "google_places_selection",
"has_street_address": true,
"street_mismatch": false,
"context": "map_selection",
"verified_at_timestamp": "2026-04-03T12:00:00+00:00"
}Context values:
manual_entry— User submitted or re-verified via the formmap_selection— User selected a location from the Places autocomplete or mapbulk_verification— Triggered by a bulk verification operationimport— Triggered during a CSV/Excel import
Planned Enhancements
No planned enhancements at this time.
See Also
- User Guide - General package features
- Import/Export Guide - Bulk verification
- Configuration Reference - All config options
- API Reference - Service layer docs