This project provides a simple, secure Node.js proxy to forward webhook events from App Store Connect to Microsoft Teams and/or Slack, including signature verification and platform-specific formatting. It can also automatically create Pull Requests in Azure DevOps when your app goes live on the App Store.
- β Verifies App Store webhook signatures using HMAC SHA-256
- β Forwards formatted messages to Microsoft Teams and Slack
- β Custom message templates per platform
- β Supports custom timezones for event timestamps
- β
Automatic Azure DevOps PR creation when app is published (
READY_FOR_SALE) - β Auto-complete with squash merge on created PRs
- β
Configurable trigger state for testing (via
APPLE_EVENT_TRIGGER) - β Error handling and logging
- β Dockerized and ready for deployment (e.g. Render, Railway)
- β One-click deployable to Render
- App Store Connect access with one of the following roles: Account Holder, Admin, or App Manager to create a webhook.
- A configured workspace in either: Microsoft Teams and/or Slack
- (Optional) An Azure DevOps Personal Access Token (PAT) with Code (Read & Write) scope, if you want automatic PR creation when the app goes live.
End-to-end simple installation guides, from installing the proxy to get the test message to MS Teams / Slack.
π‘ To enable full support for TestFlight feedback (including deep links to App Store Connect and Xcode Organizer), make sure to set the following environment variables:
APP_ADAM_ID,APP_BUNDLE_ID, andAPP_PLATFORM_ID.
π Step-by-step setup guide: Integrate App Store Webhooks with Microsoft Teams (Medium)
π Step-by-step setup guide: Integrate App Store Webhooks with Slack (Medium)
π Step-by-step setup guide: Automate Your App Store Release Pipeline β Create Azure DevOps PRs from Apple Webhooks (Medium)
When your app reaches READY_FOR_SALE (live on the App Store), the proxy can automatically create a Pull Request in Azure DevOps (squash merge). The source and target branches are configurable via AZURE_DEVOPS_SOURCE_BRANCH and AZURE_DEVOPS_TARGET_BRANCH (defaults: master β release/production).
How it works:
- Apple sends a webhook with
appStoreVersionAppVersionStateUpdatedandnewValue: "READY_FOR_SALE" - The proxy creates a PR in your Azure DevOps repository
- Auto-complete is disabled on the PR (squash merge, source branch preserved). You can configured via
ENABLE_AUTO_COMPLETE - If PR creation fails, a failure notification is sent to Teams/Slack
Setup:
- Create a PAT in Azure DevOps at
https://dev.azure.com/{YourOrg}/_usersSettings/tokenswith Code (Read & Write) scope - Set the required environment variables:
AZURE_DEVOPS_PAT,AZURE_DEVOPS_ORG_URL,AZURE_DEVOPS_PROJECT,AZURE_DEVOPS_REPO_ID - (Optional) Override source/target branches via
AZURE_DEVOPS_SOURCE_BRANCHandAZURE_DEVOPS_TARGET_BRANCH
This feature is entirely optional. If
AZURE_DEVOPS_PATis not set, the proxy works exactly as before (Teams/Slack only).
appStoreVersionAppVersionStateUpdatedwebhookPingCreatedbetaFeedbackScreenshotSubmissionCreatedbetaFeedbackCrashSubmissionCreatedbuildUploadStateUpdatedbuildBetaDetailExternalBuildStateUpdated
Unknown events will still be delivered in raw JSON.
Here you can find all the available options to run the proxy.
The incoming webhook should be sent to the path: /appstore-webhook.
Click below to deploy instantly to Render:
Make sure to set the environment variables during setup (Read the Environment Variables table below).
Render automatically sets
NODE_ENV=production
To install via Unraid:
- Open the Apps tab in your Unraid dashboard.
- Search for:
AppStore-Webhook-Proxy - Click Install and configure the required environment variables.
π¬ Need help or want to leave feedback?
Join the support thread in the Unraid Community Forum.
π₯ Watch the setup walkthrough:
Build and run using Docker:
docker build -t appstore-webhook-proxy .
docker run -p 3000:3000 --env-file .env appstore-webhook-proxyIf you'd like to run the app directly with Node.js:
git clone https://github.com/yourusername/appstore-webhook-proxy.git
cd appstore-webhook-proxy
npm installCreate a .env file (or set variables directly in your cloud environment):
| Variable | Explanation | Default Value |
|---|---|---|
SHARED_SECRET |
Required. Secret used to verify incoming App Store Webhook requests. You define it when creating the webhook in App Store Connect, then set the same value here. Set it here: App Store Webhooks Setup |
(empty) |
TEAMS_WEBHOOK_URL |
Required if integrating with Microsoft Teams. Webhook URL for sending notifications to Microsoft Teams. Leave empty if not used. Example: https://your-teams.webhook.urlCreate it here: Microsoft Teams Incoming Webhook Guide |
(empty) |
SLACK_WEBHOOK_URL |
Required if integrating with Slack. Webhook URL for sending notifications to Slack. Leave empty if not used. Example: https://hooks.slack.com/services/XXX/YYY/ZZZCreate it here: Slack Webhook Guide |
(empty) |
APP_STORE_URL |
(Optional) Public URL of your app on the App Store. Included in notifications to make it easier to access the appβs page. Example: https://apps.apple.com/app/id123456789 |
(empty) |
TIMEZONE |
(Optional) Timezone used to format timestamps in messages. Use a valid IANA timezone, e.g. Europe/Athens. |
UTC |
APP_ADAM_ID |
(Optional β Used for TestFlight feedback). The App Store Connect "adamId" of your app. Required to generate links to App Store Connect and Xcode Organizer in TestFlight screenshot feedback messages. | (empty) |
APP_BUNDLE_ID |
(Optional β Used for TestFlight feedback). The bundle identifier of your app (e.g. com.company.app). Required to generate Xcode Organizer links for TestFlight screenshot feedback. |
(empty) |
APP_PLATFORM_ID |
(Optional β Used for TestFlight feedback). The App Store Connect platform ID (e.g. iOS). Required to generate Xcode Organizer links for TestFlight screenshot feedback. |
(empty) |
AZURE_DEVOPS_PAT |
(Optional β Required for Azure DevOps PR creation). Personal Access Token with Code (Read & Write) scope. If not set, PR creation is skipped entirely. Create one at: https://dev.azure.com/{YourOrg}/_usersSettings/tokens |
(empty) |
AZURE_DEVOPS_ORG_URL |
(Optional β Required for Azure DevOps PR creation). Your Azure DevOps organization URL. Example: https://dev.azure.com/YourOrg |
(empty) |
AZURE_DEVOPS_PROJECT |
(Optional β Required for Azure DevOps PR creation). Azure DevOps project name. | (empty) |
AZURE_DEVOPS_REPO_ID |
(Optional β Required for Azure DevOps PR creation). Repository ID or name in Azure DevOps. | (empty) |
AZURE_DEVOPS_SOURCE_BRANCH |
(Optional) Source branch for the auto-created PR. | master |
AZURE_DEVOPS_TARGET_BRANCH |
(Optional) Target branch for the auto-created PR. | release/production |
ENABLE_AUTO_COMPLETE |
(Optional) Set to true to enable auto-complete (squash merge) on created PRs. |
false |
APPLE_EVENT_TRIGGER |
(Optional) The Apple version state that triggers PR creation. Override with e.g. WAITING_FOR_REVIEW for testing without a real App Store release. |
READY_FOR_SALE |
ENABLE_TEST_ENDPOINT |
(Optional β For local testing only). When set to true, enables the internal /test/webhook route that allows you to manually POST Apple-style webhook payloads to simulate real events. This endpoint is disabled by default and should never be enabled in production. |
false |
INTERNAL_TEST_TOKEN |
(Optional β Recommended when testing). Security token required via the x-internal-token HTTP header when calling /test/webhook. Helps prevent unauthorized access to the test endpoint. Ignored if ENABLE_TEST_ENDPOINT is false. |
(empty) |
You can also copy from the example:
cp .env.example .envnpm startThen send a webhook POST to:
http://localhost:3000/appstore-webhook
- When setting up the webhook in App Store Connect, Apple will ask for a secret. Use a string of your choice and set it in
SHARED_SECRET. - Official docs:
.
βββ app.js # Entry point
βββ routes/
β βββ webhook.js # Webhook handler
β βββ testWebhook.js # Test endpoint handler
βββ utils/
β βββ eventTemplates.js # Teams formatter
β βββ slackTemplates.js # Slack formatter
β βββ stateDescriptions.js
βββ services/
β βββ signatureVerifier.js
β βββ teamsNotifier.js
β βββ slackNotifier.js
β βββ azureDevOpsService.js # Azure DevOps REST API client
β βββ releaseAutomation.js # PR creation orchestration
βββ middleware/
β βββ errorHandler.js
β βββ logging.js
βββ Dockerfile
βββ render.yaml # Render deploy spec
βββ .env.example
βββ .dockerignore
βββ .gitignore
βββ README.md
PRs and feedback welcome! You can help with:
- More supported event types
- Custom Slack/Teams formatting
- Delivery logs and retry support
When developing or validating new webhook event types, you can simulate Apple webhook deliveries using the internal test endpoint.
In your local .env file, add:
ENABLE_TEST_ENDPOINT=true
INTERNAL_TEST_TOKEN=super_secret_tokenNever enable this in production environments.
The /test/webhook route is only intended for local or QA testing.
curl -X POST http://localhost:3000/test/webhook \
-H "Content-Type: application/json" \
-H "x-internal-token: super-secret-token" \
-d '{
"data": {
"type": "buildUploadStateUpdated",
"id": "1239d9f7-12b5-4456-8859-12b04e6e8445",
"version": 1,
"attributes": { "oldState": "PROCESSING", "newState": "COMPLETE" },
"relationships": {
"instance": {
"data": { "type": "buildUploads", "id": "1239d9f7-12b5-4456-8859-12b04e6e8445" },
"links": { "self": "https://api.appstoreconnect.apple.com/v1/buildUploads/1239d9f7-12b5-4456-8859-12b04e6e8445" }
}
}
}
}'
If configured correctly:
- Youβll see messages in Slack and/or Microsoft Teams.
- The terminal will log something like:
π§ͺ Simulating Apple event: buildUploadStateUpdated - The HTTP response will confirm what was sent:
{
"ok": true,
"receivedType": "buildUploadStateUpdated",
"results": {
"slack": "sent",
"teams": "sent"
}
}
Remove or comment out these lines in .env when done:
# ENABLE_TEST_ENDPOINT=true
# INTERNAL_TEST_TOKEN=super-secret-token
This ensures the testing route is not exposed in production deployments.
MIT







