realestateconz/api-client
A Laravel/PHP client for the realestate.co.nz API, giving you a clean, fluent wrapper for property listings, search, and related endpoints. Handles authentication, requests, and responses so you can integrate NZ real estate data into your app with minimal boilerplate.
Reality check first: this is a thin, vendor-published PHP SDK (0 stars, 0 dependents, not Laravel-specific). There is no service provider, facade, config file, or publishable assets. Treat it as a plain Composer library you wrap yourself — do not expect Laravel ergonomics out of the box.
Install:
composer require realestateconz/api-client
Where to look first:
README.md — for the credential format (API key vs. OAuth client id/secret) and the base URL / environment (sandbox vs. production).src/ — find the main client class (typically Client or ApiClient) and the request/response layer. This is your source of truth; the README is often stale on a package this small.composer.json — check the Guzzle major version and the PHP constraint. Old Guzzle pins (5.x/6.x) will fight with a modern Laravel app's dependency graph.Minimal first use case — pull a page of listings for a region and dump the raw payload so you can see the actual response shape:
use RealestateConz\ApiClient\Client; // confirm exact namespace from src/
$client = new Client([
'api_key' => config('services.realestate.key'),
'api_secret' => config('services.realestate.secret'),
]);
$response = $client->getListings(['region' => 'wellington', 'page' => 1]);
$data = json_decode((string) $response->getBody(), true);
dd($data); // inspect before writing any mapping code
The very first integration task should be an exploratory script like the above. Do not build DTOs or migrations until you have seen a real response body — the client almost certainly returns raw PSR-7 responses rather than typed objects.
Configuration: put REALESTATE_API_KEY / REALESTATE_API_SECRET in .env and expose via config/services.php. Never rely on the package reading env vars itself.
Bind the client as a singleton. The client is stateless HTTP; rebuild it once per request, not per call.
// AppServiceProvider::register()
$this->app->singleton(RealestateClient::class, fn () => new Client([
'api_key' => config('services.realestate.key'),
'api_secret' => config('services.realestate.secret'),
'timeout' => 10,
]));
Wrap it in your own service, not the vendor class. Inject RealestateClient into an app-owned PropertySearchService and return your own DTOs/arrays. This is the single most valuable pattern here — it isolates the zero-dependency vendor risk behind an interface you control, so swapping to a hand-rolled Guzzle client later is a one-file change.
Search → paginate → persist as a queued job. Listing APIs are paginated and rate-limited. Model ingestion as a job that requests one page, dispatches itself for page + 1 (with a delay), and upserts by listing ID. Do not loop pages synchronously inside a web request.
$page = $client->getListings(['region' => $region, 'page' => $page]);
// upsert by external id, then dispatch next page with backoff
Upsert, don't insert. Listings change (price, status, sold). Keep a realestate_id unique column and updateOrCreate on it so re-syncs are idempotent.
Cache reads aggressively. Search/browse payloads are a good fit for Cache::remember() with a TTL of minutes, keyed by a hash of the query params. The underlying data changes slowly relative to your read traffic.
Integration tips:
HandlerStack) for request/response logging and retry-on-5xx — the client likely exposes the underlying GuzzleHttp\Client or accepts handler options.No Laravel integration. No auto-discovery, no facade, no config merge. You must register bindings and write config yourself. Do not expect php artisan vendor:publish to do anything.
Vendor/abandonment risk is the real gotcha. Zero stars and zero dependents means no community safety net, no Stack Overflow answers, and a high chance of an unmaintained dependency. Pin the exact version in composer.lock and be prepared to fork. Audit composer.json for stale Guzzle/PHP constraints before adopting on a modern Laravel version.
Raw responses, not DTOs. Expect Psr\Http\Message\ResponseInterface back. You own JSON decoding, key mapping, and error detection — a 200 with an errors key in the body is common in NZ property APIs. Write one parseResponse() helper and use it everywhere.
Auth quirks. If it is OAuth rather than static keys, tokens expire and the client may not refresh them for you. Check whether the token fetch is built in or whether you must supply an access token per request. Refresh on 401, cache the token in your cache store, and never fetch a token per API call.
Rate limits and pagination edge cases. Watch for a total_pages/total_count in the response rather than assuming a full page means "more pages." Add a safety cap on page count so a bug can't spin a queue worker forever.
Debugging: enable Guzzle debug output ('debug' => true in client options) to see the actual request URI and headers. Most "it returns nothing" issues are a wrong base URL or a silently swallowed non-2xx status — check getStatusCode() before decoding.
Testing: bind a fake RealestateClient in tests, or use Guzzle's MockHandler to replay recorded fixture responses. Never hit the live API in CI. Because the client is untested upstream, your own tests around response parsing are your only regression safety.
Extension points: subclass the vendor client to add app-specific helpers, and use Guzzle HandlerStack middleware for cross-cutting concerns (logging, retries, auth headers). Both let you avoid forking while still bending the client to your needs.
Timezones and currency: this is a NZ dataset — store timestamps in Pacific/Auckland at the boundary and convert to UTC in the DB; treat prices as NZD integers (cents or whole dollars — confirm in the payload) to avoid float drift.
Verdict for day-to-day leverage: low. It saves you ~50 lines of Guzzle boilerplate at the cost of an unmaintained, untyped dependency. Use it only if the README's auth flow is genuinely fiddly (signed requests, multi-step OAuth); otherwise a 30-line hand-rolled Guzzle wrapper behind your own interface is lower risk and equally fast.
How can I help you explore Laravel packages today?