Skip to main content

Bitbucket Unofficial SDK

CI PyPI Python 3.14+ License: MIT Topics

Unofficial. This project is not affiliated with, endorsed by, or supported by Atlassian. "Bitbucket" is a trademark of Atlassian. Use at your own risk against the Bitbucket Cloud REST API.

Typed Python SDK for the Bitbucket Cloud REST API: repository core (CRUD, forks, hooks, permissions), refs (branches/tags), source, commits, downloads, and the full pull-request surface (comments, statuses, tasks, merging, default reviewers). Ships in two flavours — a sync client (BitbucketClient) backed by httpx.Client and an async client (AsyncBitbucketClient) backed by httpx.AsyncClient — with the same features and credential contract in both. Every response is a validated, frozen pydantic model with attribute access and real Python types — not a raw dict.

See docs/architecture/ for how the client is layered.

Table of contents

About

Bitbucket Cloud's REST API returns loosely shaped JSON and paginates by following next URLs. This SDK wraps it so a caller works with typed objects instead: one client per workspace or repository, lazy pagination, and a single credential contract shared by the sync and async clients.

Key features

  • Sync (BitbucketClient) and async (AsyncBitbucketClient) clients with the same endpoints.
  • Validated, frozen pydantic models for every response.
  • Lazy pagination through Page and paginate().
  • Retry and error mapping built into the transport.
  • Credentials read from arguments or environment and kept out of logs.

Installation

Install it from PyPI:

uv add bitbucket-unofficial-sdk

or with pip install bitbucket-unofficial-sdk. To try an unreleased commit, install it from git instead:

uv add "bitbucket-unofficial-sdk @ git+https://github.com/gajaguar/bitbucket-sdk"

Requirements

  • Python 3.14 or later. The floor is deliberate and can change.
  • Either an Atlassian email and API token, or a Bitbucket access token — see Authentication

Usage

List a repository's open pull requests:

from bitbucket import BitbucketClient

with BitbucketClient() as client:
    repository = client.default_workspace().repository("my-repo")

    for pull_request in repository.pull_requests.list(state="OPEN"):
        print(pull_request.id, pull_request.title)

Every list() method returns a lazy iterator that follows Bitbucket's next cursor; iterate it directly, wrap it in list(...), or call list_page(cursor=...) to manage pagination yourself. More examples — commenting, merging and waiting for the result, creating a repository — are in docs/api/recipes.md. The layout of the repository is in docs/architecture/project-layout.md.

Authentication

from bitbucket import BitbucketClient

# reads ATLASSIAN_USER_EMAIL and ATLASSIAN_API_TOKEN from the environment
client = BitbucketClient()

# or pass the email and API token explicitly
client = BitbucketClient(email="...", api_token="...")

# api_token accepts a zero-argument callable, invoked lazily on every request
client = BitbucketClient(email="...", api_token=lambda: keychain.current_token())

# access_token sends Authorization: Bearer and does not require an email
client = BitbucketClient(access_token="...")

# access_token also accepts a rotating or externally-managed provider
client = BitbucketClient(access_token=lambda: token_store.current_token())

The SDK accepts either basic credentials (email plus API token) or a bearer access token. Within each credential kind, the first source that has a value wins:

  1. A provider callable.
  2. An explicit string argument.
  3. An environment variable.

Between the two kinds, an explicit argument or provider beats the other kind's environment variable. If both kinds are explicit, or both are available only through the environment, the SDK raises ConfigurationError because the request is ambiguous. The resolver only reads or warns for the kind that wins.

ATLASSIAN_API_KEY is the former name of ATLASSIAN_API_TOKEN. It still works, with a DeprecationWarning, when ATLASSIAN_API_TOKEN is not set and basic credentials win.

Getting a credential

For an API token, open your profile menu and choose Account settings. Open the Security tab and choose Create and manage API tokens. Choose Create API token with scopes, select Bitbucket and the scopes your code needs, then copy the token. Atlassian shows it only once. API tokens are bound to your account and expire on the date you choose. Atlassian removed app passwords on 2026-07-28, so they no longer work.

For a bearer token, create a repository, project, or workspace access token in its Access tokens settings, or obtain an OAuth access token through the application's OAuth flow. The SDK uses the resulting token but does not obtain or refresh it.

What the SDK does not do

The SDK only reads the sources listed above. It has no OS keyring or keychain integration, no password-manager support, no OAuth flow, and no interactive prompts — those are application-level concerns for whatever consumes this SDK. The application is responsible for obtaining, refreshing and storing bearer tokens.

Protecting the token

A Bitbucket token grants the access of its scopes to everything it can reach. Never commit one, and rotate it immediately if it is exposed. The SDK never logs headers or its configuration, and credential values are excluded from repr(ClientConfig).

