Workspaces

Search code in a workspace

Changed on

Search code across repositories in a workspace.

Results are limited to the repositories that the calling user can access.

Supported authentication

The endpoint requires a credential that identifies the calling user. The following authentication modes are accepted:

  • Browser session cookie (Bitbucket web UI)
  • Atlassian API token (Basic auth using your email and a scoped API token that includes both repository:read and workspace:read)
  • OAuth 2.0 via Forge or an Atlassian app (3LO or 2LO, with both repository:read and workspace:read granted to the app)
  • Bitbucket repository, project, or workspace access tokens

Authentication modes that do not identify the user, including Atlassian Connect JWT, legacy Bitbucket OAuth not migrated to identity, app passwords, and API keys, are rejected with a 403.

Request body

Requires Content-Type: application/json. Anything else returns 415.

query.search_term is required. These fields are accepted:

  • query.search_term: non-blank, at most 1024 characters
  • query.filters
  • config.max_results: a JSON integer (a string or float is rejected), 1 to 100, default 50
  • config.search_mode: LEXICAL or omitted
  • request_id and pagination.next_cursor: see "Pagination"

Any other field is ignored.

{
  "query": {
    "search_term": "logr",
    "filters": { "attribute": "language", "eq": "go" }
  },
  "config": {
    "max_results": 10
  }
}

Search mode

This endpoint performs lexical code search only. config.search_mode is fixed to LEXICAL server-side, so callers may omit the field or set it explicitly to LEXICAL. Any other value returns a 400.

Filters

Use query.filters to narrow a search. For example, to search for logr only in Go files whose path matches cmd/*/main.go:

{
  "query": {
    "search_term": "logr",
    "filters": {
      "and": [
        { "attribute": "language", "eq": "go" },
        { "attribute": "path", "wildcard": "cmd/*/main.go" }
      ]
    }
  }
}

A filter names an attribute and exactly one operator:

  • eq matches a value, and works with every attribute. Values are not case-sensitive.
  • wildcard matches a pattern, and works only with path and repository. In a pattern, * matches any run of characters and ? matches one character. A pattern must match the whole value. On repository it ignores case, and on path it is case-sensitive.

Setting both eq and wildcard on one filter returns 400.

These attributes are supported:

  • repository: a repository slug, such as my-repo. Use a wildcard such as my-* to match every slug that starts with my-.
  • path: with eq, a value such as src/main matches any path that contains those folder or file names in that order, such as app/src/main/App.java. Each name must match in full. With wildcard, the pattern must match the whole file path, such as */main.go.
  • language: a language name, such as go, python, or javascript. To filter by file extension, use extension.
  • extension: a file extension without the dot, such as go or py.
  • project: a project key or name.
  • scm: the source control host of the repository.
  • branches: searches run on the default branch only. Set branches to "true" to search all indexed branches.
  • forks: by default, results include repositories that are forks. Set forks to "true" to get results from forks only, or to "false" to get results from repositories that are not forks.

branches only accepts the value "true". branches and forks only work when they are the whole of query.filters. You cannot combine them with other filters.

Combine filters with and, or, and not. Filters can nest up to 5 levels deep, and the workspace filter this endpoint adds uses one of them. That leaves 3 levels of and, or, or not around a filter. Deeper filters return 400. This filter uses all 3 levels:

{
  "and": [
    { "or": [
      { "not": { "attribute": "language", "eq": "python" } }
    ] },
    { "attribute": "extension", "eq": "go" }
  ]
}

Workspace scoping

The endpoint always applies a namespace = <workspace_slug> filter and passes the workspace's wrapped UUID as scope.workspace_ids. Callers must not include a namespace filter in query.filters (anywhere in the tree, including nested AND/OR/NOT). Doing so returns 400. A scope.workspace_ids value in the request body is ignored. The workspace in the URL always sets the scope.

Pagination

Pagination uses a cursor. To page beyond the first result set, include the id from the previous response as request_id, and the previous response's pagination.next_cursor as pagination.next_cursor. request_id is required whenever pagination is sent. Repeat until pagination.has_more is false.

On every page, query.search_term and query.filters must be the same as on the first page, including the order of items inside and/or. A different value returns 400. config.max_results may change between pages.

{
  "query": { "search_term": "logr" },
  "config": { "max_results": 10 },
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "pagination": { "next_cursor": "eyJlbnRyaWVzIjpbeyJsZXhpY2FsS2V5Ijoi..." }
}

Response

You can rely on these fields:

  • id, pagination.next_cursor, pagination.has_more
  • repositories[]: url, host, ns, name
  • matched_files[]: path, name, language, url, repositoryId, version (the commit hash), branch_or_tag_name, is_default_branch
  • matched_files[].matched_chunks[]: source_code, line_range, matched_line_numbers, matched_ranges
  • metadata.total_count: an approximate size, meaningful on page 1 only

branch_or_tag_name and is_default_branch are left out when not known, and language can be null.

Line numbers start at 1, and line_range.end is the last line of the chunk. Each matched_ranges entry is [line, start_column, end_column], where line is the line number in the file, the columns start at 0, and end_column is exclusive.

matched_line_numbers and matched_ranges mark where a search term appears as a whole word in the chunk. They can be empty even when the chunk matched.

Other fields can change or be removed without notice, so ignore any field not listed here. Treat ids and pagination.next_cursor as opaque.

Errors from this endpoint, including errors from the search backend, use the standard Bitbucket error envelope: {"type": "error", "error": {"message": ..., "code": ...}}. A backend error keeps its status code, except that a backend 5xx is returned as 502 Bad Gateway. The backend's own error code, when there is one, is in error.detail.upstream_code.

post/workspaces/{workspace}/codesearch

Request

  • Base URL
    https://api.bitbucket.org/2.0
  • URL
    https://api.bitbucket.org/2.0/workspaces/{workspace}/codesearch
  • Auth
    • OAuth 2
      Authorization code: https://bitbucket.org/site/oauth2/authorize
      Token URL: https://bitbucket.org/site/oauth2/access_token scopes: repository
    • or HTTP basic
    • or API key in header Authorization

Response

Search completed successfully. See the Response section for the fields you can rely on.

Changes