Skip to main content

Automatically redelivering failed deliveries for a GitHub App webhook

You can write a script to handle failed deliveries of a GitHub App webhook.

About automatically redelivering failed deliveries

This article describes how to write a script to find and redeliver failed deliveries for a GitHub App webhook. For more information about failed deliveries, see Handling failed webhook deliveries.

This example shows you:

  • A script that will find and redeliver failed deliveries for a GitHub App webhook
  • What credentials your script will need, and how to store the credentials securely as GitHub Actions secrets
  • A GitHub Actions workflow that can securely access your credentials and run the script periodically

This example uses GitHub Actions, but you can also run this script on your server that handles webhook deliveries. For more information, see Alternative methods.

Storing credentials for the script

The endpoints to find and redeliver failed webhooks require a JSON web token, which is generated from the app ID and private key for your app.

The endpoints to fetch and update the value of environment variables require a personal access token, GitHub App installation access token, or GitHub App user access token. This example uses a personal access token. If your GitHub App is installed on the repository where this workflow will run and has permission to write repository variables, you can modify this example to create an installation access token during the GitHub Actions workflow instead of using a personal access token. For more information, see Making authenticated API requests with a GitHub App in a GitHub Actions workflow.

  1. Find the app ID for your GitHub App. You can find the app ID on the settings page for your app. The app ID is different from the client ID. For more information about navigating to the settings page for your GitHub App, see Modifying a GitHub App registration.
  2. Store the app ID from the previous step as a GitHub Actions secret in the repository where you want the workflow to run. For more information about storing secrets, see Using secrets in GitHub Actions.
  3. Generate a private key for your app. For more information about generating a private key, see Managing private keys for GitHub Apps.
  4. Store the private key, including -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----, from the previous step as a GitHub Actions secret in the repository where you want the workflow to run.
  5. Create a personal access token with the following access. For more information, see Managing your personal access tokens.
    • For a fine-grained personal access token, grant the token:
      • Write access to the repository variables permission
      • Access to the repository where this workflow will run
    • For a personal access token (classic), grant the token the repo scope.
  6. Store your personal access token from the previous step as a GitHub Actions secret in the repository where you want the workflow to run.

Adding a workflow that will run the script

This section demonstrates how you can use a GitHub Actions workflow to securely access the credentials that you stored in the previous section, set environment variables, and periodically run a script to find and redeliver failed deliveries.

Copy this GitHub Actions workflow into a YAML file in the .github/workflows directory in the repository where you want the workflow to run. Replace the placeholders in the Run script step as described below.

YAML
name: Redeliver failed webhook deliveries
on:
  schedule:
    - cron: '40 */6 * * *'
  workflow_dispatch:

This workflow runs every 6 hours or when manually triggered.

permissions:
  contents: read

This workflow will use the built in GITHUB_TOKEN to check out the repository contents. This grants GITHUB_TOKEN permission to do that.

jobs:
  redeliver-failed-deliveries:
    name: Redeliver failed deliveries
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo content
        uses: actions/checkout@v6

This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.

      - name: Setup Node.js
        uses: actions/setup-node@v7
        with:
          node-version: '20.x'

This step sets up Node.js. The script that this workflow will run uses Node.js.

      - name: Install dependencies
        run: npm install octokit

This step installs the octokit library. The script that this workflow will run uses the octokit library.

      - name: Run script
        env:
          APP_ID: ${{ secrets.YOUR_APP_ID_SECRET_NAME }}
          PRIVATE_KEY: ${{ secrets.YOUR_PRIVATE_KEY_SECRET_NAME }}
          TOKEN: ${{ secrets.YOUR_TOKEN_SECRET_NAME }}
          LAST_REDELIVERY_VARIABLE_NAME: 'YOUR_LAST_REDELIVERY_VARIABLE_NAME'
          WORKFLOW_REPO: ${{ github.event.repository.name }}
          WORKFLOW_REPO_OWNER: ${{ github.repository_owner }}
        run: |
          node .github/workflows/scripts/redeliver-failed-deliveries.mjs

