> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a journey synchronously

> Get the journey result in the start response instead of polling for it, for server-to-server API journeys with prefilled data.

By default, starting a journey is asynchronous. The [`/journey/start`](/docs/go-v2/api-reference/endpoint/start-journey) request returns an `instanceId` straight away, and you poll [`/journey/state/fetch`](/docs/go-v2/api-reference/endpoint/fetch-journey-state) for the result.

With synchronous execution, the start request waits for the journey to finish and returns the result in the same response. If the journey doesn't finish within the wait time, then you get the `instanceId` and poll for the result as usual.

<Warning>
  Set your HTTP client's read timeout higher than `syncWaitSeconds`. Without `syncWaitSeconds`, use a timeout of at least 60 seconds. If your client closes the connection early, then you lose the `instanceId`, and sending the request again starts a second, separate journey.
</Warning>

## When to use synchronous execution

Use synchronous execution for server-to-server API journeys that meet both of these conditions:

* You supply all the data the journey needs upfront in `context.subject`.
* The journey usually finishes within a few seconds. For example, a journey that screens against PEPs and sanctions lists or runs a data verification check.

Don't use synchronous execution for:

* Hosted journeys, where `delivery` is `"page"`. The API rejects the request.
* Journeys that collect data from the end user, such as document images or a selfie.
* Long-running journeys that often take longer than the wait time.

## Before you begin

Make sure you have:

