When configuring a webhook for a GitHub repository—specifically for the workflow_job
event—it can be challenging to determine whether a given delivery corresponds to a rejected workflow job.
Rejected jobs refer to those that were not approved by a required reviewer, typically for deployments targeting a protected environment.
To identify a rejected job, let’s examine a delivery triggered by the workflow_job.completed
event. We’ll focus on the workflow_job
payload and highlight the key attributes that signal a rejection. Here’s an example payload from a workflow_job.completed webhook event:
"action": "completed",
"workflow_job": {
"id": 41511799280,
"run_id": 14785014731,
"workflow_name": "Get workflow runs details from current repository",
"head_branch": "main",
"run_url": "https://api.github.com/repos/andreypicado506/get-wf-details/actions/runs/14785014731",
"run_attempt": 1,
"node_id": "CR_kwDONkcfGM8AAAAJqkvJ8A",
"head_sha": "520405cec8339c7806e42797cf03b15b4d355c86",
"url": "https://api.github.com/repos/andreypicado506/get-wf-details/actions/jobs/41511799280",
"html_url": "https://github.com/andreypicado506/get-wf-details/actions/runs/14785014731/job/41511799280",
"status": "completed",
"conclusion": "success",
"created_at": "2025-05-01T22:55:42Z",
"started_at": "2025-05-01T22:55:48Z",
"completed_at": "2025-05-01T22:55:51Z",
"name": "comment",
"steps": [
{
"name": "Set up job",
"status": "completed",
"conclusion": "success",
"number": 1,
"started_at": "2025-05-01T22:55:48Z",
"completed_at": "2025-05-01T22:55:48Z"
},
{
"name": "Run actions/checkout@v4",
"status": "completed",
"conclusion": "success",
"number": 2,
"started_at": "2025-05-01T22:55:48Z",
"completed_at": "2025-05-01T22:55:49Z"
},
{
"name": "Run actions/github-script@v7",
"status": "completed",
"conclusion": "success",
"number": 3,
"started_at": "2025-05-01T22:55:50Z",
"completed_at": "2025-05-01T22:55:50Z"
},
{
"name": "Post Run actions/checkout@v4",
"status": "completed",
"conclusion": "success",
"number": 6,
"started_at": "2025-05-01T22:55:50Z",
"completed_at": "2025-05-01T22:55:50Z"
},
{
"name": "Complete job",
"status": "completed",
"conclusion": "success",
"number": 7,
"started_at": "2025-05-01T22:55:50Z",
"completed_at": "2025-05-01T22:55:50Z"
}
],
"check_run_url": "https://api.github.com/repos/andreypicado506/get-wf-details/check-runs/41511799280",
"labels": [
"ubuntu-latest"
],
"runner_id": 59,
"runner_name": "GitHub Actions 38",
"runner_group_id": 2,
"runner_group_name": "GitHub Actions"
In this successful example, two key properties at the top level and within each step are especially relevant: status and conclusion. Since this job completed successfully, both are set to “completed” and “success“, respectively.
Let’s now compare this with a rejected job to see how those values change.
"status": "completed",
"conclusion": "failure",
"steps": [
],
In this case, the conclusion is “failure“. However, this value alone is not sufficient to distinguish a rejected job—it is also the result when a job fails due to an actual error during execution.
What makes a rejected job stand out is the fact that the steps array is empty. This contrasts with a failed job, where the steps array is still populated with the steps that ran (and potentially failed).
Therefore, the conclusion field is not a reliable indicator of a rejected job. Unfortunately, there isn’t a documented or explicit flag within the workflow_job payload that definitively identifies rejections.
To clarify this behavior, I reached out to GitHub Support to confirm whether an empty steps array is unique to rejected jobs. They confirmed that an empty steps array indicates a job was rejected. You can read more about this in the GitHub Community discussion:
Final takeaway
If the steps array is empty in a workflow_job.completed event, it’s a reliable signal that the job was rejected.