# Explain a line

> Why a line of a file is the way it is: the commit that last changed it (by blame, at ref or the default branch), the merged pull request it arrived in, that pull request's issue, the decision records on the pull request, and the session entries recorded around that commit (what was said and the tool calls that touched the file, at most eight). pull, issue, decisions and sessions are empty when the commit did not arrive through a pull request.

<div class="g1t-endpoint"><span class="g1t-method" data-method="get">GET</span><code>/repos/{owner}/{name}/why</code></div>

`ref` reads the file at a branch, tag or commit. See [sessions and why-blame](/guides/why-blame/#why-over-the-api).

- **Authentication:** Optional. Public data can be read without a token; send one to see what is private.
- **MCP tool:** [`repository`](/reference/mcp/#repository) with `action` `why`, and the same inputs
- **Scope:** An access token needs [`code:read`](/guides/authentication/#scopes).

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | Yes | The workspace that owns the repository. |
| `name` | string | Yes | The repository's name. |

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `path` | string | Yes | The file, from the repository's root, such as "src/main.rs". |
| `line` | integer | Yes | The line, counted from 1. |
| `ref` | string | No | A branch, tag or commit. The default branch if not given. |

## Example request

```sh
curl "https://api.g1t.sh/repos/flagon-io/hello/why?path=src%2Fconfig.rs&line=42" \
  -H "Authorization: Bearer $G1T_TOKEN"
```

## Example response

A successful request answers `200` with:

```json
{
  "path": "src/config.rs",
  "line": 42,
  "commit": {
    "hash": "7d3e9a1c5b2f4e6a8c0d2e4f6a8b0c2d4e6f8a0b",
    "tree_hash": "c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0",
    "message": "Read retry_limit, as #12 names it",
    "author": {
      "name": "Ana Lima",
      "email": "ana@example.com"
    },
    "parents": [
      "4be1c0d9a2f3e4b5c6d7e8f90a1b2c3d4e5f6a7b"
    ],
    "authored_at": "2026-10-12T15:29:02Z"
  },
  "pull": {
    "number": 14,
    "title": "Retry failed webhook deliveries",
    "author": "ana",
    "agent": "claude-code",
    "merged_by": "g1t",
    "merged_at": "2026-10-12T15:52:18.330Z"
  },
  "issue": {
    "number": 9,
    "title": "Webhook deliveries are not retried",
    "state": "closed",
    "body": "A delivery that times out is never sent again."
  },
  "decisions": [
    {
      "id": "dec_01kpz8m2q4r6s8t0v2w4x6y8za",
      "issue": 9,
      "pull": 14,
      "session_id": null,
      "actor": null,
      "kind": "integration_failure",
      "confidence": "tested",
      "summary": "#14 failed in the merge queue together with #12: `CI / merge_group` failed when they were combined.",
      "evidence": {
        "commit": "4be1c0d9a2f3e4b5c6d7e8f90a1b2c3d4e5f6a7b",
        "check": {
          "name": "CI / merge_group",
          "conclusion": "failure",
          "url": "https://g1t.sh/acme/web/actions/runs/run_01kpz8k0"
        },
        "combination": [
          11,
          12,
          14
        ],
        "other_pulls": [
          11,
          12
        ],
        "suspects": [
          12
        ],
        "bisected": true,
        "landed": []
      },
      "created_at": "2026-10-12T15:04:11.204Z"
    },
    {
      "id": "dec_01kpz9a1b3c5d7e9f1g3h5j7kb",
      "issue": 9,
      "pull": 14,
      "session_id": "ses_01kpz7x9y1z3a5b7c9d1e3f5gh",
      "actor": "ana",
      "kind": "fix",
      "confidence": "claimed",
      "summary": "Renamed the config key #12 also introduced, so both read retry_limit.",
      "evidence": {
        "commit": "7d3e9a1c5b2f4e6a8c0d2e4f6a8b0c2d4e6f8a0b"
      },
      "created_at": "2026-10-12T15:31:40.019Z"
    }
  ],
  "sessions": [
    {
      "seq": 31,
      "kind": "message",
      "text": "#12 renamed retries to retry_limit; reading the new name here.",
      "tool": null,
      "commit": null,
      "at": "2026-10-12T15:27:40.118Z"
    }
  ]
}
```

## Errors

A failed request answers with one of these statuses and a body like `{"error": {"code": "not_found", "message": "Repository not found."}}`. See [errors](/reference/api/#errors).

| Status | Code | When |
| --- | --- | --- |
| 401 | `unauthenticated` | A token is required, or the one sent is not valid. |
| 403 | `forbidden` | The token is valid but not allowed to do this, such as a member-only change, or a token without the scope it needs. |
| 404 | `not_found` | It does not exist, or you cannot see it. |
| 422 | `invalid` | The input is not valid. `message` says which field and why. |
