API Reference

Table of contents

  1. Artisan Commands
    1. postcode:download
    2. postcode:seed
  2. Models
    1. Province
    2. Regency
    3. District
    4. Village
  3. Seeders
    1. PostcodeSeeder
    2. Individual Seeders
  4. Example Queries
    1. Full Address Lookup
    2. All Districts in a Province
    3. Search Villages by Name
    4. Count Statistics
    5. Find by Province Code

Artisan Commands

postcode:download

Downloads all postcode data from Pos Indonesia and saves as CSV.

php artisan postcode:download

Options: None

Output: CSV file at the configured storage_path (default: storage/app/postcode/kodepos.csv)


postcode:seed

Seeds all postcode tables (provinces, regencies, districts, villages) from the downloaded CSV.

php artisan postcode:seed

Options: None

Output: All 4 tables populated with data from Pos Indonesia

This command is a convenient alternative to php artisan db:seed --class=..., which can fail on Linux due to shell backslash escaping.


Models

Province

use Ajangsupardi\PostcodeId\Models\Province;

// Get all provinces
$provinces = Province::all();

// Find by code
$province = Province::where('code', 'JI')->first();

// Get regencies
$regencies = $province->regencies;

Table: provinces

Column Type Description
id bigint Primary key
name string Province name (e.g., “Jawa Timur”)
code string(10) Province code (e.g., “JI”)

Relationships:

Method Type Related Model
regencies() HasMany Regency

Regency

use Ajangsupardi\PostcodeId\Models\Regency;

// Get regencies for a province
$regencies = Regency::where('province_id', $provinceId)->get();

// Get parent province
$province = $regency->province;

// Get districts
$districts = $regency->districts;

Table: regencies

Column Type Description
id bigint Primary key
province_id bigint Foreign key to provinces
name string Regency/city name (e.g., “Kota Surabaya”)

Relationships:

Method Type Related Model
province() BelongsTo Province
districts() HasMany District

District

use Ajangsupardi\PostcodeId\Models\District;

// Get districts for a regency
$districts = District::where('regency_id', $regencyId)->get();

// Get parent regency
$regency = $district->regency;

// Get villages
$villages = $district->villages;

Table: districts

Column Type Description
id bigint Primary key
regency_id bigint Foreign key to regencies
name string District name (e.g., “Gubeng”)

Relationships:

Method Type Related Model
regency() BelongsTo Regency
villages() HasMany Village

Village

use Ajangsupardi\PostcodeId\Models\Village;

// Find by postal code
$village = Village::where('postal_code', '60111')->first();

// Get with full hierarchy
$village = Village::with('district.regency.province')
    ->where('postal_code', '60111')
    ->first();

// Search by name
$villages = Village::where('name', 'LIKE', '%Gubeng%')->get();

Table: villages

Column Type Description
id bigint Primary key
district_id bigint Foreign key to districts
name string Village name (e.g., “Gubeng”)
postal_code string(10) Postal code (nullable)

Relationships:

Method Type Related Model
district() BelongsTo District

Scopes:

Scope Parameters Description
postalCode $query, $code Filter by postal code

Seeders

PostcodeSeeder

Runs all seeders in the correct order (Province → Regency → District → Village).

use Ajangsupardi\PostcodeId\Database\Seeders\PostcodeSeeder;

Artisan::call('db:seed', ['--class' => PostcodeSeeder::class]);

Individual Seeders

Run specific seeders if needed:

use Ajangsupardi\PostcodeId\Database\Seeders\ProvinceSeeder;
use Ajangsupardi\PostcodeId\Database\Seeders\RegencySeeder;
use Ajangsupardi\PostcodeId\Database\Seeders\DistrictSeeder;
use Ajangsupardi\PostcodeId\Database\Seeders\VillageSeeder;

Artisan::call('db:seed', ['--class' => ProvinceSeeder::class]);
Artisan::call('db:seed', ['--class' => RegencySeeder::class]);
Artisan::call('db:seed', ['--class' => DistrictSeeder::class]);
Artisan::call('db:seed', ['--class' => VillageSeeder::class]);

Seeders must run in order: Province → Regency → District → Village (due to foreign key dependencies).


Example Queries

Full Address Lookup

$village = Village::with('district.regency.province')
    ->where('postal_code', '60111')
    ->first();

// Output:
// {
//   "name": "Gubeng",
//   "postal_code": "60111",
//   "district": {
//     "name": "Gubeng",
//     "regency": {
//       "name": "Kota Surabaya",
//       "province": {
//         "name": "Jawa Timur",
//         "code": "JI"
//       }
//     }
//   }
// }

All Districts in a Province

use Ajangsupardi\PostcodeId\Models\District;

$districts = District::whereHas('regency', function ($query) use ($provinceId) {
    $query->where('province_id', $provinceId);
})->get();

Search Villages by Name

$villages = Village::where('name', 'LIKE', '%Gubeng%')
    ->with('district.regency')
    ->get();

Count Statistics

use Ajangsupardi\PostcodeId\Models\{Province, Regency, District, Village};

$stats = [
    'provinces' => Province::count(),
    'regencies' => Regency::count(),
    'districts' => District::count(),
    'villages'  => Village::count(),
];

Find by Province Code

use Ajangsupardi\PostcodeId\Models\Province;

$regencies = Province::where('code', 'JI')  // Jawa Timur
    ->first()
    ->regencies()
    ->with('districts')
    ->get();