Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Getting 401 error when accessing bitbucket api

wailoktam
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
July 22, 2025

I want to retrieve all pull request ids from a repository but I get stuck with log in.

I have read the following

Getting 401 error for a valid Bitbucket user account, when trying to access API from Jira cloud

Not sure what account I get. I dont know the distinction between service account and user account. I signed up with bitbucket ages ago . 

Below is my code, copied from answer of AI. 

 

import requests
import os
from typing import List, Optional, Dict, Any


def get_all_pr_ids(
workspace: str,
repo_slug: str,
username: str,
app_password: str,
state: Optional[str] = None # 'OPEN', 'MERGED', 'DECLINED', 'SUPERSEDED'
) -> Optional[List[int]]:
"""
Retrieves the IDs of all pull requests in a Bitbucket Cloud repository.

Args:
workspace (str): The Bitbucket workspace ID (e.g., 'your-company-workspace').
repo_slug (str): The repository slug (e.g., 'my-awesome-repo').
username (str): Your Bitbucket username (email or username).
app_password (str): Your Bitbucket app password with 'pullrequests:read' permission.
state (Optional[str]): Filter PRs by state. Can be 'OPEN', 'MERGED', 'DECLINED', 'SUPERSEDED'.
If None, retrieves all PRs regardless of state.

Returns:
Optional[List[int]]: A list of pull request IDs, or None if an error occurs.
"""
base_url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repo_slug}/pull-requests"
# base_url = f"https://bitbucket.org/{workspace}/{repo_slug}/pull-requests"
params: Dict[str, Any] = {'pagelen': 100} # Fetch 100 PRs per page (max is 100)
if state:
params['state'] = state.upper() # Ensure state is uppercase for API

all_pr_ids: List[int] = []
next_page_url: Optional[str] = base_url

while next_page_url:
print(f"Fetching PRs from: {next_page_url}")
try:
response = requests.get(next_page_url, auth=(username, app_password),
params=params if next_page_url == base_url else None)
response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)

data = response.json()

for pr in data.get('values', []):
all_pr_ids.append(pr['id'])

next_page_url = data.get('next') # Get URL for the next page, if any

# For subsequent pages, the 'next' URL already contains the necessary parameters,
# so we don't need to pass 'params' again. Reset params for the loop.
params = {}

except requests.exceptions.HTTPError as e:
print(f"HTTP error occurred: {e}")
print(f"Response content: {e.response.text}")
if e.response.status_code == 404:
print(f"Repository {workspace}/{repo_slug} not found or no pull requests.")
elif e.response.status_code == 401:
print("Authentication failed. Check your username and app password.")
return None
except requests.exceptions.ConnectionError as e:
print(f"Connection error occurred: {e}")
return None
except requests.exceptions.Timeout as e:
print(f"Timeout error occurred: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"An unexpected error occurred: {e}")
return None
except Exception as e:
print(f"An unexpected error occurred during JSON parsing or data access: {e}")
return None

return all_pr_ids


if __name__ == "__main__":
# --- Configuration (Replace with your actual details) ---
# It's highly recommended to use environment variables for sensitive information
# rather than hardcoding them directly in the script.

BITBUCKET_USERNAME = os.getenv("BITBUCKET_USERNAME", "correctid")
BITBUCKET_APP_PASSWORD = os.getenv("BITBUCKET_APP_PASSWORD", "correctpw")
BITBUCKET_WORKSPACE = os.getenv("BITBUCKET_WORKSPACE", "correctworkspace") # e.g., 'my-company'
BITBUCKET_REPO_SLUG = os.getenv("BITBUCKET_REPO_SLUG", "correctrepo") # e.g., 'project-x'

# Optional: Filter by PR state. Uncomment and set to one of:
# 'OPEN', 'MERGED', 'DECLINED', 'SUPERSEDED'
PR_STATE_FILTER: Optional[str] = None # Set to 'OPEN' to get only open PRs, etc.

# --- Check if default values are still present ---
if "your_bitbucket_username" in BITBUCKET_USERNAME or \
"your_bitbucket_app_password" in BITBUCKET_APP_PASSWORD or \
"your-workspace-id" in BITBUCKET_WORKSPACE or \
"your-repository-slug" in BITBUCKET_REPO_SLUG:
print(
"WARNING: Please update the placeholder values for BITBUCKET_USERNAME, BITBUCKET_APP_PASSWORD, BITBUCKET_WORKSPACE, and BITBUCKET_REPO_SLUG.")
print("You can set them as environment variables or directly in the script for testing.")
# For a real scenario, you'd stop here.
# exit(1) # Uncomment this to force exit if not configured

print(f"Retrieving all pull request IDs for {BITBUCKET_WORKSPACE}/{BITBUCKET_REPO_SLUG}...")
if PR_STATE_FILTER:
print(f"Filtering by state: {PR_STATE_FILTER}")

pr_ids = get_all_pr_ids(
workspace=BITBUCKET_WORKSPACE,
repo_slug=BITBUCKET_REPO_SLUG,
username=BITBUCKET_USERNAME,
app_password=BITBUCKET_APP_PASSWORD,
state=PR_STATE_FILTER
)

if pr_ids is not None:
if pr_ids:
print(f"\nFound {len(pr_ids)} pull request(s):")
for pr_id in pr_ids:
print(f"- PR ID: {pr_id}")
else:
print("\nNo pull requests found for the specified criteria in this repository.")
else:
print("\nFailed to retrieve pull request IDs due to an error.")

The original base_url ends with pullrequests without a hyphen. No difference whether I add back a hypen or not

 

curl -u correctid:correctpw https://api.bitbucket.org/2.0/repositories/correctsworkpace

gives nothing back. 

 

Can anyone tell me what is wrong?

2 answers

0 votes
Theodora Boudale
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
July 23, 2025

Hi @wailoktam and welcome to the community!

While basic authentication with username and app password still works for our APIs, we are deprecating app app passwords and replacing them with API tokens:

  • On September 9, 2025, the creation of app passwords will be discontinued.
  • On June 9, 2026, any existing app passwords will become inactive.

So, if you want to use Basic authentication, I recommend switching to email and API token (email instead of username and API token instead of app password).

You can then check if they work by running:

curl -u {email}:{API_TOKEN} --request GET \
--url 'https://api.bitbucket.org/2.0/repositories/{workspace_id}/{repo_slug}/pullrequests' \
--header 'Accept: application/json'

Replace the placeholders (including curly brackets) with your values.

If the API call with curl succeeds and returns what you expect, then you'll need to look into your script.

If there's an issue with the curl command, please add the -v option to the curl command for verbose output, and let me know what status code the command returns and any errors.

The service account mentioned in the post you linked is just a term people use for a Bitbucket account they create only for CI/CD purposes. It's not a separate type of account.

Kind regards,
Theodora

0 votes
Aron Gombas _Midori_
Community Champion
July 23, 2025

It seems that you are using BASIC auth.

Not sure, but I think it will not work with your email address and password. It should work with your email address and a valid API token though!

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PERMISSIONS LEVEL
Product Admin Site Admin
TAGS
AUG Leaders

Atlassian Community Events