Skip to content

Activity API

Access commit, pull request, and issue activity across all monitored repositories.

List Activity

Get recent activity across all repositories.

GET /api/activity/

Query Parameters

Parameter Type Default Description
days integer 7 Number of days to look back
organization_id UUID - Filter by organization
repository_id UUID - Filter by repository
type string - Activity type: commit, pr, issue
limit integer 100 Max results
offset integer 0 Pagination offset

Response

{
  "items": [
    {
      "type": "commit",
      "repository": "my-org/awesome-project",
      "title": "Fix critical bug in authentication",
      "author": "jane@example.com",
      "timestamp": "2026-02-28T10:30:00Z",
      "url": "https://github.com/my-org/awesome-project/commit/abc123"
    },
    {
      "type": "pr",
      "repository": "my-org/awesome-project",
      "title": "Add OAuth2 support",
      "author": "johndoe",
      "timestamp": "2026-02-28T09:00:00Z",
      "url": "https://github.com/my-org/awesome-project/pull/42"
    }
  ],
  "total": 250,
  "limit": 100,
  "offset": 0
}

List Commits

Get commit activity.

GET /api/activity/commits

Query Parameters

Parameter Type Default Description
days integer 7 Number of days to look back
organization_id UUID - Filter by organization
repository_id UUID - Filter by repository
author_email string - Filter by author email
limit integer 100 Max results
offset integer 0 Pagination offset

Response

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440010",
      "sha": "abc123def456",
      "message": "Fix critical bug in authentication\n\nThis commit addresses issue #42 by...",
      "author_name": "Jane Doe",
      "author_email": "jane@example.com",
      "authored_at": "2026-01-14T09:12:00Z",
      "committed_at": "2026-02-28T10:30:00Z",
      "repository": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "awesome-project",
        "full_name": "my-org/awesome-project"
      },
      "stats": {
        "additions": 50,
        "deletions": 20,
        "files_changed": 3
      }
    }
  ],
  "total": 150,
  "limit": 100,
  "offset": 0
}

Two timestamps

A commit carries both, and they answer different questions:

  • authored_at: when the work was written. It belongs to the author, and a rebase or squash does not change it. Use it for attribution.
  • committed_at: when it landed. Use it for anything time-windowed.

They differ whenever history is rewritten, which is most of the time on a project that rebases or squash-merges: the example above is work written in January and merged at the end of February.

since and until filter on committed_at, and results are ordered by it, because that is also what the forges' own filters apply to. Bucketing by author date puts merged work into windows that already closed.

List Pull Requests

Get pull request activity.

GET /api/activity/pull-requests

Query Parameters

Parameter Type Default Description
days integer 30 Number of days to look back
organization_id UUID - Filter by organization
repository_id UUID - Filter by repository
state string - Filter by state: open, closed, merged
author string - Filter by author username
limit integer 100 Max results
offset integer 0 Pagination offset

Response

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440020",
      "number": 42,
      "title": "Add OAuth2 support",
      "body": "This PR adds OAuth2 authentication...",
      "state": "open",
      "author": "johndoe",
      "created_at": "2026-02-28T09:00:00Z",
      "updated_at": "2026-02-28T10:00:00Z",
      "merged_at": null,
      "repository": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "awesome-project",
        "full_name": "my-org/awesome-project"
      },
      "stats": {
        "commits": 5,
        "additions": 200,
        "deletions": 50,
        "changed_files": 8
      }
    }
  ],
  "total": 25,
  "limit": 100,
  "offset": 0
}

List Issues

Get issue activity.

GET /api/activity/issues

Query Parameters

Parameter Type Default Description
days integer 30 Number of days to look back
organization_id UUID - Filter by organization
repository_id UUID - Filter by repository
state string - Filter by state: open, closed
author string - Filter by author username
limit integer 100 Max results
offset integer 0 Pagination offset

Response

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440030",
      "number": 100,
      "title": "Bug: Login fails on mobile",
      "body": "When trying to login on mobile devices...",
      "state": "open",
      "author": "reporter",
      "labels": ["bug", "high-priority"],
      "created_at": "2026-02-26T10:00:00Z",
      "updated_at": "2026-02-28T08:00:00Z",
      "closed_at": null,
      "repository": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "awesome-project",
        "full_name": "my-org/awesome-project"
      }
    }
  ],
  "total": 10,
  "limit": 100,
  "offset": 0
}

Activity Summary

Get aggregated activity statistics.

GET /api/activity/summary

Query Parameters

Parameter Type Default Description
days integer 30 Period to analyze
organization_id UUID - Filter by organization

Response

{
  "period": {
    "start": "2026-01-29T00:00:00Z",
    "end": "2026-02-28T23:59:59Z",
    "days": 30
  },
  "commits": {
    "total": 500,
    "by_day": [
      {"date": "2026-02-28", "count": 25},
      {"date": "2026-02-27", "count": 30}
    ]
  },
  "pull_requests": {
    "opened": 50,
    "merged": 45,
    "closed": 5,
    "avg_merge_time_hours": 24
  },
  "issues": {
    "opened": 30,
    "closed": 25,
    "avg_close_time_hours": 48
  },
  "contributors": {
    "total": 25,
    "active": 18,
    "new": 3
  }
}

Example: Weekly Activity Report

import httpx
from datetime import datetime

client = httpx.Client(
    base_url="http://localhost:8000/api",
    headers={"Authorization": f"Bearer {token}"}
)

# Get activity summary for the past week
summary = client.get("/activity/summary", params={"days": 7}).json()

print(f"Weekly Activity Report ({summary['period']['start'][:10]} to {summary['period']['end'][:10]})")
print(f"=" * 60)
print(f"Commits: {summary['commits']['total']}")
print(f"Pull Requests: {summary['pull_requests']['opened']} opened, {summary['pull_requests']['merged']} merged")
print(f"Issues: {summary['issues']['opened']} opened, {summary['issues']['closed']} closed")
print(f"Active Contributors: {summary['contributors']['active']}")

# Get top contributors
commits = client.get("/activity/commits", params={"days": 7, "limit": 500}).json()

# Count commits per author
from collections import Counter
author_commits = Counter(c["author_email"] for c in commits["items"])

print(f"\nTop Contributors:")
for author, count in author_commits.most_common(5):
    print(f"  {author}: {count} commits")