Workflows REST API
Edit page
Trigger a workflow and check its status from your own systems with the EAS REST API.
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
The EAS REST API exposes endpoints for triggering a workflow and reading run details. All endpoints live under https://api.expo.dev. Requests and responses are JSON.
Authentication
Both endpoints require an EAS access token, sent as a bearer token in the Authorization header.
For production integrations, create a robot user on the account that owns the project and give it a scoped role. The token then represents the robot user, not a person. You can revoke it without affecting any user. A personal access token also works for one-off scripts.
Authorization: Bearer <EXPO_TOKEN> Content-Type: application/json
Trigger a workflow
POST /v2/workflows/dispatch
Resolves the workflow file on the given Git ref, validates inputs against the workflow_dispatch schema declared in the workflow, and enqueues a new run.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
appId | string (UUID) | Yes | The EAS project ID. Find it on the project page or in app config under extra.eas.projectId. |
gitRef | string | Yes | A branch name (main), tag (v1.0.0), commit SHA, or fully qualified ref (refs/heads/main, refs/tags/v1.0.0). |
fileName | string | Yes | The workflow file name only, such as deploy.yml. Do not include the .eas/workflows/ prefix or any other path segments. |
inputs | object | No | Values for inputs declared under on.workflow_dispatch.inputs in the workflow file. Validated against the declared schema. |
Response
Returns 200 OK with the new workflow run ID and a link to the run in the dashboard:
{ "data": { "id": "019d9d17-013a-7e05-89aa-4aa83ff68c32", "url": "https://expo.dev/accounts/acme/projects/example/workflows/019d9d17-013a-7e05-89aa-4aa83ff68c32" } }
Example
- curl -X POST "https://api.expo.dev/v2/workflows/dispatch" \ -H "Authorization: Bearer $EXPO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "appId": "a415eac6-231a-4b38-b481-3255a59f13b8", "gitRef": "main", "fileName": "deploy.yml", "inputs": { "environment": "production" } }'Errors
| Status | Reason |
|---|---|
| 400 | The request body fails schema validation, or inputs do not match the workflow's declared schema. |
| 403 | The token does not have access to the given appId. |
| 404 | The Git ref does not exist in the linked repository, or the workflow file is not found on that ref. |
Get a workflow run
GET /v2/workflows/runs/:workflowRunId
Returns the workflow run and the jobs it contains. Use this endpoint to poll for completion after triggering a run, or to render a run's details in your own UI.
Response
{ "data": { "id": "019d9d17-013a-7e05-89aa-4aa83ff68c32", "status": "in-progress", "url": "https://expo.dev/accounts/acme/projects/example/workflows/019d9d17-013a-7e05-89aa-4aa83ff68c32", "gitCommitHash": "564b61ebdd403d28b5dc616a12ce160b91585b5b", "gitCommitMessage": "Add home screen", "requestedGitRef": "refs/heads/main", "triggerEventType": "MANUAL", "createdAt": "2026-05-22T15:04:11.000Z", "updatedAt": "2026-05-22T15:05:42.000Z", "jobs": [ { "id": "019d9d17-1a3f-7c10-bdee-5f2811a9d6ad", "key": "build_ios", "name": "Build iOS", "type": "build", "status": "in-progress", "requiredJobKeys": [], "environment": "production", "outputs": {}, "errors": [], "buildId": "f9609423-5072-4ea2-a0a5-c345eedf2c2a", "submissionId": null, "createdAt": "2026-05-22T15:04:11.000Z", "updatedAt": "2026-05-22T15:04:42.000Z" } ] } }
The run's status is one of:
| Value | Meaning |
|---|---|
new | The run is queued and has not started yet. |
in-progress | At least one job is running. |
action-required | The run is paused and waiting on a manual action, such as approval. |
success | The run finished and every job succeeded. Terminal. |
failure | The run finished with at least one failed job. Terminal. |
canceled | The run was canceled before it finished. Terminal. |
Each entry in jobs includes its own status, one of:
| Value | Meaning |
|---|---|
new | The job is queued. |
in-progress | The job is running. |
action-required | The job is paused and waiting on a manual action, such as approval. |
pending-cancel | A cancellation has been requested but the job has not stopped yet. |
success | The job succeeded. Terminal. |
failure | The job failed. Terminal. |
canceled | The job was canceled. Terminal. |
skipped | The job was skipped because a required upstream job did not succeed. |
outputs contains any values the job sets with outputs: in the workflow file. Any referenced secrets appear as placeholders in the response. Jobs of type: build include buildId, and jobs of type: submission include submissionId. Each ID links to the underlying EAS Build or EAS Submit record.
Example
Save the following as a shell script (or paste into your terminal) to trigger a run and poll until it reaches a terminal status:
RUN_ID=$(curl -s -X POST "https://api.expo.dev/v2/workflows/dispatch" \ -H "Authorization: Bearer $EXPO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"appId":"...","gitRef":"main","fileName":"deploy.yml"}' \ | jq -r '.data.id') while true; do STATUS=$(curl -s "https://api.expo.dev/v2/workflows/runs/$RUN_ID" \ -H "Authorization: Bearer $EXPO_TOKEN" \ | jq -r '.data.status') echo "status: $STATUS" case "$STATUS" in success|failure|canceled) break ;; esac sleep 10 done
Errors
| Status | Reason |
|---|---|
| 400 | workflowRunId is not a valid UUID. |
| 403 | The token does not have access to the run's project. |
| 404 | No workflow run exists with that ID. |
Next step
Reference for the workflow YAML file, including the workflow_dispatch trigger and input schema.