> For the complete documentation index, see [llms.txt](https://docs.flxbl.io/flxbl/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flxbl.io/flxbl/sfp-server/api-reference/reviews.md).

# Reviews

## List pull requests with metadata and review environments

> Retrieves all pull requests for a repository with comprehensive metadata including Salesforce component changes, review environment assignments, validation status, and component overlap detection.\
> \
> \*\*This endpoint always answers from cache and returns in \~1s.\*\* The snapshot is rebuilt by the Hatchet \`refresh-review-cache\` workflow every 15 minutes.\
> \
> Passing \`refresh=true\` \*\*dispatches\*\* a refresh for this repository and returns the \*current\* snapshot immediately with \`refreshing: true\` — it does not wait for the rebuild. Poll this endpoint until \`cacheVersion\` changes to pick up the fresh data.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.40.2"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"ReviewStatusDto":{"type":"object","properties":{"openPrs":{"type":"object","description":"Object containing open pull requests, keyed by PR number.","additionalProperties":{"$ref":"#/components/schemas/PullRequestSummaryDto"}},"closedPrs":{"type":"object","description":"Object containing closed pull requests, keyed by PR number.","additionalProperties":{"$ref":"#/components/schemas/PullRequestSummaryDto"}},"cacheVersion":{"type":"number","description":"Doc-store version of the cached snapshot. Increments every time the refresh workflow republishes it, so clients can poll for \"my refresh landed\" without diffing the payload."},"refreshing":{"type":"boolean","description":"True when a refresh workflow is in flight for this repository. The payload returned alongside it is the previous snapshot (or empty on a cold cache)."},"refreshRunId":{"type":"string","description":"Hatchet run id of the in-flight refresh, when one was dispatched or already running."}},"required":["openPrs","closedPrs"]},"PullRequestSummaryDto":{"type":"object","properties":{"issueTitle":{"type":"string","description":"Title of the pull request"},"issueUrl":{"type":"string","description":"Link to the pull request on GitHub"},"number":{"type":"number","description":"Pull request number"},"branch":{"type":"string","description":"Source branch name of the PR"},"baseBranch":{"type":"string","description":"Target branch name of the PR"},"author":{"type":"string","description":"Author login of the pull request"},"authorAvatarUrl":{"type":"string","description":"Author avatar URL"},"labels":{"description":"Labels attached to the pull request","type":"array","items":{"$ref":"#/components/schemas/LabelDto"}},"elapsedTime":{"type":"number","description":"Time elapsed since PR creation in milliseconds"},"merged":{"type":"boolean","description":"Whether the PR has been merged"},"headSha":{"type":"string","description":"Full SHA of the head (source branch tip) commit"},"mergeCommitSha":{"type":"object","description":"SHA of the merge commit if PR is merged"},"files":{"description":"Files changed in the pull request","allOf":[{"$ref":"#/components/schemas/FilesChangedDto"}]},"commitsAhead":{"type":"number","description":"Number of commits ahead of the base branch"},"commitsBehind":{"type":"number","description":"Number of commits behind the base branch"},"metadata":{"description":"Salesforce metadata changes organized by package","allOf":[{"$ref":"#/components/schemas/SalesforceMetadataDto"}]},"reviewEnvironment":{"description":"Review environment details for this pull request","allOf":[{"$ref":"#/components/schemas/ReviewEnvironmentDetailDto"}]},"error":{"type":"object","description":"Error message if the PR failed to process, null if no error occurred"},"buildActionLink":{"type":"string","description":"Link to the build action run"},"checkStatus":{"type":"string","description":"Status of the checks (queued, in_progress, completed)"},"checkConclusion":{"type":"string","description":"Conclusion of the checks (success, failure, neutral, cancelled, skipped, timed_out, action_required)"},"validationActionLink":{"type":"string","description":"Link to the validation action run"}},"required":["issueTitle","issueUrl","number","branch","baseBranch","author","authorAvatarUrl","elapsedTime","merged","headSha"]},"LabelDto":{"type":"object","properties":{"key":{"type":"string","description":"Label key/name"},"description":{"type":"object","description":"Label description"},"color":{"type":"string","description":"Label color hex code"}},"required":["key"]},"FilesChangedDto":{"type":"object","properties":{"added":{"description":"List of files added in the PR","type":"array","items":{"type":"string"}},"deleted":{"description":"List of files deleted in the PR","type":"array","items":{"type":"string"}},"modified":{"description":"List of files modified in the PR","type":"array","items":{"type":"string"}}},"required":["added","deleted","modified"]},"SalesforceMetadataDto":{"type":"object","properties":{}},"ReviewEnvironmentDetailDto":{"type":"object","properties":{"orgId":{"type":"string","description":"Salesforce org ID of the review environment"},"username":{"type":"string","description":"Username to access the review environment"},"browserLoginUrl":{"type":"string","description":"Browser-accessible codev login URL that serves as a gateway proxy authenticator. Once authenticated, allows user access to the Salesforce org."},"apiAuthUrl":{"type":"string","description":"Server-side API endpoint that returns the actual Salesforce frontdoor URL with session token for programmatic access."},"type":{"type":"string","description":"Type of environment: scratchorg or sandbox"},"branch":{"type":"string","description":"Branch associated with the environment"},"pool":{"type":"string","description":"Pool that the environment belongs to"},"environmentName":{"type":"string","description":"Environment name/identifier"},"status":{"type":"string","description":"Current status of the environment"},"isActive":{"type":"boolean","description":"Whether the environment is currently active"},"name":{"type":"string","description":"Name identifier of the environment"},"issue":{"type":"string","description":"Issue/PR number associated with the environment"},"loginUrl":{"type":"string","description":"Direct Salesforce login URL"},"expiryDate":{"type":"string","description":"Expiry date of the environment (for scratch orgs)"},"assignedAt":{"type":"number","description":"Timestamp when environment was assigned to the PR"},"createdAt":{"type":"number","description":"Timestamp when environment was created (for sandboxes)"},"isImmortal":{"type":"boolean","description":"Whether the environment is immortal (for sandboxes)"}}}}},"paths":{"/sfp/api/reviews/pull-requests":{"get":{"operationId":"ReviewController_getRepositoryReviewStatus","summary":"List pull requests with metadata and review environments","description":"Retrieves all pull requests for a repository with comprehensive metadata including Salesforce component changes, review environment assignments, validation status, and component overlap detection.\n\n**This endpoint always answers from cache and returns in ~1s.** The snapshot is rebuilt by the Hatchet `refresh-review-cache` workflow every 15 minutes.\n\nPassing `refresh=true` **dispatches** a refresh for this repository and returns the *current* snapshot immediately with `refreshing: true` — it does not wait for the rebuild. Poll this endpoint until `cacheVersion` changes to pick up the fresh data.","parameters":[{"name":"repositoryIdentifier","required":true,"in":"query","description":"Repository identifier in the format owner/repo","schema":{"type":"string"}},{"name":"prNumber","required":false,"in":"query","description":"Optional PR number to filter for a specific pull request","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Optional status filter: open, closed, or all (default: all)","schema":{"type":"string"}},{"name":"refresh","required":false,"in":"query","description":"Force refresh the cache and fetch fresh data","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"Pull requests with metadata retrieved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStatusDto"}}}},"400":{"description":"Bad Request (e.g., missing repositoryIdentifier)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: member, application"},"404":{"description":"Repository not found or no access"}},"tags":["Reviews"]}}}}
```

## Request a rebuild of the review status cache for a repository

> Dispatches the Hatchet \`refresh-review-cache\` workflow scoped to this repository and returns immediately with the run id.\
> \
> The rebuild clones the repository and resolves Salesforce metadata for every open PR, so it takes minutes — it deliberately runs in a worker and never on the API process. Poll \`GET reviews/pull-requests\` until \`cacheVersion\` changes to observe the result.\
> \
> Repeat requests within a short window coalesce onto the in-flight run (\`alreadyRunning: true\`) instead of queueing another.

```json
{"openapi":"3.0.0","info":{"title":"sfp server","version":"51.40.2"},"security":[{"access-token":[]}],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","in":"header"}},"schemas":{"RefreshReviewStatusResponseDto":{"type":"object","properties":{"repositoryIdentifier":{"type":"string","description":"Repository the refresh was requested for."},"dispatched":{"type":"boolean","description":"True when a new workflow run was started by this request."},"alreadyRunning":{"type":"boolean","description":"True when a run was already in flight and this request coalesced onto it."},"runId":{"type":"string","description":"Hatchet run id, when a run is available."},"reason":{"type":"string","description":"Stable, client-safe code for why no run could be started. Never raw exception text — the underlying error stays in server logs.","enum":["hatchet-disabled","refresh-dispatch-failed"]}},"required":["repositoryIdentifier","dispatched","alreadyRunning"]}}},"paths":{"/sfp/api/reviews/pull-requests/refresh":{"post":{"operationId":"ReviewController_refreshRepositoryReviewStatus","summary":"Request a rebuild of the review status cache for a repository","description":"Dispatches the Hatchet `refresh-review-cache` workflow scoped to this repository and returns immediately with the run id.\n\nThe rebuild clones the repository and resolves Salesforce metadata for every open PR, so it takes minutes — it deliberately runs in a worker and never on the API process. Poll `GET reviews/pull-requests` until `cacheVersion` changes to observe the result.\n\nRepeat requests within a short window coalesce onto the in-flight run (`alreadyRunning: true`) instead of queueing another.","parameters":[{"name":"repositoryIdentifier","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":"Refresh dispatched (or coalesced onto an in-flight run).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshReviewStatusResponseDto"}}}},"400":{"description":"Bad Request (e.g. missing repositoryIdentifier)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Requires role: member, application"}},"tags":["Reviews"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.flxbl.io/flxbl/sfp-server/api-reference/reviews.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
