bitbucket/client
A PHP client for the Bitbucket REST API, giving Laravel and plain PHP apps programmatic access to repositories, pull requests, webhooks, users, and teams. Supports OAuth and access-token authentication over PSR-18 HTTP clients.
Install the client and authenticate before touching endpoint objects. Version 5.1.0 adds PHP 8.5 support, so it is safe on current runtimes; pin a constraint if you support older PHP:
composer require bitbucket/client:"^5.1"
use Bitbucket\Client;
$client = new Client();
// Preferred for long-lived integrations: OAuth access token.
$client->authenticate(Client::AUTH_OAUTH, config('services.bitbucket.token'));
// App-password/basic-auth style:
// $client->authenticate(
// Client::AUTH_HTTP_PASSWORD,
// config('services.bitbucket.username'),
// config('services.bitbucket.password')
// );
Register it once in Laravel's container rather than constructing it ad hoc:
$this->app->singleton(Client::class, function () {
$client = new Client();
$client->authenticate(Client::AUTH_OAUTH, config('services.bitbucket.token'));
return $client;
});
A good first use case is a PR dashboard or scheduled review reminder: list open pull requests for a repository. Note the explicit workspace()->repository() chain — the top-level pullRequests() pass-through was deprecated in 5.1.0, so start on the supported path now:
$pullRequests = $client->pullRequests()
->workspace($workspace)
->repository($repository)
->list(['state' => 'OPEN']);
foreach ($pullRequests['values'] ?? [] as $pr) {
echo $pr['id'].' '.$pr['title'].PHP_EOL;
}
Look first at the README, src/Client.php, and the relevant class under src/Api. The package is a thin fluent wrapper over Bitbucket Cloud REST 2.0, so the endpoint class usually maps closely to the REST resource. After listing PRs, the next natural steps are fetching a single PR, posting a comment, creating a PR, or checking commit/build statuses. The 5.1.0 release notes and the newly documented "Bitbucket API migration paths" are worth skimming early, because they tell you which fluent methods are on borrowed time.
Wrap the client in a small application service. Do not let fluent Bitbucket calls spread through controllers and jobs. A wrapper gives you one place for auth assumptions, pagination, retries, logging, and response normalization — and one place to swap a deprecated method when the next release lands.
final class BitbucketPullRequests
{
public function __construct(private Client $client)
{
}
public function open(string $workspace, string $repository): array
{
return $this->client->pullRequests()
->workspace($workspace)
->repository($repository)
->list(['state' => 'OPEN']);
}
public function create(string $workspace, string $repository, array $payload): array
{
return $this->client->pullRequests()
->workspace($workspace)
->repository($repository)
->create($payload);
}
}
Use it from Artisan commands and queued jobs. Typical day-to-day uses are PR reminders, merge checks, issue synchronization, release automation, repository provisioning, and CI/CD gates. Read-only jobs can run on a schedule; write operations such as comments, approvals, and PR creation should generally run in queued jobs with explicit retry/backoff.
Centralize pagination on the package's own pager. Bitbucket list endpoints return a values array plus a next link, and the package ships ResultPager. 5.1.0 fixed partial-response fields handling and previous-page navigation, so if you built a workaround for those two bugs, re-evaluate it against the new pager before keeping the code. Still wrap pagination in one helper so a future pager change touches one file. Cache read-only metadata such as workspace, repository, and user lookups with short TTLs.
Discover workspaces instead of hardcoding them. The new current-user-workspaces endpoint (and its fix in 5.1.0) makes multi-tenant setup practical: enumerate the workspaces a token can see, then let configuration or an admin UI select one, rather than pasting slugs into .env.
Use the new permission and branch-model APIs as validation steps. Project permissions config and repository permissions config APIs let an admin/integration flow read and set permission schemes; the effective branching model endpoint lets you resolve which model actually applies to a repository before you attempt a branch creation or a merge gate. Checking the effective model beats guessing from repository settings, especially where project-level config overrides.
Treat pipeline config subresources as infrastructure-as-code. The new repository pipelines config subresources mean you can inspect and update pipeline enablement and variables from the app instead of clicking through the UI — useful for onboarding a repository or rotating a deployment variable. Guard these writes: a bad pipeline variable breaks every subsequent build.
Use the workspace PR endpoint for "my work" views. The workspace pull requests endpoint for selected users supports a personal dashboard ("PRs I authored/review across the workspace") without fanning out one request per repository. Combine it with state=OPEN and the pager.
Prefer webhooks for change detection, and this client for enrichment. For example, receive a pull-request webhook, then use the client to fetch the PR details, changed files, comments, or statuses needed by your workflow. Avoid aggressive polling of Bitbucket APIs.
Treat responses as raw Bitbucket payloads. The package is transport-oriented and generally returns arrays, not strongly typed DTOs. Validate expected keys at your boundary and map into your own domain objects if the data is used widely.
Test against fixtures, not live Bitbucket. Mock your wrapper service in feature tests, or inject a mocked HTTP client if the package exposes that extension point in your installed version. Keep recorded Bitbucket JSON fixtures for shape-sensitive tests.
$client->pullRequests()->workspace(...)->repository(...) is the durable shape; $client->pullRequests($workspace, $repo)-style shortcuts are the ones being retired. Writing the explicit chain now avoids a migration later.429 responses and Retry-After headers. Add backoff and jitter in queued jobs; do not retry immediately in a tight loop.ResultPager behavior for fields/partial responses and previous-page navigation — re-run pagination tests rather than assuming identical output.fields partial responses cut payloads but can bite you. If you request a subset of fields, your code must tolerate missing keys; the 5.1.0 pager fix improves traversal but does not populate fields you did not ask for.404 can mean "not found" or "not authorized." Bitbucket often hides private resources behind a 404. Log workspace/repository/PR identifiers and the authenticated principal when debugging.state=OPEN where they exist, and build complex queries with explicit escaping.How can I help you explore Laravel packages today?