* **Published API journey**: All the domain elements that the journey needs must be in the start interaction, so that you can prefill them. To move domain elements to the start interaction, see [Start a journey in partial prefill mode](/docs/go-v2/developer-integration/execute-customer-journeys/start-a-journey-step#start-a-journey-partial-prefill-mode).
* **Access token**: Obtained in [Step 1: Authenticate](/docs/go-v2/developer-integration/execute-customer-journeys/authenticate).

## Start a journey synchronously

To wait for the result, set `inlineResult` to `true` in `context.config`. To limit how long the request waits, set `syncWaitSeconds`.

```bash cURL theme={null}
curl --request POST \
  --url https://eu.platform.go.gbgplc.com/v2/captain/journey/start \
  --header 'Authorization: Bearer your_access_token' \
  --header 'Content-Type: application/json' \
  --max-time 60 \
  --data '{
    "resourceId": "9dcd95e06495ec32c9ad149283a935548e4a380461b9ee6981af0fef5c70c8c3@5f7yigc4",
    "context": {
      "config": {
        "delivery": "api",
        "inlineResult": true,
        "syncWaitSeconds": 30
      },
      "subject": {
        "identity": {
          "firstName": "John",
          "lastNames": ["Doe"],
          "dateOfBirth": "1982-09-27",
          "currentAddress": {
            "lines": ["New Orleans, Louisiana, U.S."],
            "locality": "New Orleans",
            "postalCode": "900010",
            "country": "US"
          }
        }
      }
    }
  }'
```

### Request body fields

These fields control synchronous execution. For the other start request fields, see [Step 2: Start a journey](/docs/go-v2/developer-integration/execute-customer-journeys/start-a-journey-step#request-body-fields).

| Field | Required | Description |
| - | - | - |
| `context.config.delivery` | Yes | Set to `"api"`. Synchronous execution works only with API delivery. |
| `context.config.inlineResult` | Yes | Set to `true` to wait for the result. If you omit it or set it to `false`, then the journey runs asynchronously. |
| `context.config.syncWaitSeconds` | No | The maximum number of seconds to wait, as a positive integer. Defaults to the platform maximum, which is currently 55 seconds. The API reduces a higher value to the maximum. |

### Validation errors

The API rejects the request with a `400` error, and doesn't create a journey, in these cases:

* You set `syncWaitSeconds` without setting `inlineResult` to `true`.
* You set `syncWaitSeconds` to zero, a negative number or a value that isn't an integer.
* You set `inlineResult` to `true` and `delivery` isn't `"api"`.

## Handle the response

The API returns `201 Created` for every synchronous outcome. Check the top-level `status` field to decide what to do next.

| `status` | Meaning | `state` object | Next step |
| - | - | - | - |
| `completed` | The journey finished within the wait time. | Included | Read the result from `state.context.result` and the module outputs from `state.context.process.steps`. |
| `failed` | The journey finished but failed. For example, a provider rejected the check. | Included | Inspect `state.context.result` and `state.context.process.steps` for details. In this case, `state.status` is `Error`. |
| `pending` | The journey is still running and the wait time ran out. | Not included | Poll `/journey/state/fetch` with the `instanceId`. See [Step 5: Fetch journey state](/docs/go-v2/developer-integration/execute-customer-journeys/fetch-journey-state-step). |
| `awaiting-input` | The journey reached an interaction that needs more data. | Not included | Fetch the interaction and submit the data. See [Step 3: Fetch the interaction](/docs/go-v2/developer-integration/execute-customer-journeys/retrieve-tasks-step). |
| `started` | The platform couldn't wait for this request. The journey is running. | Not included | Poll `/journey/state/fetch` with the `instanceId`, as for `pending`. |

The `state` object has the same structure as the `/journey/state/fetch` response. You can parse the result of both modes with the same code.

<Note>
  The top-level `status` describes the start call, and `state.status` describes the journey. They usually match, but when a journey fails, the top-level `status` is `failed` and `state.status` is `Error`. Base your logic on the top-level `status`, and read the details from `state`.
</Note>

### Example completed response

```json JSON expandable theme={null}
{
  "instanceId": "Pq_hhIX6-sHUy9FLSDzPLu",
  "status": "completed",
  "message": "Journey Pq_hhIX6-sHUy9FLSDzPLu started successfully",
  "state": {
    "instanceId": "Pq_hhIX6-sHUy9FLSDzPLu",
    "status": "Completed",
    "context": {
      "process": {
        "journey": {
          "endedAt": "2026-03-16T23:56:06.417Z",
          "durationMilliSec": 2320,
          "id": "9dcd95e06495ec32c9ad149283a935548e4a380461b9ee6981af0fef5c70c8c3",
          "version": "5f7yigc4",
          "name": "Age verification",
          "startedAt": "2026-03-16T23:56:04.097Z"
        },
        "instance": {
          "id": "Pq_hhIX6-sHUy9FLSDzPLu",
          "instanceId": "Pq_hhIX6-sHUy9FLSDzPLu"
        },
        "steps": [
          {
            "nodeId": "mp586xkhweua5v4z5n",
            "result": {
              "status": "complete",
              "note": {
                "expectid_age": {
                  "id_number": "6554532688"
                }
              },
              "advice": {
                "age_result_capabilities": [
                  "resultcode.confirm.age"
                ]
              },
              "outcome": "Of Age"
            },
            "process": {}
          }
        ]
      },
      "subject": {
        "identity": {
          "dateOfBirth": "1982-09-27",
          "firstName": "John",
          "lastNames": [
            "Doe"
          ],
          "currentAddress": {
            "postalCode": "900010",
            "country": "US",
            "lines": [
              "New Orleans, Louisiana, U.S."
            ],
            "locality": "New Orleans"
          }
        }
      },
      "result": {
        "status": "complete",
        "advice": {}
      }
    }
  }
}
```

For a description of each field in `state`, see [Step 5: Fetch journey state](/docs/go-v2/developer-integration/execute-customer-journeys/fetch-journey-state-step#response-fields).

### Handle each outcome in code

The following example starts a journey synchronously and handles each `status`. The `pollUntilComplete` function is the polling example from [Step 5: Fetch journey state](/docs/go-v2/developer-integration/execute-customer-journeys/fetch-journey-state-step#polling-for-completion). You write `handleInteraction` to collect and submit the extra data.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function startJourneySync(subject, accessToken) {
    const response = await fetch('https://eu.platform.go.gbgplc.com/v2/captain/journey/start', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        resourceId: process.env.JOURNEY_RESOURCE_ID,
        context: {
          config: { delivery: 'api', inlineResult: true, syncWaitSeconds: 30 },
          subject
        }
      }),
      signal: AbortSignal.timeout(60000)
    });

    if (!response.ok) {
      throw new Error(`Journey start failed with HTTP ${response.status}`);
    }

    const start = await response.json();

    switch (start.status) {
      case 'completed':
      case 'failed':
        return start.state;
      case 'pending':
      case 'started':
        return pollUntilComplete(start.instanceId, accessToken);
      case 'awaiting-input':
        return handleInteraction(start.instanceId, accessToken);
      default:
        throw new Error(`Unexpected status: ${start.status}`);
    }
  }
  ```

  ```python Python theme={null}
  import os
  import requests

  def start_journey_sync(subject, access_token):
      response = requests.post(
          'https://eu.platform.go.gbgplc.com/v2/captain/journey/start',
          headers={
              'Authorization': f'Bearer {access_token}',
              'Content-Type': 'application/json'
          },
          json={
              'resourceId': os.environ['JOURNEY_RESOURCE_ID'],
              'context': {
                  'config': {'delivery': 'api', 'inlineResult': True, 'syncWaitSeconds': 30},
                  'subject': subject
              }
          },
          timeout=60
      )
      response.raise_for_status()
      start = response.json()

      if start['status'] in ('completed', 'failed'):
          return start['state']
      if start['status'] in ('pending', 'started'):
          return poll_until_complete(start['instanceId'], access_token)
      if start['status'] == 'awaiting-input':
          return handle_interaction(start['instanceId'], access_token)
      raise ValueError(f"Unexpected status: {start['status']}")
  ```
</CodeGroup>

## Best practices

* When the response `status` is `pending` or `started`, poll with the returned `instanceId`. Don't send the start request again, because that starts a second journey.
* If your journey sends a completion webhook, then the webhook still fires in synchronous mode. It might arrive before the start response does. Process webhook events idempotently, so that you handle each result once.
* Keep `syncWaitSeconds` below the timeout of every component between your server and GBG Go, such as proxies and load balancers.

## FAQ

<Accordion title="What is the difference between sync and async journey execution?">
  In the v2 API, journey execution is asynchronous by default.

  When you start a journey, the API returns an `instanceId` immediately. Backend modules such as document verification, face matching, data checks process in the background.

  To track progress, you poll the `/journey/interaction/fetch` endpoint to discover when the next interaction is available, or poll `/journey/state/fetch` to check the overall journey status.

  The recommended polling approach is to call the fetch endpoint at a base interval of 10 seconds, apply backoff on errors, and stop when the journey status changes from `InProgress` to either `Completed` or `Error`.

  For server-to-server API journeys where you prefill all the data, you can opt in to synchronous execution instead. Set `inlineResult` to `true` in `context.config`, and the start request waits for the journey and returns the result. For details, see [Run a journey synchronously](/docs/go-v2/tutorials/run-journeys-synchronously).

  If you are migrating from v1: the `async: true` flag was a v1-specific concept. In v2, async behaviour is the default and does not need to be specified.
</Accordion>
