REST API Reference

All endpoints are prefixed with /v1/projects/{project}/locations/{location}.

Default project is my-project and default location is us-central1. These are configurable via the PROJECT and LOCATION environment variables. See CLI & Configuration.

Workflows API

Create Workflow

POST /v1/projects/{project}/locations/{location}/workflows?workflowId={id}

Request body:

{
  "sourceContents": "main:\n  steps:\n    - done:\n        return: 42\n",
  "description": "Optional description"
}
FieldTypeRequiredDescription
sourceContentsstringYesYAML or JSON workflow definition (max 128 KB)
descriptionstringNoHuman-readable description (max 1000 chars)

Response: The workflow resource (see below).

Errors:

  • 400 if workflowId is missing, sourceContents is empty, or the workflow definition is invalid
  • 409 if a workflow with the same ID already exists

Note: The real GCW API returns a long-running Operation. The emulator completes immediately and returns the workflow directly.

Get Workflow

GET /v1/projects/{project}/locations/{location}/workflows/{workflowId}

Response:

{
  "name": "projects/my-project/locations/us-central1/workflows/my-wf",
  "state": "ACTIVE",
  "revisionId": "000001-abc",
  "sourceContents": "main:\n  steps:\n    ...",
  "description": "",
  "createTime": "2026-01-15T10:00:00Z",
  "updateTime": "2026-01-15T10:00:00Z"
}

Errors: 404 if the workflow does not exist.

List Workflows

GET /v1/projects/{project}/locations/{location}/workflows

Response:

{
  "workflows": [
    {
      "name": "projects/my-project/locations/us-central1/workflows/my-wf",
      "state": "ACTIVE",
      ...
    }
  ]
}

Update Workflow

PATCH /v1/projects/{project}/locations/{location}/workflows/{workflowId}

Request body: Same fields as Create (provide sourceContents and/or description).

Response: An Operation with done: true and the updated workflow in response.

Errors: 404 if the workflow does not exist.

Delete Workflow

DELETE /v1/projects/{project}/locations/{location}/workflows/{workflowId}

Response: An Operation with done: true.

Errors: 404 if the workflow does not exist.


Executions API

Create Execution

POST /v1/projects/{project}/locations/{location}/workflows/{workflowId}/executions

Request body:

{
  "argument": "{\"key\": \"value\"}"
}
FieldTypeRequiredDescription
argumentstringNoJSON-encoded string with execution arguments (max 32 KB)

The argument field is a JSON-encoded string, not a JSON object. This matches the real GCW API format.

Response: The execution resource with state: "ACTIVE".

The execution runs asynchronously. Poll the Get Execution endpoint to check for completion.

Errors: 404 if the workflow does not exist.

Get Execution

GET /v1/projects/{project}/locations/{location}/workflows/{workflowId}/executions/{executionId}

Successful response:

{
  "name": "projects/my-project/locations/us-central1/workflows/my-wf/executions/exec-abc123",
  "state": "SUCCEEDED",
  "result": "\"Hello, World!\"",
  "argument": "{\"name\": \"Alice\"}",
  "startTime": "2026-01-15T10:00:00Z",
  "endTime": "2026-01-15T10:00:01Z",
  "workflowRevisionId": "000001-abc"
}

Failed response:

{
  "name": "...",
  "state": "FAILED",
  "error": {
    "payload": "{\"message\":\"division by zero\",\"tags\":[\"ZeroDivisionError\"]}",
    "context": "step: calculate"
  },
  "startTime": "...",
  "endTime": "..."
}

The result field is a JSON-encoded string. The error.payload field is also a JSON-encoded string containing the error map.

Errors: 404 if the execution does not exist.

List Executions

GET /v1/projects/{project}/locations/{location}/workflows/{workflowId}/executions

Response:

{
  "executions": [
    {
      "name": "...",
      "state": "SUCCEEDED",
      ...
    }
  ]
}

Cancel Execution

POST /v1/projects/{project}/locations/{location}/workflows/{workflowId}/executions/{executionId}:cancel

Cancels an active execution. The execution state changes to CANCELLED.

Errors:

  • 404 if the execution does not exist
  • 400 if the execution is not in ACTIVE state

Execution states

StateDescription
ACTIVECurrently running
SUCCEEDEDCompleted successfully (check result field)
FAILEDCompleted with error (check error field)
CANCELLEDCancelled via the Cancel API

State transitions: ACTIVE -> SUCCEEDED, FAILED, or CANCELLED.


Callbacks API

List Callbacks

GET /v1/projects/{project}/locations/{location}/workflows/{workflowId}/executions/{executionId}/callbacks

Response:

{
  "callbacks": [
    {
      "name": "...",
      "method": "POST",
      "url": "http://localhost:8787/callbacks/abc123",
      "createTime": "2026-01-15T10:00:00Z"
    }
  ]
}

Send Callback

POST /callbacks/{callbackId}

Sends data to a waiting events.await_callback step. The request body can be any JSON payload and will be available in the callback result's http_request.body field.


gRPC API

The emulator also exposes a gRPC API on port 8788 (configurable via GRPC_PORT environment variable). The gRPC API implements the same operations as the REST API using the official Google Cloud Workflows protobuf definitions.

Workflows service

RPCDescription
ListWorkflowsList workflows in a project/location
GetWorkflowGet workflow details
CreateWorkflowCreate a new workflow (returns Operation)
DeleteWorkflowDelete a workflow (returns Operation)
UpdateWorkflowUpdate a workflow (returns Operation)

Executions service

RPCDescription
ListExecutionsList executions for a workflow
CreateExecutionStart a new execution
GetExecutionGet execution details
CancelExecutionCancel a running execution

Connecting via gRPC

import (
    workflowspb "cloud.google.com/go/workflows/apiv1/workflowspb"
    executionspb "cloud.google.com/go/workflows/executions/apiv1/executionspb"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
)

conn, err := grpc.Dial("localhost:8788", grpc.WithTransportCredentials(insecure.NewCredentials()))
workflowsClient := workflowspb.NewWorkflowsClient(conn)
executionsClient := executionspb.NewExecutionsClient(conn)

Emulator simplifications

The emulator differs from the real GCW API in these ways:

Real GCWEmulator
Create/Update/Delete return long-running Operations that must be polledReturns the result immediately
Requires IAM authenticationAccepts all requests without credentials
Supports pagination (page_size, page_token)Returns all results in one response
Supports filter and order_by parametersNot implemented