> ## 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.

# Core SDK quickstart

> Run your first developer-first GBG Go journey with the Core SDK, in TypeScript or Java

This quickstart guides you through your first developer-first integration using the GBG Go Core SDK, in TypeScript or Java. You authenticate, start a journey, fetch the first interaction, submit data, and poll for the result.

> [!TIP]
>
> If you're unsure of the best way to integrate, then start with [Get started with GBG Go](https://docs.go.gbgplc.com/docs/go-v2/get-started/integration-sequence.md).

> [!NOTE]
>
> This quickstart runs the same journey as the [API-first integration quickstart](https://docs.go.gbgplc.com/docs/go-v2/get-started/quickstart/quickstartdev.md), which makes each call with raw HTTP. Read the two side by side to see what the SDK does for you.

## Before you start

Before running this quickstart, make sure you have:

* An API client created in the Account management portal, which provides the client ID and client secret you use to authenticate. For instructions, see [Manage API clients](https://docs.go.gbgplc.com/docs/go-v2/platform/account-management/manage-api-clients.md).
* Permission to create and publish journeys in the Journey builder.
* For TypeScript, Node.js 18 or later, and npm.
* For Java, JDK 11 or later, and Maven.

## Step 1: Set up your journey

You need a published journey with the **Age Verification** module. Follow the steps in [Option 2: Create a journey from scratch](https://docs.go.gbgplc.com/docs/go-v2/get-started/quickstart/quickstartbusiness.md#option-2-create-a-journey-from-scratch) of the Platform quickstart to add the module to a journey and publish it.

> [!NOTE]
>
> The program submits a name and a date of birth. Add only the **Age Verification** module, so that the journey doesn't wait for anything else. A journey with more modules, for example document checks, stays in progress after the submit.

Once you've published your journey to Preview, copy the **Resource ID** and **Version number** from the **Dashboard**. You combine them as `<resourceId>@<version>`, for example:

```
97c8b0c5272ba450c48899cc78f6e3f3ba89b5d131c42f7ea972588bd8213b3e@y5z6bj7o
```

## Step 2: Create a project

> [tab] TypeScript
>
> Create a folder for the quickstart, then install the SDK and `tsx`, which runs TypeScript files directly:
>
> ```bash theme={null}
> mkdir go-sdk-quickstart
> cd go-sdk-quickstart
> npm init -y
> npm install @gbg/go-core
> npm install --save-dev tsx
> ```

> [tab] Java
>
> Create a folder for the quickstart, with a source folder inside it:
>
> ```bash theme={null}
> mkdir -p go-sdk-quickstart/src/main/java
> cd go-sdk-quickstart
> ```
>
> Create a file named `pom.xml` in the `go-sdk-quickstart` folder. It adds the SDK as a dependency, and pins a compiler plugin that supports the `release` setting:
>
> ```xml pom.xml theme={null}
> <?xml version="1.0" encoding="UTF-8"?>
> <project xmlns="http://maven.apache.org/POM/4.0.0"
>          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
>   <modelVersion>4.0.0</modelVersion>
>
>   <groupId>com.example</groupId>
>   <artifactId>go-sdk-quickstart</artifactId>
>   <version>1.0.0</version>
>
>   <properties>
>     <maven.compiler.release>11</maven.compiler.release>
>     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
>   </properties>
>
>   <dependencies>
>     <dependency>
>       <groupId>com.gbg</groupId>
>       <artifactId>go-core-sdk</artifactId>
>       <version>0.2.1</version>
>     </dependency>
>   </dependencies>
>
>   <build>
>     <plugins>
>       <plugin>
>         <groupId>org.apache.maven.plugins</groupId>
>         <artifactId>maven-compiler-plugin</artifactId>
>         <version>3.13.0</version>
>       </plugin>
>     </plugins>
>   </build>
> </project>
> ```
>
> > [!TIP]
> >
> > To use Gradle instead, add `implementation 'com.gbg:go-core-sdk:0.2.1'` to your dependencies. The rest of this quickstart uses Maven.

## Step 3: Set your credentials

The program reads your credentials and journey from environment variables. Set them in the terminal you'll run it from:

```bash theme={null}
export GBG_CLIENT_ID="your-client-id"
export GBG_CLIENT_SECRET="your-client-secret"
export JOURNEY_RESOURCE_ID="your-resource-id@your-version"
```

> [!WARNING]
>
> Never commit your client secret, and never put it in front-end code. The SDK runs on your server, which is the only place your credentials belong.

## Step 4: Write the program

> [tab] TypeScript
>
> Create a file named `quickstart.ts` in the project folder with this code:
>
> ```typescript quickstart.ts expandable theme={null}
> import { Go } from "@gbg/go-core";
> import { GoError } from "@gbg/go-core/models/errors";
>
> const SERVER_URL = "https://eu.platform.go.gbgplc.com/v2/captain";
>
> const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
>
> async function main() {
>   // Exchange your client credentials for an access token
>   const tokenResponse = await new Go().tokens.generate({
>     grantType: "client_credentials",
>     clientId: process.env.GBG_CLIENT_ID!,
>     clientSecret: process.env.GBG_CLIENT_SECRET!,
>     scope: "gbg.token",
>   });
>
>   const accessToken = tokenResponse.accessToken;
>   if (!accessToken) {
>     throw new Error("The token endpoint returned no access token");
>   }
>
>   const go = new Go({
>     serverURL: SERVER_URL,
>     customerAccess: accessToken,
>   });
>
>   // Start a journey
>   const started = await go.journeys.start({
>     resourceId: process.env.JOURNEY_RESOURCE_ID!,
>     context: {
>       config: { delivery: "api" },
>       subject: {},
>     },
>   });
>
>   const { instanceId } = started;
>   console.log(`Started journey instance ${instanceId}`);
>
>   // Fetch the first interaction
>   let interactionId: string | undefined;
>
>   for (let attempt = 1; attempt <= 10 && !interactionId; attempt++) {
>     const interaction = await go.interactions.fetch(
>       { interactionAccess: accessToken },
>       { body: { instanceId } },
>     );
>
>     if (interaction.view === "UNKNOWN") {
>       throw new Error("GBG Go returned an interaction the SDK doesn't recognise");
>     }
>
>     interactionId = interaction.interactionId;
>
>     if (interactionId) {
>       console.log("Outstanding domain elements:", interaction.outstanding);
>     } else {
>       await sleep(2000);
>     }
>   }
>
>   if (!interactionId) {
>     throw new Error("No interaction became available");
>   }
>
>   // Submit interaction data
>   const submitted = await go.interactions.submit(
>     { interactionAccess: accessToken },
>     {
>       instanceId,
>       interactionId,
>       participants: [
>         { domainElementId: "FullName" },
>         { domainElementId: "DateOfBirth" },
>       ],
>       context: {
>         subject: {
>           identity: {
>             firstName: "Jane",
>             lastNames: ["Doe"],
>             dateOfBirth: "1992-10-01",
>           },
>         },
>       },
>     },
>   );
>
>   console.log(`Submit status: ${submitted.status}`);
>
>   // Poll the journey state until the journey finishes
>   for (let attempt = 1; attempt <= 30; attempt++) {
>     const state = await go.journeys.getState({ body: { instanceId } });
>
>     if (state.view === "UNKNOWN") {
>       throw new Error("GBG Go returned a journey state the SDK doesn't recognise");
>     }
>
>     if (state.status !== "InProgress") {
>       console.log(`Journey finished with status ${state.status}`);
>       console.log(JSON.stringify(state.result, null, 2));
>       return;
>     }
>
>     await sleep(2000);
>   }
>
>   console.log("The journey is still in progress. Check it in the Investigation portal.");
> }
>
> main().catch((error) => {
>   if (error instanceof GoError) {
>     console.error(`GBG Go returned HTTP ${error.statusCode}: ${error.body}`);
>   } else {
>     console.error(error);
>   }
>   process.exit(1);
> });
> ```

> [tab] Java
>
> Create a file named `Quickstart.java` in `src/main/java` with this code:
>
> ```java Quickstart.java expandable theme={null}
> import com.gbg.gocore.Go;
> import com.gbg.gocore.models.ClientCredentialsGrantRequest;
> import com.gbg.gocore.models.ClientCredentialsGrantRequestGrantType;
> import com.gbg.gocore.models.InteractionFetchResponse;
> import com.gbg.gocore.models.JourneyStartResponse;
> import com.gbg.gocore.models.Scope;
> import com.gbg.gocore.models.StateFetchResponse;
> import com.gbg.gocore.models.errors.GoException;
> import com.gbg.gocore.models.operations.Config;
> import com.gbg.gocore.models.operations.FetchInteractionRequestBody;
> import com.gbg.gocore.models.operations.FetchInteractionResponseBody;
> import com.gbg.gocore.models.operations.FetchInteractionSecurity;
> import com.gbg.gocore.models.operations.GetJourneyStateRequestBody;
> import com.gbg.gocore.models.operations.GetJourneyStateResponseBody;
> import com.gbg.gocore.models.operations.Participant;
> import com.gbg.gocore.models.operations.StartJourneyContext;
> import com.gbg.gocore.models.operations.StartJourneyContextSubject;
> import com.gbg.gocore.models.operations.StartJourneyRequest;
> import com.gbg.gocore.models.operations.SubmitInteractionContext;
> import com.gbg.gocore.models.operations.SubmitInteractionIdentity;
> import com.gbg.gocore.models.operations.SubmitInteractionRequest;
> import com.gbg.gocore.models.operations.SubmitInteractionResponse;
> import com.gbg.gocore.models.operations.SubmitInteractionSecurity;
> import com.gbg.gocore.models.operations.SubmitInteractionSubject;
> import java.io.UncheckedIOException;
> import java.util.List;
>
> public class Quickstart {
>
>     private static final String SERVER_URL = "https://eu.platform.go.gbgplc.com/v2/captain";
>
>     public static void main(String[] args) throws InterruptedException {
>         try {
>             run();
>         } catch (GoException e) {
>             System.err.printf("GBG Go returned HTTP %d: %s%n", e.code(), e.bodyAsString().orElse(""));
>             System.exit(1);
>         } catch (UncheckedIOException e) {
>             System.err.println("Couldn't reach GBG Go: " + e.getMessage());
>             System.exit(1);
>         }
>     }
>
>     private static void run() throws InterruptedException {
>         // Exchange your client credentials for an access token
>         String accessToken = Go.builder().build()
>                 .tokens()
>                 .generate()
>                 .request(ClientCredentialsGrantRequest.builder()
>                         .grantType(ClientCredentialsGrantRequestGrantType.CLIENT_CREDENTIALS)
>                         .clientId(System.getenv("GBG_CLIENT_ID"))
>                         .clientSecret(System.getenv("GBG_CLIENT_SECRET"))
>                         .scope(Scope.GBG_TOKEN)
>                         .build())
>                 .call()
>                 .object()
>                 .flatMap(body -> body.accessToken())
>                 .orElseThrow(() -> new IllegalStateException("The token endpoint returned no access token"));
>
>         Go go = Go.builder()
>                 .serverURL(SERVER_URL)
>                 .customerAccess(accessToken)
>                 .build();
>
>         // Start a journey
>         String instanceId = go.journeys().start()
>                 .request(StartJourneyRequest.builder()
>                         .resourceId(System.getenv("JOURNEY_RESOURCE_ID"))
>                         .context(StartJourneyContext.builder()
>                                 .config(Config.builder().delivery("api").build())
>                                 .subject(StartJourneyContextSubject.builder().build())
>                                 .build())
>                         .build())
>                 .call()
>                 .journeyStartResponse()
>                 .map(JourneyStartResponse::instanceId)
>                 .orElseThrow(() -> new IllegalStateException("The journey didn't start"));
>
>         System.out.println("Started journey instance " + instanceId);
>
>         // Fetch the first interaction
>         String interactionId = null;
>
>         for (int attempt = 1; attempt <= 10 && interactionId == null; attempt++) {
>             FetchInteractionResponseBody body = go.interactions().fetch()
>                     .security(FetchInteractionSecurity.builder()
>                             .interactionAccess(accessToken)
>                             .build())
>                     .body(FetchInteractionRequestBody.builder()
>                             .instanceId(instanceId)
>                             .build())
>                     .call()
>                     .oneOf()
>                     .orElseThrow();
>
>             if (!(body instanceof InteractionFetchResponse)) {
>                 throw new IllegalStateException("Expected the full interaction view, got " + body.view());
>             }
>
>             InteractionFetchResponse interaction = (InteractionFetchResponse) body;
>             interactionId = interaction.interactionId().orElse(null);
>
>             if (interactionId != null) {
>                 System.out.println("Outstanding domain elements: " + interaction.outstanding().orElse(List.of()));
>             } else {
>                 Thread.sleep(2000);
>             }
>         }
>
>         if (interactionId == null) {
>             throw new IllegalStateException("No interaction became available");
>         }
>
>         // Submit interaction data
>         SubmitInteractionResponse submitted = go.interactions().submit()
>                 .security(SubmitInteractionSecurity.builder()
>                         .interactionAccess(accessToken)
>                         .build())
>                 .request(SubmitInteractionRequest.builder()
>                         .instanceId(instanceId)
>                         .interactionId(interactionId)
>                         .participants(List.of(
>                                 Participant.builder().domainElementId("FullName").build(),
>                                 Participant.builder().domainElementId("DateOfBirth").build()))
>                         .context(SubmitInteractionContext.builder()
>                                 .subject(SubmitInteractionSubject.builder()
>                                         .identity(SubmitInteractionIdentity.builder()
>                                                 .firstName("Jane")
>                                                 .lastNames(List.of("Doe"))
>                                                 .dateOfBirth("1992-10-01")
>                                                 .build())
>                                         .build())
>                                 .build())
>                         .build())
>                 .call();
>
>         submitted.interactionSubmitResponse()
>                 .ifPresent(response -> System.out.println("Submit status: " + response.status().value()));
>
>         // Poll the journey state until the journey finishes
>         for (int attempt = 1; attempt <= 30; attempt++) {
>             GetJourneyStateResponseBody body = go.journeys().getState()
>                     .body(GetJourneyStateRequestBody.builder()
>                             .instanceId(instanceId)
>                             .build())
>                     .call()
>                     .oneOf()
>                     .orElseThrow();
>
>             if (!(body instanceof StateFetchResponse)) {
>                 throw new IllegalStateException("Expected the full state view, got " + body.view());
>             }
>
>             StateFetchResponse state = (StateFetchResponse) body;
>
>             if (!"InProgress".equals(state.status())) {
>                 System.out.println("Journey finished with status " + state.status());
>                 System.out.println(state.result().orElse(null));
>                 return;
>             }
>
>             Thread.sleep(2000);
>         }
>
>         System.out.println("The journey is still in progress. Check it in the Investigation portal.");
>     }
> }
> ```

The program makes five calls, in order:

| Step | TypeScript | Java | What it does |
| - | - | - | - |
| 1 | `tokens.generate` | `tokens().generate()` | Exchanges your client credentials for an access token. The token endpoint is global, so this call uses a client with no region set. |
| 2 | `journeys.start` | `journeys().start()` | Starts a journey instance with API delivery and an empty subject, so the end user provides all the data. |
| 3 | `interactions.fetch` | `interactions().fetch()` | Returns the first interaction. The program fetches again until an interaction ID appears, because the journey might still be processing. |
| 4 | `interactions.submit` | `interactions().submit()` | Sends the name and date of birth that the Age Verification module checks. |
| 5 | `journeys.getState` | `journeys().getState()` | Returns the journey state. The program polls until the status is no longer `InProgress`. |

> [!WARNING]
>
> Pass the access token as `interactionAccess` on every interaction call. These methods don't use the client's `customerAccess` token. Without it, the SDK sends the request without an `Authorization` header and GBG Go rejects it.

The fetch and state responses each arrive as one of three variants. Each is a full view, a slim view, or an unknown body, and the program checks which variant arrived before it reads any fields.

If your tenant is in the Americas or Australasia, then replace `eu` in `SERVER_URL` with `us` or `au`.

## Step 5: Run the program

> [tab] TypeScript
>
> Run the program from the project folder:
>
> ```bash theme={null}
> npx tsx quickstart.ts
> ```
>
> When the journey finishes, your output looks similar to this:
>
> ```text theme={null}
> Started journey instance Pq_hhIX6-sHUy9FLSDzPLu
> Outstanding domain elements: [ 'FullName/firstName', 'FullName/lastNames', 'DateOfBirth' ]
> Submit status: success
> Journey finished with status Completed
> {
>   "status": "complete",
>   "advice": {}
> }
> ```

> [tab] Java
>
> Compile and run the program from the `go-sdk-quickstart` folder:
>
> ```bash theme={null}
> mvn -q compile exec:java -Dexec.mainClass=Quickstart
> ```
>
> When the journey finishes, your output looks similar to this:
>
> ```text theme={null}
> Started journey instance Pq_hhIX6-sHUy9FLSDzPLu
> Outstanding domain elements: [FullName/firstName, FullName/lastNames, DateOfBirth]
> Submit status: success
> Journey finished with status Completed
> {status=complete, advice={}}
> ```
>
> The program also prints three `SLF4J` warnings at startup, because the project has no logging implementation. They don't affect the program.

If the journey needs more data than a name and a date of birth, then the program ends with this line instead:

```text theme={null}
The journey is still in progress. Check it in the Investigation portal.
```

The journey instance appears in the [Investigation](https://docs.go.gbgplc.com/docs/go-v2/platform/investigate/overview.md) portal, where you can see the module result and the data you submitted.

## Troubleshooting

> [accordion] The token request returns HTTP 400 or 401
>
> The client ID or client secret is wrong, or someone deleted the API client. Check the values in the **Clients** tab of the Account management portal, and set the environment variables again.

> [accordion] The start request returns HTTP 404
>
> GBG Go can't find the journey. Check that `JOURNEY_RESOURCE_ID` includes the version, that you've published the journey, and that `SERVER_URL` names the region your tenant is in.

> [accordion] Fetch or submit returns HTTP 401, but start succeeds
>
> The call is missing its security setting. In TypeScript, pass `{ interactionAccess: accessToken }` as the first argument to `interactions.fetch` and `interactions.submit`. In Java, call `.security()` with `interactionAccess(accessToken)` on `interactions().fetch()` and `interactions().submit()`.

> [accordion] The program reports that the journey is still in progress
>
> The journey is waiting for data the program doesn't send, such as an address or a photo of a document. Open the journey instance in the [Investigation](https://docs.go.gbgplc.com/docs/go-v2/platform/investigate/overview.md) portal to see which step it's waiting at.
>
> Remove the extra modules from the journey and publish it again, or extend the submit call to send the data they need.

> [accordion] The program reports that no interaction became available
>
> The journey didn't present an interaction within 20 seconds. Open the journey instance in the [Investigation](https://docs.go.gbgplc.com/docs/go-v2/platform/investigate/overview.md) portal to see which step it stopped at.

> [accordion] TypeScript: ConnectionError: fetch failed, or UNABLE\_TO\_GET\_ISSUER\_CERT\_LOCALLY
>
> Node.js uses its own list of trusted certificate authorities, not your operating system's. Behind a TLS-inspecting proxy, every request fails even though curl works.
>
> On Node.js 22.15 or later, run `export NODE_OPTIONS=--use-system-ca` before you run the program. On older versions, set `NODE_EXTRA_CA_CERTS` to the path of your proxy's root certificate.

## Next steps

* [Core SDK](https://docs.go.gbgplc.com/docs/go-v2/developer-integration/sdks/core-sdk.md): every resource and method the SDK exposes, with regions, retries, and error handling.
* [TypeScript notes](https://docs.go.gbgplc.com/docs/go-v2/developer-integration/sdks/core/typescript.md) and [Java notes](https://docs.go.gbgplc.com/docs/go-v2/developer-integration/sdks/core/java.md): install details, runtime support, and language-specific features.
* [Sample applications](https://docs.go.gbgplc.com/docs/go-v2/tutorials/sample-apps-overview.md): working onboarding apps with a front end, on an API or SDK backend.
* [API usage guides](https://docs.go.gbgplc.com/docs/go-v2/developer-integration/execute-customer-journeys/overview.md): detailed step-by-step reference for each call.
