Skip to main content

Overview

The branches endpoint fetches all available branches for a GitHub repository along with branch metadata. This is useful for displaying branch selection UI or validating branch names before analysis.

Endpoint

POST /api/branches

Request

Headers

Content-Type
string
required
Must be application/json

Body Parameters

url
string
required
Full GitHub repository URLFormat: https://github.com/{owner}/{repo}Example: https://github.com/vercel/next.js

Example Request

curl -X POST https://repolyze.ossium.live/api/branches \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/vercel/next.js"}'

Response

Success Response (200)

branches
BranchInfo[]
Array of branch objects
defaultBranch
string
Name of the repository’s default branch

Response Headers

Content-Type: application/json
Cache-Control: public, s-maxage=300, stale-while-revalidate=600

Example Response

{
  "branches": [
    {
      "name": "canary",
      "commit": {
        "sha": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
        "url": "https://api.github.com/repos/vercel/next.js/commits/a1b2c3d4"
      },
      "protected": true,
      "isDefault": true
    },
    {
      "name": "main",
      "commit": {
        "sha": "b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1",
        "url": "https://api.github.com/repos/vercel/next.js/commits/b2c3d4e5"
      },
      "protected": true,
      "isDefault": false
    },
    {
      "name": "develop",
      "commit": {
        "sha": "c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2",
        "url": "https://api.github.com/repos/vercel/next.js/commits/c3d4e5f6"
      },
      "protected": false,
      "isDefault": false
    }
  ],
  "defaultBranch": "canary"
}

Error Responses

400 Bad Request

Returned when the request is invalid.
{
  "error": "URL is required"
}
or
{
  "error": "Invalid GitHub URL format. Expected: https://github.com/owner/repo"
}

404 Not Found

Returned when the repository doesn’t exist or is not accessible.
{
  "error": "Repository not found or not accessible"
}

429 Too Many Requests

Returned when rate limit is exceeded.
{
  "error": "Too many requests. Please try again later."
}
Response Headers:
Retry-After: 60

500 Internal Server Error

Returned when an unexpected error occurs.
{
  "error": "Failed to fetch branches"
}

Code Examples

JavaScript/TypeScript

interface BranchInfo {
  name: string;
  commit: {
    sha: string;
    url: string;
  };
  protected: boolean;
  isDefault: boolean;
}

interface BranchesResponse {
  branches: BranchInfo[];
  defaultBranch: string;
}

async function fetchBranches(repoUrl: string): Promise<BranchesResponse> {
  const response = await fetch('https://repolyze.ossium.live/api/branches', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ url: repoUrl })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error || 'Failed to fetch branches');
  }

  return await response.json();
}

// Usage
try {
  const { branches, defaultBranch } = await fetchBranches(
    'https://github.com/vercel/next.js'
  );
  
  console.log('Default branch:', defaultBranch);
  console.log('All branches:', branches.map(b => b.name));
  console.log('Protected branches:', branches.filter(b => b.protected).map(b => b.name));
} catch (error) {
  console.error('Error:', error.message);
}

React Hook Example

import { useState, useEffect } from 'react';

function useBranches(repoUrl: string | null) {
  const [branches, setBranches] = useState<BranchInfo[]>([]);
  const [defaultBranch, setDefaultBranch] = useState<string>('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!repoUrl) return;

    const fetchBranches = async () => {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch('/api/branches', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ url: repoUrl })
        });

        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.error);
        }

        const data = await response.json();
        setBranches(data.branches);
        setDefaultBranch(data.defaultBranch);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Unknown error');
      } finally {
        setLoading(false);
      }
    };

    fetchBranches();
  }, [repoUrl]);

  return { branches, defaultBranch, loading, error };
}

// Usage in component
function BranchSelector({ repoUrl }: { repoUrl: string }) {
  const { branches, defaultBranch, loading, error } = useBranches(repoUrl);
  const [selectedBranch, setSelectedBranch] = useState('');

  useEffect(() => {
    if (defaultBranch) {
      setSelectedBranch(defaultBranch);
    }
  }, [defaultBranch]);

  if (loading) return <div>Loading branches...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <select value={selectedBranch} onChange={(e) => setSelectedBranch(e.target.value)}>
      {branches.map((branch) => (
        <option key={branch.name} value={branch.name}>
          {branch.name}
          {branch.isDefault && ' (default)'}
          {branch.protected && ' 🔒'}
        </option>
      ))}
    </select>
  );
}

Python

import requests
from typing import List, Dict, Any