The full contract is in docs/sdk/credential-contract.md, and the values that belong to Bitbucket are in docs/sdk/credentials.md.

Users, SSH keys and GPG keys

client.user acts for the authenticated user (me(), emails(), email(address)), while client.users(selected_user) returns a handle for any user, by Atlassian account id or {uuid}:

user = client.users("{ed08f5e1-605b-4f4a-aee4-6c97628a673e}")
profile = user.get()

for key in user.ssh_keys.list():
    print(key.label, key.fingerprint)

user.ssh_keys.create(SshKeyCreate(key="ssh-ed25519 AAAA...", label="Work"), expires_on="2027-01-01")
user.gpg_keys.delete("A1B2C3D4E5F6A7B8")

ws.search, client.users(selected_user).search and client.teams(username).search search code across an account's repositories. The query is required and uses the UI's syntax; code search must be turned on at https://bitbucket.org/search, and Bitbucket deprecates these routes on 2026-11-01:

for result in client.workspace("acme").search.code("foo repo:demo", pagelen=50):
    print(result.file.path if result.file else None, result.content_match_count)

Async client

AsyncBitbucketClient mirrors the sync client one-for-one — same email/api_token/access_token/options, same workspace(), default_workspace(), users(), teams(), .user, same resource tree (.pull_requests, .refs, .source, .commits, ...), and the same merge_and_wait polling helper. Single-shot methods are async def; auto-paginating methods return AsyncIterator.

from bitbucket import AsyncBitbucketClient
from bitbucket import MergeParameters

async with AsyncBitbucketClient() as client:
    repository = client.default_workspace().repository("my-repo")

    async for pull_request in repository.pull_requests.list(state="OPEN"):
        print(pull_request.id, pull_request.title)

    diff = await repository.pull_requests.diff(pull_request.id)

    status = await repository.pull_requests.merge_and_wait(
        pull_request.id,
        MergeParameters(merge_strategy="squash"),
    )
    print(status.task_status)

BasicAuth, BearerAuth and the credential-resolution rules (provider, env vars, deprecated ATLASSIAN_API_KEY) are shared between the sync and async clients, so the credential tests in docs/sdk/credential-tests.md apply to both.

Configuration

Variable Where it's read Default Description
ATLASSIAN_USER_EMAIL BitbucketClient() none Email of the Atlassian account, used for basic auth.
ATLASSIAN_API_TOKEN BitbucketClient() none API token, used for basic auth.
ATLASSIAN_API_KEY BitbucketClient() none Deprecated name of ATLASSIAN_API_TOKEN; emits a warning.
BITBUCKET_ACCESS_TOKEN BitbucketClient() none Bearer access token; no email is required.
BITBUCKET_WORKSPACE BitbucketClient.default_workspace() none Workspace slug used by default_workspace().

The names are exported as EMAIL_ENV_VAR, API_TOKEN_ENV_VAR, ACCESS_TOKEN_ENV_VAR and WORKSPACE_ENV_VAR, so an application does not have to repeat the strings.

Origin

Extracted from a larger internal toolkit's Bitbucket provider module, which had grown the whole project's maintenance surface. That toolkit keeps the provider-neutral pull-request seam (models, protocol, registry) and review-workflow logic (comment filtering and threading, reviewer-queue aggregation); this SDK carries only the Bitbucket wire client.

Contributing

See CONTRIBUTING.md.

Open items

License

MIT — see LICENSE.

Metadata

Release files for bitbucket-unofficial-sdk 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bitbucket-unofficial-sdk 0.9.0
File Size Uploaded
bitbucket_unofficial_sdk-0.9.0.tar.gz 227.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bitbucket-unofficial-sdk 0.9.0
File Interpreter ABI Platform
bitbucket_unofficial_sdk-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 354.5 kB

Release files / bitbucket_unofficial_sdk-0.9.0.tar.gz

Download URL bitbucket_unofficial_sdk-0.9.0.tar.gz
Size 227.1 kB
Tags Source
SHA-256 checksum
How to use checksums
e975e392a92735777c45ee6d52bf3d93b10239451f0162bc24557047ffe6ab7b
BLAKE2b-256 checksum
How to use checksums
08455717579424cd301519f37bfe9970640913ab863ef9186cfa4eb4bffa2578
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / bitbucket_unofficial_sdk-0.9.0-py3-none-any.whl

Download URL bitbucket_unofficial_sdk-0.9.0-py3-none-any.whl
Size 127.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fc631b706c375f0400c117d8c615f7eacae983ec82fce5e5b5f241faa8af1774
BLAKE2b-256 checksum
How to use checksums
237c63ccf118e103b942464c159d6c517edf212372e22a93d61cb9058decd181
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.4.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page