Skip to main content
Glama
webhooks.md7.39 kB
--- title: Webhooks description: Learn how to configure webhooks to get alerts on EAS Build and Submit completion. --- EAS can alert you as soon as your build or submission is completed via a webhook. Webhooks need to be configured per project. For example, if you want to be alerted for both `@johndoe/awesomeApp` and `@johndoe/coolApp`, in each directory, run the command: After running it, you'll be prompted to choose the webhook event type (unless you provide the `--event BUILD|SUBMIT` parameter). Next, provide the webhook URL (or specify it with the `--url` flag) that handles HTTP POST requests. Additionally, you'll have to input a webhook signing secret, if you have not already provided it with the `--secret` flag. It must be at least 16 characters long, and it will be used to calculate the signature of the request body which we send as the value of the `expo-signature` HTTP header. You can use the [signature to verify a webhook request](#webhook-server) is genuine. EAS calls your webhook using an HTTP POST request. All the data is passed in the request body. EAS sends the data as a JSON object. If the webhook responds with an HTTP status code outside of the 200-399 range, delivery will be attempted a few more times with exponential back-off. Additionally, we send an `expo-signature` HTTP header with the hash signature of the payload. You can use this signature to verify the authenticity of the request. The signature is a hex-encoded HMAC-SHA1 digest of the request body, using your webhook secret as the HMAC key. > If you want to test the above webhook locally, you can use a service such as [ngrok](https://ngrok.com/docs) to forward `localhost:8080` via a tunnel and make it publicly accessible with the URL `ngrok` gives you. You can always change your webhook URL and/or webhook secret by running command: You can find the webhook ID by running the command: If you want us to stop sending requests to your webhook, run the command below and choose the webhook from the list: ## Webhook payload The build webhook payload may look as the example below: ```json { "id": "147a3212-49fd-446f-b4e3-a6519acf264a", "accountName": "dsokal", "projectName": "example", "buildDetailsPageUrl": "https://expo.dev/accounts/dsokal/projects/example/builds/147a3212-49fd-446f-b4e3-a6519acf264a", "parentBuildId": "75ac0be7-0d90-46d5-80ec-9423fa0aaa6b", // available for build retries "appId": "bc0a82de-65a5-4497-ad86-54ff1f53edf7", "initiatingUserId": "d1041496-1a59-423a-8caf-479bb978203a", "cancelingUserId": null, // available for canceled builds "platform": "android", // or "ios" "status": "errored", // or: "finished", "canceled" "artifacts": { "buildUrl": "https://expo.dev/artifacts/eas/wyodu9tua2ZuKKiaJ1Nbkn.aab", // available for successful builds "logsS3KeyPrefix": "production/f9609423-5072-4ea2-a0a5-c345eedf2c2a" }, "metadata": { "appName": "example", "username": "dsokal", "workflow": "managed", "appVersion": "1.0.2", "appBuildVersion": "123", "cliVersion": "0.37.0", "sdkVersion": "41.0.0", "buildProfile": "production", "distribution": "store", "appIdentifier": "com.expo.example", "gitCommitHash": "564b61ebdd403d28b5dc616a12ce160b91585b5b", "gitCommitMessage": "Add home screen", "runtimeVersion": "1.0.2", "channel": "default", // available for EAS Update "releaseChannel": "default", // available for legacy updates "reactNativeVersion": "0.60.0", "trackingContext": { "platform": "android", "account_id": "7c34cbf1-efd4-4964-84a1-c13ed297aaf9", "dev_client": false, "project_id": "bc0a82de-65a5-4497-ad86-54ff1f53edf7", "tracking_id": "a3fdefa7-d129-42f2-9432-912050ab0f10", "project_type": "managed", "dev_client_version": "0.6.2" }, "credentialsSource": "remote", "isGitWorkingTreeDirty": false, "message": "release build", // message attached to the build "runFromCI": false }, "metrics": { "memory": 895070208, "buildEndTimestamp": 1637747861168, "totalDiskReadBytes": 692224, "buildStartTimestamp": 1637747834445, "totalDiskWriteBytes": 14409728, "cpuActiveMilliseconds": 12117.540078, "buildEnqueuedTimestamp": 1637747792476, "totalNetworkEgressBytes": 355352, "totalNetworkIngressBytes": 78781667 }, // available for failed builds "error": { "message": "Unknown error. Please see logs.", "errorCode": "UNKNOWN_ERROR" }, "createdAt": "2021-11-24T09:53:01.155Z", "enqueuedAt": "2021-11-24T09:53:01.155Z", "provisioningStartedAt": "2021-11-24T09:54:01.155Z", "workerStartedAt": "2021-11-24T09:54:11.155Z", "completedAt": "2021-11-24T09:57:42.715Z", "updatedAt": "2021-11-24T09:57:42.715Z", "expirationDate": "2021-12-24T09:53:01.155Z", "priority": "high", // or: "normal", "low" "resourceClass": "android-n2-1.3-12", "actualResourceClass": "android-n2-1.3-12", "maxRetryTimeMinutes": 3600 // max retry time for failed/canceled builds } ``` The submit webhook payload may look as the example below: ```json { "id": "0374430d-7776-44ad-be7d-8513629adc54", "accountName": "dsokal", "projectName": "example", "submissionDetailsPageUrl": "https://expo.dev/accounts/dsokal/projects/example/builds/0374430d-7776-44ad-be7d-8513629adc54", "parentSubmissionId": "75ac0be7-0d90-46d5-80ec-9423fa0aaa6b", // available for submission retries "appId": "23c0e405-d282-4399-b280-5689c3e1ea85", "archiveUrl": "http://archive.url/abc.apk", "initiatingUserId": "7bee4c21-3eaa-4011-a0fd-3678b6537f47", "cancelingUserId": null, // available for canceled submissions "turtleBuildId": "8c84111e-6d39-449c-9895-071d85fd3e61", // available when submitting a build from EAS "platform": "android", // or "ios" "status": "errored", // or: "finished", "canceled" "submissionInfo": { // available for failed submissions "error": { "message": "Android version code needs to be updated", "errorCode": "SUBMISSION_SERVICE_ANDROID_OLD_VERSION_CODE_ERROR" }, "logsUrl": "https://submission-service-logs.s3-us-west-1.amazonaws.com/production/submission_728aa20b-f7a9-4da7-9b64-39911d427b19.txt" }, "createdAt": "2021-11-24T10:15:32.822Z", "updatedAt": "2021-11-24T10:17:32.822Z", "completedAt": "2021-11-24T10:17:32.822Z", "maxRetryTimeMinutes": 3600 // max retry time for failed/canceled submissions } ``` ## Webhook server Here's an example of how you can implement your server: ```js server.js const crypto = require('crypto'); const express = require('express'); const bodyParser = require('body-parser'); const safeCompare = require('safe-compare'); const app = express(); app.use(bodyParser.text({ type: '*/*' })); app.post('/webhook', (req, res) => { const expoSignature = req.headers['expo-signature']; // process.env.SECRET_WEBHOOK_KEY has to match SECRET value set with `eas webhook:create` command const hmac = crypto.createHmac('sha1', process.env.SECRET_WEBHOOK_KEY); hmac.update(req.body); const hash = `sha1=${hmac.digest('hex')}`; if (!safeCompare(expoSignature, hash)) { res.status(500).send("Signatures didn't match!"); } else { // Do something here. For example, send a notification to Slack! // console.log(req.body); res.send('OK!'); } }); app.listen(8080, () => console.log('Listening on port 8080')); ```

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server