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.
- β 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
- β 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
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)
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) |
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
βββ utils/
β βββ eventTemplates.js # Teams formatter
β βββ slackTemplates.js # Slack formatter
β βββ stateDescriptions.js
βββ services/
β βββ signatureVerifier.js
β βββ teamsNotifier.js
β βββ slackNotifier.js
βββ 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






