Creates the run, or returns the stored one when ci_system, external_run_id and attempt match (200). Sending the same attempt with status: in_progress starts a run stored as queued; nothing else about the stored run changes. A higher attempt adds an attempt to the same run; a lower one is a 409 conflict. Everything sent through this API is self-reported: the run is marked trust: self_reported, policies ignore its data unless a rule opts in, and it never counts as provider provenance. Runs count toward your plan's monthly run and pipeline limits, counted apart from the runs your connected providers send. Each key or OIDC trust can create up to 2,000 new runs a day (UTC); past that a new run is a 429 rate_limited until the next day. Unknown fields in the body are a 400.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
application/jsonci_system*stringShort id of your CI system, for example jenkins or circleci. Lowercase letters, digits and hyphens.
^[a-z0-9][a-z0-9-]{0,31}$ci_system_name?stringDisplay name of the CI system.
1 <= length <= 60external_run_id*stringYour CI system's id for the run. With ci_system it identifies the run, so sending it again is safe.
^[A-Za-z0-9._:\/-]{1,128}$attempt?integerAttempt number. Resending the same attempt returns the stored run; a higher one adds an attempt; a lower one is a 409.
1 <= value <= 9991repository*stringThe repository as a URL, an scp-style address or host/owner/name. Credentials in the URL are refused.
1 <= length <= 300commit_sha*stringFull commit hash, 40 (SHA-1) or 64 (SHA-256) lowercase hex characters.
^(?:[0-9a-f]{40}|[0-9a-f]{64})$ref?|Branch or tag the run built.
1 <= length <= 255pipeline_name*string1 <= length <= 200url?|Link to the run in your CI system.
length <= 2048status?string"in_progress""queued""in_progress"started_at?stringdate-timeactor?|Who started the run, as your CI system names them. Never used for billing or approvals.
1 <= length <= 200event?string"other""push""pull_request""tag""schedule""manual""other"timeout_minutes?integerMinutes after which a run still open is settled as timed_out. Default 360, at most 4320.
5 <= value <= 4320The run already existed; the stored run.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/runs" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "ci_system": "string", "external_run_id": "string", "repository": "string", "commit_sha": "string", "pipeline_name": "string" }'{ "data": { "id": "string", "provider": "other", "ci_system": "string", "ci_system_name": "string", "external_run_id": "string", "attempt": 0, "repository": "string", "commit_sha": "string", "ref": "string", "pipeline_name": "string", "url": "string", "status": "string", "started_at": "2019-08-24T14:15:22Z", "completed_at": "2019-08-24T14:15:22Z", "actor": "string", "event": "string", "deadline_at": "2019-08-24T14:15:22Z", "trust": "string", "linked_repository": { "provider": "string", "id": "string" }, "credential": { "type": "string", "name": "string" }, "app_url": "string", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }}Moves the attempt forward (queued, in_progress, then a final state). A finished attempt cannot change: sending a different state is a 409 run_finished, resending the same final state is a 200. Runs left open past their deadline are settled as timed_out.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
run_id*stringThe id of a run created with createCiRun.
^[A-Za-z0-9._:-]{1,128}$application/jsonattempt?integer1 <= value <= 9991status?string"queued""in_progress""success""failure""cancelled""timed_out""skipped"completed_at?|date-timeurl?|length <= 2048The updated run.
application/jsondata*curl -X PATCH "https://api.prodgator.io/v1/ci/runs/string" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{}'{ "data": { "id": "string", "provider": "other", "ci_system": "string", "ci_system_name": "string", "external_run_id": "string", "attempt": 0, "repository": "string", "commit_sha": "string", "ref": "string", "pipeline_name": "string", "url": "string", "status": "string", "started_at": "2019-08-24T14:15:22Z", "completed_at": "2019-08-24T14:15:22Z", "actor": "string", "event": "string", "deadline_at": "2019-08-24T14:15:22Z", "trust": "string", "linked_repository": { "provider": "string", "id": "string" }, "credential": { "type": "string", "name": "string" }, "app_url": "string", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" }}A report is one job's results: a summary, up to 20 attestations (test results, coverage, SBOM, scan, custom) and up to 50 artifact files. The same attempt, job, matrix and name replaces the earlier report, so retrying is safe. The response lists upload slots: PUT each file to its slot, then call completeCiArtifacts. The kinds provenance and ownership are refused with 400 kind_not_allowed. Everything is self-reported and marked untrusted.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
run_id*stringThe id of a run created with createCiRun.
^[A-Za-z0-9._:-]{1,128}$application/jsonattempt?integer1 <= value <= 9991job*name?string1 <= length <= 100"default"summary?|Markdown summary, at most 1 MiB.
attestations?array<>0 <= items <= 20[]artifacts?array<>0 <= items <= 50[]The report was stored.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/runs/string/reports" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "job": { "name": "string" } }'{ "data": { "report_id": "string", "run_id": "string", "attempt": 0, "url": "string", "trust": "string", "uploads": [ { "artifact_id": "string", "path": "string", "url": "string", "method": "PUT", "headers": { "property1": "string", "property2": "string" }, "expires_at": "2019-08-24T14:15:22Z" } ], "skipped": [ { "path": "string", "reason": "string" } ], "warnings": [ "string" ] }}Merges by kind and name: an attestation with the same kind and name is replaced, nothing is ever deleted. At most 20 per call, and provenance and ownership kinds are refused with 400 kind_not_allowed.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
run_id*stringThe id of a run created with createCiRun.
^[A-Za-z0-9._:-]{1,128}$report_id*stringThe report_id returned by createCiReport.
^[1-9]\d{0,2}-[0-9a-f]{24}$application/jsonattestations*array<>1 <= items <= 20The attestations were stored.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/runs/string/reports/string/attestations" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "attestations": [ { "kind": "test-results", "name": "string", "data": {} } ] }'{ "data": { "report_id": "string", "attestations": [ { "id": "string", "kind": "string", "name": "string", "status": "string" } ], "warnings": [ "string" ] }}Returns a presigned PUT slot per file. PUT the file with the slot's headers before expires_at, then call completeCiArtifacts. A file already uploaded with the same checksum is listed under skipped with already_uploaded.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
run_id*stringThe id of a run created with createCiRun.
^[A-Za-z0-9._:-]{1,128}$report_id*stringThe report_id returned by createCiReport.
^[1-9]\d{0,2}-[0-9a-f]{24}$application/jsonartifacts*array<>1 <= items <= 50The slots.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/runs/string/reports/string/artifacts" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "artifacts": [ { "path": "string", "size": 1, "sha256": "string" } ] }'{ "data": { "report_id": "string", "uploads": [ { "artifact_id": "string", "path": "string", "url": "string", "method": "PUT", "headers": { "property1": "string", "property2": "string" }, "expires_at": "2019-08-24T14:15:22Z" } ], "skipped": [ { "path": "string", "reason": "string" } ], "warnings": [ "string" ] }}Prodgator checks each object's size and checksum. A file that does not match is rejected and deleted. Safe to call again.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
run_id*stringThe id of a run created with createCiRun.
^[A-Za-z0-9._:-]{1,128}$report_id*stringThe report_id returned by createCiReport.
^[1-9]\d{0,2}-[0-9a-f]{24}$application/jsonartifact_ids*array<>1 <= items <= 50The result for each artifact.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/runs/string/reports/string/artifacts/complete" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "artifact_ids": [ "string" ] }'{ "data": { "report_id": "string", "results": [ { "artifact_id": "string", "status": "string", "reason": "string" } ] }}Opens a deployment against a gate your organization owns and returns a poll_token. Poll getCiGate with that token and deploy only when decision is approved: treat anything else, a timeout or an error as not approved. When no gate covers the environment the call is a 409 gate_not_configured. A write:ci credential can open a gate but can never approve it.
Required scope: write:ci
AuthorizationBearer <token>Send the key as Authorization: Bearer plk_live_.... No other header is accepted.
application/jsonrun_id*stringThe id of the run, from createCiRun.
^[A-Za-z0-9._:-]{1,128}$attempt?integer1 <= value <= 9991environment*stringThe environment you deploy to, for example production.
1 <= length <= 100gate_id?stringA gate that covers the environment. Without it Prodgator resolves the covering gates.
^[A-Za-z0-9._:-]{1,128}$job?stringThe deploying job, so two jobs deploying to one environment get separate gates.
^[A-Za-z0-9_.-]{1,100}$The gate was already open for this run, attempt, environment and job.
application/jsondata*curl -X POST "https://api.prodgator.io/v1/ci/gates" \ -H "Authorization: Bearer plk_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "run_id": "string", "environment": "string" }'{ "data": { "gate_id": "string", "deployment_id": "string", "environment": "string", "gate": { "id": "string", "name": "string" }, "decision": "string", "status": "string", "decided_by": "string", "note": "string", "url": "string", "poll_after_seconds": 0, "poll_token": "string", "expires_at": "2019-08-24T14:15:22Z" }}Authenticated with the poll token from openCiGate, not an API key. Wait poll_after_seconds between polls (at most 12 per minute per gate). Deploy only when decision is approved.
gatePollTokenAuthorizationBearer <token>The poll token returned when a gate opens (openCiGate). It reads that one gate, expires after 12 hours and cannot do anything else.
gate_id*stringThe gate_id returned by openCiGate.
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$The gate.
application/jsondata*curl -X GET "https://api.prodgator.io/v1/ci/gates/string" \ -H "Authorization: Bearer plk_live_YOUR_KEY"{ "data": { "gate_id": "string", "deployment_id": "string", "environment": "string", "gate": { "id": "string", "name": "string" }, "decision": "string", "status": "string", "decided_by": "string", "note": "string", "url": "string", "poll_after_seconds": 0 }}