DEV Community

Rojo
Rojo Subscriber

Posted on • Originally published at packagepr.com

A Developer's Checklist: Does Your App Ship to Puerto Rico?

Quick audit checklist for ecommerce developers. If your platform fails any of these, you're blocking 3.2 million US customers.

The Checklist

Address Validation

  • [ ] State dropdown includes PR, GU, VI, AS, MP, DC
  • [ ] Zip code validation accepts 006xx through 009xx (PR range)
  • [ ] Address autocomplete returns Puerto Rico results
  • [ ] "Country: United States" includes PR addresses

Shipping Configuration

  • [ ] PR is in your "Domestic" shipping zone (not "International" or "Rest of World")
  • [ ] No Extended Area Surcharges applied to PR (use USPS)
  • [ ] Carrier API correctly classifies PR as domestic
  • [ ] Shipping calculator returns valid rates for zip 00901

Tax Calculation

  • [ ] PR addresses get IVU rate (11.5%), not mainland state tax
  • [ ] Tax exempt for certain categories per PR law
  • [ ] No import duties calculated (it's domestic!)

Checkout Flow

  • [ ] Complete checkout possible with PR billing address
  • [ ] PR phone format accepted (+1-787-XXX-XXXX and +1-939-XXX-XXXX)
  • [ ] Email confirmation doesn't say "international order"
  • [ ] Delivery estimate reflects actual PR shipping times (5-14 days)

Test Addresses

San Juan Metro:
  123 Calle Fortaleza
  San Juan, PR 00901

Suburban:
  456 Ave Los Pinos
  Bayamón, PR 00959

West Coast:
  789 Calle McKinley
  Mayagüez, PR 00680

Rural:
  101 Carr 123 Km 4.5
  Adjuntas, PR 00601
Enter fullscreen mode Exit fullscreen mode

Common Bugs

Bug 1: State array is incomplete

// ❌ Bad
const US_STATES = ['AL', 'AK', ... , 'WY']; // 50 states only

// ✅ Good  
const US_JURISDICTIONS = [
  'AL', 'AK', ... , 'WY',
  'DC', 'PR', 'GU', 'VI', 'AS', 'MP'
];
Enter fullscreen mode Exit fullscreen mode

Bug 2: Zip code regex is wrong

// ❌ Rejects PR zips
const isValidZip = /^\d{5}(-\d{4})?$/.test(zip) && parseInt(zip) >= 10000;

// ✅ Accepts all US zips including PR (00601-00988)
const isValidZip = /^\d{5}(-\d{4})?$/.test(zip);
Enter fullscreen mode Exit fullscreen mode

Bug 3: Carrier API defaults

# ❌ Some APIs default PR to international
shipping_zone = carrier.get_zone(destination)
# Returns "INTERNATIONAL" for PR addresses

# ✅ Override for US territories
if destination.state in ['PR', 'GU', 'VI', 'AS', 'MP']:
    shipping_zone = 'DOMESTIC'
Enter fullscreen mode Exit fullscreen mode

The Business Case

  • 3.2 million potential customers
  • ~$5.5 billion annual online spending
  • Higher avg order values (limited local retail)
  • Zero extra logistics (USPS = domestic rates)

Five lines of code. Millions in revenue.


Full breakdown of which retailers get it right and which don't: packagepr.com/blog/us-retailers-that-dont-ship-or-restrict-shipping-to-puerto-rico

Shopify-specific guide: packagepr.com/blog/does-shopify-ship-to-puerto-rico

Top comments (0)