def fetch_branches(repo_url: str) -> Dict[str, Any]:
    """
    Fetch all branches for a GitHub repository.
    
    Args:
        repo_url: Full GitHub repository URL
        
    Returns:
        Dictionary with 'branches' and 'defaultBranch' keys
        
    Raises:
        Exception: If the request fails
    """
    endpoint = 'https://repolyze.ossium.live/api/branches'
    
    response = requests.post(
        endpoint,
        json={'url': repo_url},
        headers={'Content-Type': 'application/json'}
    )
    
    if response.status_code != 200:
        error_data = response.json()
        raise Exception(error_data.get('error', 'Failed to fetch branches'))
    
    return response.json()

# Usage
try:
    result = fetch_branches('https://github.com/vercel/next.js')
    branches = result['branches']
    default_branch = result['defaultBranch']
    
    print(f"Default branch: {default_branch}")
    print(f"Total branches: {len(branches)}")
    
    # Print protected branches
    protected = [b['name'] for b in branches if b['protected']]
    print(f"Protected branches: {', '.join(protected)}")
    
    # Print all branch names
    for branch in branches:
        prefix = '🔒' if branch['protected'] else '  '
        suffix = ' (default)' if branch['isDefault'] else ''
        print(f"{prefix} {branch['name']}{suffix}")
        
except Exception as e:
    print(f"Error: {e}")

cURL

# Basic request
curl -X POST https://repolyze.ossium.live/api/branches \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/vercel/next.js"}'

# Pretty print with jq
curl -X POST https://repolyze.ossium.live/api/branches \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/vercel/next.js"}' \
  | jq '.'

# Get only branch names
curl -s -X POST https://repolyze.ossium.live/api/branches \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/vercel/next.js"}' \
  | jq -r '.branches[].name'

# Get default branch
curl -s -X POST https://repolyze.ossium.live/api/branches \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/vercel/next.js"}' \
  | jq -r '.defaultBranch'

Caching

The branches endpoint implements HTTP caching:
  • Cache-Control: public, s-maxage=300, stale-while-revalidate=600
  • Duration: 5 minutes (300 seconds)
  • Stale-while-revalidate: 10 minutes (600 seconds)
This means:
  1. Fresh responses are served from cache for 5 minutes
  2. Stale responses can be served for up to 10 additional minutes while revalidating in the background
  3. Total potential cache duration: 15 minutes

Rate Limiting

The branches endpoint is subject to the same rate limits as other API endpoints:
  • Per-minute limit: 10 requests per IP
  • Window: 60-second rolling window
  • Response code: 429 Too Many Requests
  • Retry-After header: 60 seconds
See API Overview - Rate Limits for details.

Use Cases

1. Branch Selection UI

Fetch branches before analysis to allow users to select which branch to analyze:
// Step 1: Fetch branches
const { branches, defaultBranch } = await fetchBranches(repoUrl);

// Step 2: Display branch selector
// User selects a branch

// Step 3: Analyze selected branch
const analysis = await analyzeRepository(repoUrl, selectedBranch);

2. Branch Validation

Validate that a branch exists before attempting analysis:
async function analyzeWithValidation(repoUrl: string, branchName: string) {
  const { branches } = await fetchBranches(repoUrl);
  
  const branchExists = branches.some(b => b.name === branchName);
  
  if (!branchExists) {
    throw new Error(`Branch "${branchName}" not found`);
  }
  
  return analyzeRepository(repoUrl, branchName);
}

3. Default Branch Detection

Use the default branch when no specific branch is requested:
async function analyzeDefaultBranch(repoUrl: string) {
  const { defaultBranch } = await fetchBranches(repoUrl);
  return analyzeRepository(repoUrl, defaultBranch);
}

4. Protected Branch Filtering

Filter and display only protected branches:
const { branches } = await fetchBranches(repoUrl);
const protectedBranches = branches.filter(b => b.protected);
console.log('Protected branches:', protectedBranches.map(b => b.name));

Best Practices

Cache locally: Store branch data in your application state to avoid redundant requests when users navigate between views.
Handle errors gracefully: Always provide fallback UI when branch fetching fails. The default branch from repository metadata can be used as a fallback.
Pre-fetch branches: Fetch branches immediately after URL validation but before the user needs to select a branch. This provides instant branch selection UI.
Don’t poll unnecessarily: Branches don’t change frequently. Rely on the HTTP cache headers and avoid polling for updates.

Build docs developers (and LLMs) love