This step sets some environment variables, then runs a script to find and redeliver failed webhook deliveries.

  • Replace YOUR_APP_ID_SECRET_NAME with the name of the secret where you stored your app ID.
  • Replace YOUR_PRIVATE_KEY_SECRET_NAME with the name of the secret where you stored your private key.
  • Replace YOUR_TOKEN_SECRET_NAME with the name of the secret where you stored your personal access token.
  • Replace YOUR_LAST_REDELIVERY_VARIABLE_NAME with the name that you want to use for a configuration variable that will be stored in the repository where this workflow is stored. The name can be any string that contains only alphanumeric characters and _, and does not start with GITHUB_ or a number. For more information, see Store information in variables.
#
name: Redeliver failed webhook deliveries

# This workflow runs every 6 hours or when manually triggered.
on:
  schedule:
    - cron: '40 */6 * * *'
  workflow_dispatch:

# This workflow will use the built in `GITHUB_TOKEN` to check out the repository contents. This grants `GITHUB_TOKEN` permission to do that.
permissions:
  contents: read

#
jobs:
  redeliver-failed-deliveries:
    name: Redeliver failed deliveries
    runs-on: ubuntu-latest
    steps:
      # This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.
      - name: Check out repo content
        uses: actions/checkout@v6

      # This step sets up Node.js. The script that this workflow will run uses Node.js.
      - name: Setup Node.js
        uses: actions/setup-node@v7
        with:
          node-version: '20.x'

      # This step installs the octokit library. The script that this workflow will run uses the octokit library.
      - name: Install dependencies
        run: npm install octokit

      # This step sets some environment variables, then runs a script to find and redeliver failed webhook deliveries.
      # - Replace `YOUR_APP_ID_SECRET_NAME` with the name of the secret where you stored your app ID.
      # - Replace `YOUR_PRIVATE_KEY_SECRET_NAME` with the name of the secret where you stored your private key.
      # - Replace `YOUR_TOKEN_SECRET_NAME` with the name of the secret where you stored your personal access token.
      # - Replace `YOUR_LAST_REDELIVERY_VARIABLE_NAME` with the name that you want to use for a configuration variable that will be stored in the repository where this workflow is stored. The name can be any string that contains only alphanumeric characters and `_`, and does not start with `GITHUB_` or a number. For more information, see [AUTOTITLE](/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows).
      
      - name: Run script
        env:
          APP_ID: ${{ secrets.YOUR_APP_ID_SECRET_NAME }}
          PRIVATE_KEY: ${{ secrets.YOUR_PRIVATE_KEY_SECRET_NAME }}
          TOKEN: ${{ secrets.YOUR_TOKEN_SECRET_NAME }}
          LAST_REDELIVERY_VARIABLE_NAME: 'YOUR_LAST_REDELIVERY_VARIABLE_NAME'
          
          WORKFLOW_REPO: ${{ github.event.repository.name }}
          WORKFLOW_REPO_OWNER: ${{ github.repository_owner }}
        run: |
          node .github/workflows/scripts/redeliver-failed-deliveries.mjs

Adding the script

This section demonstrates how you can write a script to find and redeliver failed deliveries.

Copy this script into a file called .github/workflows/scripts/redeliver-failed-deliveries.mjs in the same repository where you saved the GitHub Actions workflow file above.

JavaScript
import { App, Octokit } from "octokit";

This script uses GitHub's Octokit SDK to make API requests. For more information, see AUTOTITLE.

async function checkAndRedeliverWebhooks() {
  const APP_ID = process.env.APP_ID;
  const PRIVATE_KEY = process.env.PRIVATE_KEY;
  const TOKEN = process.env.TOKEN;
  const LAST_REDELIVERY_VARIABLE_NAME = process.env.LAST_REDELIVERY_VARIABLE_NAME;
  const WORKFLOW_REPO_NAME = process.env.WORKFLOW_REPO;
  const WORKFLOW_REPO_OWNER = process.env.WORKFLOW_REPO_OWNER;

Get the values of environment variables that were set by the GitHub Actions workflow.

  const app = new App({
    appId: APP_ID,
    privateKey: PRIVATE_KEY,
  });

Create an instance of the octokit App using the app ID and private key values that were set in the GitHub Actions workflow.

This will be used to make API requests to the webhook-related endpoints.

  const octokit = new Octokit({ 
    auth: