Deployments
/api/v1/deploymentsDeployments in the active organization, paginated, newest-started-
first. Matches list_services' (app/api/v1/services.py) own
page/per_page + filter shape.
Authorization
HTTPBearer In: header
Query Parameters
Page number
1 <= value1Items per page
1 <= value <= 10020Filter by service name
Filter by environment
Filter by status
Response Body
application/json
application/json
curl -X GET "https://example.com/api/v1/deployments"{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_name": "string", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "version": "string", "commit_sha": "string", "environment": "string", "started_at": "2019-08-24T14:15:22Z", "finished_at": "2019-08-24T14:15:22Z", "status": "string", "source": "string", "idempotency_key": "string", "metadata": {}, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } ], "total": 0, "page": 0, "per_page": 0}/api/v1/deploymentsCreate a deployment. org_id comes only from org (the
authenticated principal's resolved organization) — see this module's
schema, app.schemas.deployment, for why the request body has no field
for it at all.
Replaying the same (source, idempotency_key) returns the existing row
unchanged with 200 OK rather than creating a second one, which is why
the status code is set explicitly below instead of relying on the
decorator's default 201. See DeploymentRepository.create_or_get for
how replay is enforced.
Authorization
HTTPBearer In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
curl -X POST "https://example.com/api/v1/deployments" \ -H "Content-Type: application/json" \ -d '{ "service_name": "string", "version": "string", "commit_sha": "string", "environment": "string", "started_at": "2019-08-24T14:15:22Z", "idempotency_key": "string" }'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_name": "string", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "version": "string", "commit_sha": "string", "environment": "string", "started_at": "2019-08-24T14:15:22Z", "finished_at": "2019-08-24T14:15:22Z", "status": "string", "source": "string", "idempotency_key": "string", "metadata": {}, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}/api/v1/deployments/markersThe marker-overlay hot path (#876's own reason to exist as a
separate endpoint from GET "" — see module docstring). Registered
ahead of GET "/{deployment_id}" so "markers" is never parsed as a
UUID path parameter.
to before from is rejected the same way
services.py::_validate_range rejects it. The window-too-wide case is
DeploymentRepository.get_marker_window's own
DeploymentMarkerWindowTooWide, caught here and turned into a 400 —
matching get_service_signals' SignalsRangeTooWide handling.
Authorization
HTTPBearer In: header
Query Parameters
One or more service names to fetch markers for
Window start (inclusive)
date-timeWindow end (inclusive)
date-timeResponse Body
application/json
application/json
curl -X GET "https://example.com/api/v1/deployments/markers?service=string&from=2019-08-24T14%3A15%3A22Z&to=2019-08-24T14%3A15%3A22Z"[ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "service": "string", "version": "string", "short_commit": "string", "environment": "string", "status": "string", "started_at": "2019-08-24T14:15:22Z" }]/api/v1/deployments/changed-sinceWhat shipped for service between the deployment before an anchor
and the anchor itself (#885, epic deployment-attribution, M09) — the
deployment-attribution half of "changed since last deploy"; the
objectives half is out of scope (epic.md's Dependencies section).
The anchor is given directly (deployment_id) or resolved from a point
in time (at) — exactly one of the two, or a 400.
DeploymentRepository.get_change_window does the resolution; see that
method's docstring for exactly how each input maps to an anchor, and
for why from_deployment (the "lower bound") comes back None for the
first-ever deployment of a service rather than an empty range.
Registered ahead of GET "/{deployment_id}" for the same reason
/markers is: deployment_id's uuid.UUID path-param type does not
stop FastAPI matching "changed-since" against that pattern first if it
were registered later — it would 422 attempting to parse the literal
segment as a UUID rather than falling through to this route.
Commit range comes from CommitLinkService.resolve_commit_range
(#881) — never called at all for the first-ever-deployment case (there
is no from_deployment to diff against), and returns None (not an
error) when the service has no connected source repo. See
DeploymentChangedSinceResponse's docstring for the four shapes this
produces and how a caller tells them apart without inferring anything
from an absence.
Authorization
HTTPBearer In: header
Query Parameters
Service name
Anchor on this deployment
Anchor on the deployment in effect at this point in time
Response Body
application/json
application/json
curl -X GET "https://example.com/api/v1/deployments/changed-since?service=string"{ "service_name": "string", "first_deployment": true, "from_deployment": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "version": "string", "commit_sha": "string", "started_at": "2019-08-24T14:15:22Z", "status": "string" }, "to_deployment": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "version": "string", "commit_sha": "string", "started_at": "2019-08-24T14:15:22Z", "status": "string" }, "commit_range": { "compare_url": "string", "commits": [ { "sha": "string", "url": "string", "subject": "string", "author": "string" } ], "total_commits": 0, "truncated": true, "degraded": true }}/api/v1/deployments/{deployment_id}One deployment by id, within the active organization. 404 across
tenants, matching finish_deployment's own get_by_id precedent.
Authorization
HTTPBearer In: header
Path Parameters
uuidResponse Body
application/json
application/json
curl -X GET "https://example.com/api/v1/deployments/497f6eca-6276-4993-bfeb-53cbbbba6f08"{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_name": "string", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "version": "string", "commit_sha": "string", "environment": "string", "started_at": "2019-08-24T14:15:22Z", "finished_at": "2019-08-24T14:15:22Z", "status": "string", "source": "string", "idempotency_key": "string", "metadata": {}, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}/api/v1/deployments/{deployment_id}Finish a deployment: sets finished_at and a terminal status.
404 across tenants, matching SilenceRepository.get_by_id's own
org-scoped lookup precedent. 409 when the deployment already has a
finished_at — a rollback is reported as a new deployment (its own
POST, its own idempotency key), never a second PATCH here; see
DeploymentAlreadyFinishedError.
Authorization
HTTPBearer In: header
Path Parameters
uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
curl -X PATCH "https://example.com/api/v1/deployments/497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{ "status": "succeeded" }'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_name": "string", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "version": "string", "commit_sha": "string", "environment": "string", "started_at": "2019-08-24T14:15:22Z", "finished_at": "2019-08-24T14:15:22Z", "status": "string", "source": "string", "idempotency_key": "string", "metadata": {}, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}/api/v1/deployments/{deployment_id}/issuesIssues whose first occurrence was attributed to deployment_id.
404s if the deployment itself is not in this org — checked first, via
DeploymentRepository.get_by_id's own org-scoped precedent — so a
cross-org deployment id and one that does not exist at all read
identically, before the issue query ever runs.
Attribution is a candidate, not a verdict (epic architecture decision):
this is exactly Issue.deployment_id == deployment_id, the same column
the forward read exposes, never a confidence-ranked or causally-
asserted subset. A deployment nothing has attributed to yet returns a
clean empty page, not an error — the normal case for a fresh deploy.
Authorization
HTTPBearer In: header
Path Parameters
uuidQuery Parameters
Page number
1 <= value1Items per page
1 <= value <= 10020Response Body
application/json
application/json
curl -X GET "https://example.com/api/v1/deployments/497f6eca-6276-4993-bfeb-53cbbbba6f08/issues"{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "title": "string", "culprit": "string", "status": "unresolved", "first_seen_at": "2019-08-24T14:15:22Z", "last_seen_at": "2019-08-24T14:15:22Z", "total_count": 0, "attribution_offset_seconds": 0 } ], "total": 0, "page": 0, "per_page": 0}