Bitbucket Unofficial SDK
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
- Key features
- Installation
- Requirements
- Usage
- Configuration
- Origin
- Contributing
- Open items
- License
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
Pageandpaginate(). - 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:
- A provider callable.
- An explicit string argument.
- 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.
Async client
AsyncBitbucketClient mirrors the sync client one-for-one — same
email/api_token/access_token/options, same workspace(), default_workspace(),
.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
- Branch restrictions, branching model, projects, workspaces, and pipelines
are not yet modeled — see
docs/api/endpoint-coverage.mdfor the full endpoint matrix anddocs/api/roadmap.mdfor the phased plan to full API parity. - A handful of
Commitsoperations from the original Phase 2 estimate (a "file-conflicts" endpoint and up to 2 others) couldn't be confidently mapped to a real spec path without re-checking the live spec — see the note indocs/api/endpoint-coverage.md'sCommitssection.
License
MIT — see LICENSE.
Metadata
Release files for bitbucket-unofficial-sdk 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bitbucket_unofficial_sdk-0.6.0.tar.gz | 156.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bitbucket_unofficial_sdk-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 229.4 kB
Release files / bitbucket_unofficial_sdk-0.6.0.tar.gz
| Download URL | bitbucket_unofficial_sdk-0.6.0.tar.gz |
|---|---|
| Size | 156.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ce53d3506e97d00b50f7728242eb7fdb05afa1514af1b8b1bb666e2499ad2ead
|
|
BLAKE2b-256 checksum How to use checksums |
18d3ee2b7c0681b4ce4221be6c1bf34763f4fffbf95035887d1c491f06b2c41b
|
| 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 logRelease files / bitbucket_unofficial_sdk-0.6.0-py3-none-any.whl
| Download URL | bitbucket_unofficial_sdk-0.6.0-py3-none-any.whl |
|---|---|
| Size | 73.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
41a9adb7a1f4fc1189ebe15783536d9e2828eee3053b0d056b94d2c17d5904eb
|
|
BLAKE2b-256 checksum How to use checksums |
c870de839e588c6adf56fa74d659b0a5c3aea8078a7b1b68d52e7352bfe6b6d4
|
| 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