Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Foursquare Api Client Laravel Package

jcroll/foursquare-api-client

A PHP client for the Foursquare API that simplifies authentication and requests to endpoints like venues, users, and check-ins. Works in Laravel or standalone PHP projects, helping you query location data without boilerplate.

Deep Wiki
Context7

Getting Started

1. Install with an explicit PSR-7/HTTPlug implementation. The package ships no HTTP transport of its own — it declares php-http/client-implementation and relies on php-http/discovery. On a modern Laravel app you must install an adapter yourself, otherwise you get a discovery exception at runtime:

composer require jcroll/foursquare-api-client
composer require php-http/guzzle7-adapter   # or guzzle6-adapter on older apps

2. Configure credentials. Foursquare v2 userless auth needs only a client ID/secret pair plus a mandatory v (version date) parameter:

// config/services.php
'foursquare' => [
    'client_id'     => env('FOURSQUARE_CLIENT_ID'),
    'client_secret' => env('FOURSQUARE_CLIENT_SECRET'),
    'version'       => env('FOURSQUARE_VERSION', '20180201'), // YYYYMMDD, required
    'mode'          => 'foursquare', // base URL flavour; 'venues' scopes to /v2/venues/
],

3. Bind it once in a service provider. FoursquareClient::factory() wires up the discovered HTTP client with the package's auth, version and endpoint plugins:

// app/Providers/FoursquareServiceProvider.php
use Jcroll\FoursquareApiClient\Client\FoursquareClient;

public function register(): void
{
    $this->app->singleton(FoursquareClient::class, fn () => FoursquareClient::factory(
        config('services.foursquare')
    ));
}

4. First use case — a venue search. This is what 90% of integrations use the package for: venues/search to enrich a location, address, or free-text place query.

use Jcroll\FoursquareApiClient\Client\FoursquareClient;

$response = app(FoursquareClient::class)->get('venues/search', [
    'near'  => 'Chicago, IL',
    'query' => 'coffee',
    'limit' => 10,
]);

$payload = json_decode((string) $response->getBody(), true);
$venues  = $payload['response']['venues'] ?? [];

Look first at src/Client/FoursquareClient.php (what factory() accepts and returns) and src/Plugin/ (auth, version, endpoint). Both are small and are the entire public surface.

Implementation Patterns

Wrap the client in a domain service — never inject it into controllers. The client returns a PSR-7 response with a Foursquare meta/response envelope; that shape should not leak into your application layer.

final class VenueSearch
{
    public function __construct(private FoursquareClient $client) {}

    public function nearby(float $lat, float $lng, string $query, int $limit = 10): array
    {
        $response = $this->client->get('venues/search', [
            'll'    => "{$lat},{$lng}",
            'query' => $query,
            'limit' => $limit,
            'intent' => 'browse',
        ]);

        return $this->unwrap($response);
    }

    private function unwrap($response): array
    {
        $body = json_decode((string) $response->getBody(), true);

        if (($body['meta']['code'] ?? 500) !== 200) {
            throw new FoursquareException($body['meta']['errorDetail'] ?? 'Unknown error');
        }

        return $body['response'];
    }
}

Cache aggressively. Foursquare quotas are per-hour and per-endpoint; venue data is effectively static on a request timescale. A short TTL turns a quota problem into a non-problem:

$venues = Cache::remember("fsq:search:{$key}", now()->addHours(6), fn () => $search->nearby(...));

Push bulk enrichment onto the queue. Bulk geocoding hundreds of records inline will burn your quota and block the request:

class EnrichVenue implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public int $tries = 3;
    public int $backoff = 30;

    public function handle(VenueSearch $search): void { /* ... */ }
}

Throttle the queue with Redis::throttle('foursquare')->allow(50)->every(60) rather than relying on retries to absorb 429s.

Use plugins rather than editing vendor code for cross-cutting concerns. The factory composes an HTTPlug PluginClient, so you can append RetryPlugin, LoggerPlugin, or your own Plugin implementation for request signing. If a package version doesn't expose plugin injection, bind your own HttpClient and pass it in, or wrap sendRequest().

Test against a mock client. Bind php-http/mock-client in the test container so FoursquareClient never touches the network:

$mock->addResponse(new Response(200, [], file_get_contents(base_path('tests/fixtures/venues.json'))));
$this->app->instance(ClientInterface::class, $mock);

Keep a response-fixture directory. Foursquare payloads are deep and vary by intent (checkin, browse, global, match); fixtures are the only sane way to write assertions against response.venues[].location.formattedAddress.

Gotchas and Tips

  • The package is unmaintained (last release Feb 2017). It pins HTTPlug/php-http v1 constraints, which conflict with newer packages in a Laravel 10/11 app. If Composer fights you, isolate it behind a ClientInterface you own and plan a migration; don't let its types spread across your codebase.
  • Foursquare signals errors inside a 200 response. meta.code is the real status code — a bad OAuth token, a rate limit, or a deprecated endpoint all come back as HTTP 200 with meta.code 401/429/400. Always check meta.code; the client will not throw for these.
  • v is mandatory. Omitting or malforming the version date (YYYYMMDD) returns a 400 "Invalid version" inside the envelope. Put it in config, never hardcode it in calls.
  • Credentials travel in the query string. The auth plugin appends client_id/client_secret to the URL, so they land in access logs, queue payload dumps, and exception traces. Scrub client_secret in logging/exception handlers, or move to a token-based plugin.
  • Body streams are single-read. (string) $response->getBody() consumes the stream. If you need the raw body for logging and parsing, rewind() first or capture the string once.
  • Discovery failures are cryptic. "No PSR-7 implementation found" or "No HTTP client found" means no php-http/client-implementation is installed — not that the package is misconfigured.
  • Legacy v2 endpoints are sunsetting. Foursquare's newer Places API uses a different host (places-api.foursquare.com), bearer service keys, and different paths/payloads. This client will not follow you there; the endpoint plugin is your extension point if you want to buy time by repointing the base URL while keeping the auth/version plumbing.
  • mode changes the base path. 'venues' scopes requests under /v2/venues/, so get('search', ...) becomes /v2/venues/search. Mixing modes and full paths produces double-segmented 404s — pick one convention per codebase.
  • No user OAuth support. Only two-legged client credentials are built in. Delegated (acting as a user) calls require your own HTTPlug plugin that adds oauth_token and strips the client secret.
  • Rate limits are per-endpoint, not global. Read X-RateLimit-Remaining from the response headers and expose it as a metric; a search loop that looks fine in dev can exhaust quota in minutes in production.
  • Extension points worth knowing: HTTPlug Plugin (retry, logging, auth), a swapped HttpClient implementation, and the factory config array. Everything else in the package is internal.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk