gandung/tokopedia-php-sdk
A PHP SDK for integrating Tokopedia's API into Laravel or plain PHP apps, offering convenient wrappers for authentication and common seller endpoints so you can manage products, orders, and shop data with less boilerplate.
The package is a framework-agnostic Composer library — it does not ship a Laravel service provider or config file, so treat it as a thin client you wire yourself.
composer require gandung/tokopedia-php-sdk
Where to look first
vendor/gandung/tokopedia-php-sdk/composer.json — check require (PHP and Guzzle versions). The 2021-09-01 release predates PHP 8.2/Laravel 10+, so confirm it installs cleanly before writing any code.vendor/gandung/tokopedia-php-sdk/src/ — identify the main client class and namespace (typically Gandung\Tokopedia\...). Use composer show gandung/tokopedia-php-sdk and grep -r "function " src/ to map the public methods.README.md in the repo — the constructor signature (client ID / client secret / token) and the base URL it targets.Get credentials
Create an app in the Tokopedia Seller dashboard (Open API / Developer section) to obtain a Client ID and Client Secret. Tokopedia issues short-lived bearer tokens via its accounts endpoint; the SDK either handles that for you or expects you to pass a token in.
First use case — read your shop's catalog
use Gandung\Tokopedia\Tokopedia; // confirm the real class name in vendor/
$client = new Tokopedia(config('services.tokopedia.client_id'), config('services.tokopedia.client_secret'));
$products = $client->getProducts($shopId, ['page' => 1, 'per_page' => 20]);
The lowest-risk first integration is a read-only catalog sync: pull products/orders into your database, render them in a Laravel resource or dashboard, and prove auth + error handling before adding write calls.
Bind as a singleton and centralise config
// config/services.php
'tokopedia' => [
'client_id' => env('TOKOPEDIA_CLIENT_ID'),
'client_secret' => env('TOKOPEDIA_CLIENT_SECRET'),
'shop_id' => env('TOKOPEDIA_SHOP_ID'),
'base_url' => env('TOKOPEDIA_BASE_URL', 'https://fs.tokopedia.net'),
],
// app/Providers/AppServiceProvider.php
$this->app->singleton(Tokopedia::class, fn () => new Tokopedia(
config('services.tokopedia.client_id'),
config('services.tokopedia.client_secret'),
));
Wrap it in your own service, don't scatter SDK calls
namespace App\Services;
use Gandung\Tokopedia\Tokopedia;
class TokopediaCatalog
{
public function __construct(private Tokopedia $client) {}
public function firstPageOfProducts(int $shopId): array
{
return $this->client->getProducts($shopId, ['page' => 1, 'per_page' => 50]);
}
}
This gives you one place to swap the SDK out (see Gotchas) without touching controllers/jobs.
Token caching pattern — if the SDK re-authenticates on every call, cache the token yourself:
$token = Cache::remember('tokopedia:token', now()->addMinutes(50), function () {
return $this->client->requestToken(); // check the actual method name
});
Queue long-running work
Catalog and order syncs paginate. Push them to jobs so HTTP timeouts don't hit the request cycle:
SyncTokopediaProducts::dispatch($shopId)->onQueue('tokopedia');
Inside the job, app(Tokopedia::class) resolves the singleton; loop pages with usleep() between requests to stay under Tokopedia's rate limits.
Use a facade for ergonomics
// config/app.php (Laravel 10) or bootstrap/app.php aliases
'aliases' => ['Tokopedia' => App\Facades\Tokopedia::class],
Create App\Facades\Tokopedia extending Illuminate\Support\Facades\Facade and returning Tokopedia::class. This keeps call sites readable and avoids constructor noise.
Integration tip: for endpoints the SDK doesn't cover, don't abandon it — keep a tokopedia Laravel HTTP client with the same token so you get Http::fake() testability alongside the SDK's coverage.
composer require fails on PHP 8.2+/Laravel 11, check the require block — you may need --ignore-platform-reqs locally, or a fork with bumped Guzzle/PHP constraints. Don't ship --ignore-platform-reqs to production.{"error": {"message": ...}} with non-2xx codes. If the SDK only returns an array, inspect header.status/HTTP status — don't assume a missing key means "no products."retry(3, 1000)) or usleep(200_000) between pages. Tokopedia's documented limits are per-app, so one aggressive sync can starve your other integrations.shop_id, product_id, order_id as bigInteger/string, never int(11) assumptions, and normalise dates into Carbon at the boundary.Http::fake():
$mock = new \GuzzleHttp\Handler\MockHandler([new \GuzzleHttp\Psr7\Response(200, [], json_encode($fixture))]);
$client = new Tokopedia(..., ['handler' => \GuzzleHttp\HandlerStack::create($mock)]);
If the constructor doesn't accept a handler, test your TokopediaCatalog wrapper instead and keep the wrapper's methods small.HandlerStack middleware (for logging raw requests/responses and retries) injected into the SDK if it accepts a config array. Log correlation IDs from Tokopedia's response headers so support tickets are debuggable..env only, never in config/services.php defaults, and add TOKOPEDIA_* to .env.example. If you later fork the package, keep the token-fetching code out of version control diffs.How can I help you explore Laravel packages today?