Building a Postal Code Lookup API for Indonesian E-commerce


Indonesian e-commerce sites need postal code lookups for checkout forms. Users select province, then kabupaten/kota, then kecamatan, then kelurahan, and the postal code populates automatically. Simple in theory. Messy in practice because Indonesian postal data is inconsistent, incomplete, and changes without clear documentation.

I’ve built three different postal code lookup systems for Indonesian platforms. Here’s what actually works versus what the official data suggests should work.

The Data Source Problem

Indonesia Post (Pos Indonesia) maintains the official postal code database. But accessing clean, complete, current data is harder than it should be. The official website has lookup functionality but no public API. Third-party datasets exist but vary in completeness and accuracy.

The data includes hierarchical relationships: province contains multiple kabupaten/kota, each contains kecamatan, each contains kelurahan/desa, each has a postal code. Sometimes multiple kelurahan share a postal code. Sometimes one kelurahan has multiple postal codes for different neighborhoods.

Data quality issues include: missing entries for remote areas, outdated codes for areas that have changed administratively, inconsistent spelling of place names, and codes that don’t match what local postal workers actually use. Your lookup API needs to handle these imperfections.

Structuring the Database

A relational database works well for this hierarchical data. Tables for provinces, kabupaten_kota, kecamatan, kelurahan, and postal_codes with foreign key relationships. This allows querying at each level and enforcing referential integrity.

Index heavily on the columns used for lookups—province_id, kabupaten_id, kecamatan_id. These queries happen constantly during checkout. Without proper indexing, response times suffer as data grows.

Include name variations and alternative spellings. “DKI Jakarta” versus “Jakarta” versus “Jakarta Raya”—users search using all variations. A names table with aliases linked to canonical entries helps address this. Full-text search on name fields catches partial matches.

API Design Considerations

The typical flow needs these endpoints:

  • GET /provinces - returns all provinces
  • GET /kabupaten?province_id={id} - returns kabupaten for a province
  • GET /kecamatan?kabupaten_id={id} - returns kecamatan for a kabupaten
  • GET /kelurahan?kecamatan_id={id} - returns kelurahan for a kecamatan
  • GET /postal-code?kelurahan_id={id} - returns postal code for a kelurahan

Include search endpoints for type-ahead functionality:

  • GET /search/kabupaten?q={query}&province_id={id}
  • GET /search/kecamatan?q={query}&kabupaten_id={id}

These let users start typing and see matching results, improving UX for unfamiliar place names.

Handling Data Inconsistencies

Some kelurahan have multiple postal codes. Your API should return an array of codes, not assume one-to-one mapping. The frontend needs to handle displaying multiple options or picking the most common one.

Missing data for remote areas requires graceful handling. Return the most specific postal code available—maybe kecamatan-level if kelurahan-level doesn’t exist. Indicate confidence level in responses so frontends can communicate uncertainty to users.

Name variations need normalization. Store canonical names but search across variations. “Kab. Bandung” and “Kabupaten Bandung” should match the same entity. Diacritics and special characters need handling too.

Caching Strategy

Postal codes don’t change frequently. Heavy caching makes sense. Cache province and kabupaten lists aggressively—these almost never change. Cache kecamatan and kelurahan for longer periods—they change but rarely.

Use ETags to allow clients to cache responses. When data does change, clients detect it through ETag mismatches and fetch fresh data. This reduces API load dramatically for production applications making frequent lookups.

Consider returning entire hierarchies in single requests for provinces that aren’t too large. Some provinces have limited kabupaten and kecamatan. Sending the full hierarchy in one response lets frontends populate dropdowns without additional API calls.

Search Performance

Type-ahead search needs to be fast—sub-100ms for good UX. Full-text search indexes help. PostgreSQL’s pg_trgm extension for trigram matching works well for Indonesian place names. This handles spelling variations and partial matches better than simple prefix search.

Ranking search results matters. Prioritize by population—Jakarta should rank above small desa with similar names. Consider usage frequency—if 95% of users search for certain locations, rank those higher. Machine learning can improve ranking based on actual user behavior.

Data Updates

Indonesian administrative boundaries do change. New kelurahan get created, codes get reassigned, names change officially. Your system needs update mechanisms without breaking existing references.

Soft deletion works better than hard deletion. Mark old entries as deprecated rather than removing them. This prevents breaking historical order data using old codes while directing new entries to current codes.

Version the data. Each entry can have effective_from and effective_until dates. Queries default to current data but can retrieve historical information when needed. This supports analytics and customer service looking at old orders.

Integration with Shipping

The postal codes need to integrate with shipping provider APIs. JNE, SiCepat, J&T, and others have their own location databases that don’t perfectly align with official postal codes. Sometimes you need to map official codes to shipping provider codes.

Maintain a mapping table between your postal codes and shipping provider location IDs. This lets you translate user-selected locations into shipping provider requests without users dealing with multiple systems.

Some shipping providers use their own hierarchical systems that don’t match government administrative divisions. Your API might need to support multiple hierarchical models and translate between them.

Frontend Patterns

Cascading dropdowns are standard but have UX issues—users must make multiple selections sequentially. Consider autocomplete search that searches across all levels simultaneously. “Type any part of your address” with smart parsing.

Save location history for registered users. If someone ordered before, pre-populate their previous address including postal code. Most users order to the same locations repeatedly. This reduces friction dramatically.

Mobile optimization matters. Dropdowns with thousands of options are painful on mobile. Search with keyboard input works better than scrolling through options. Consider location detection to default to user’s current province.

Validation and Error Handling

Validate the entire hierarchy—ensure the selected kelurahan actually belongs to the selected kecamatan within the selected kabupaten. Users sometimes make selection errors. Server-side validation catches these before order submission.

Provide helpful error messages. “This kelurahan doesn’t exist in the selected kecamatan” tells users what’s wrong. “Invalid postal code” is vague and frustrating.

Handle API failures gracefully. If your lookup API is down, allow manual postal code entry rather than blocking checkout. Business continuity matters more than perfect data validation.

Security and Rate Limiting

Postal code lookups are public information but APIs still need protection. Rate limiting prevents abuse—someone scraping your entire database or DDoSing your API. 100 requests per minute per IP covers legitimate usage while blocking abuse.

API keys for production integrations let you monitor usage patterns and contact integrators if problems arise. Public endpoints for casual usage with stricter rate limits. Different tiers based on needs.

Log suspicious patterns. Systematic scraping, unusual geographic interest patterns, or credential sharing become visible in logs. Monitoring helps identify and block abuse early.

Alternative Data Sources

Several third parties maintain Indonesian postal databases. Some charge for API access, others provide free data with attribution requirements. Comparing multiple sources helps identify data quality issues—if three sources agree but one differs, probably the outlier is wrong.

Crowdsourcing corrections from users helps. When someone reports an incorrect postal code, verify and update. Platforms like business AI solutions sometimes help organizations build data validation workflows to improve database quality over time.

Government open data initiatives sometimes release updated postal code datasets. Monitoring these sources and integrating updates keeps your database current without manual research.

Testing Across Indonesia

Don’t just test with Jakarta and major cities. Include remote areas like Papua or Nusa Tenggara where data is often incomplete. Test with difficult cases—areas that recently changed administratively or have unusual naming.

Beta test with users from diverse regions. They’ll find data problems your development team in Jakarta wouldn’t notice. Regional variations in how people expect to search or what names they use become apparent through user testing.

Cost Considerations

Building and maintaining this system has costs. Database hosting, API infrastructure, data updates, and support all require resources. For small e-commerce sites, third-party APIs might be cheaper than building internally.

For larger platforms with high transaction volumes, internal APIs avoid per-lookup fees and provide control over data quality and features. The build-versus-buy decision depends on scale and specific needs.

Real-World Compromises

Perfect postal code data doesn’t exist. Your API will have gaps, errors, and inconsistencies. The goal is making the system good enough for business purposes while handling imperfection gracefully.

Users can usually complete purchases even with data gaps if the system allows manual entry and doesn’t enforce rigid validation. The postal code mainly needs to be accurate enough for shipping—exact matching matters less than getting packages to the right general area.

Documentation that acknowledges limitations helps set appropriate expectations. “Our database contains 99% of Indonesian postal codes, with the most complete coverage in urban areas” is honest and manages expectations better than claiming perfect completeness.

Building a postal code lookup API for Indonesian e-commerce means accepting that the underlying data is messy and building systems that work despite imperfection. Clean data architecture, smart searching, careful error handling, and graceful degradation create functional systems even when the data isn’t perfect.