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

# How to get tuple changes

> Getting tuple changes

This section illustrates how to call the Read Changes API to get the list of relationship tuple changes that happened in your store, in the exact order that they happened. The API response includes tuples that have been added or removed in your store. It does not include other changes, like updates to your authorization model and adding new assertions.

## Before you start

> [tab] Node.js
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the SDK](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [updated the *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] Go
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the SDK](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [added some *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] .NET
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the SDK](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [updated the *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] Python
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the SDK](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [updated the *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] CLI
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the CLI](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [updated the *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] Java
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [installed the SDK](https://docs.fga.dev/integration/install-sdk.md).
> 3. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md).
> 4. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

> [tab] curl
>
> 1. You have [obtained FGA API credentials](https://docs.fga.dev/integration/getting-your-api-keys.md) and set `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID`, and `FGA_CLIENT_SECRET`.
> 2. You have [configured the *authorization model*](https://docs.fga.dev/modeling.md) and [updated the *relationship tuples*](https://docs.fga.dev/integration/update-tuples.md).
> 3. You have loaded `FGA_API_URL`, `FGA_STORE_ID`, `FGA_API_TOKEN_ISSUER`, `FGA_API_AUDIENCE`, `FGA_CLIENT_ID` and `FGA_CLIENT_SECRET` as environment variables.

## Step by step

To get a chronologically ordered list of tuples that have been written or deleted in your store, you can do so by calling the Read Changes API.

### 01. Configure The Auth0 FGA API Client

First you will need to configure the API client.

> [tab] Node.js
>
> ```javascript theme={null}
> const { CredentialsMethod, OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');
>
> const fgaClient = new OpenFgaClient({
>   apiUrl: process.env.FGA_API_URL, // https://api.us1.fga.dev, or your store's eu1/au1 region
>   storeId: process.env.FGA_STORE_ID,
>   authorizationModelId: process.env.FGA_MODEL_ID,
>   credentials: {
>     method: CredentialsMethod.ClientCredentials,
>     config: {
>       apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER, // auth.fga.dev
>       apiAudience: process.env.FGA_API_AUDIENCE, // URL for your store's region
>       clientId: process.env.FGA_CLIENT_ID,
>       clientSecret: process.env.FGA_CLIENT_SECRET,
>     },
>   },
> });
> ```

> [tab] Go
>
> ```go theme={null}
> package main
>
> import (
>     "os"
>     . "github.com/openfga/go-sdk/client"
>     "github.com/openfga/go-sdk/credentials"
> )
>
> // Configure FGA_API_URL and FGA_API_AUDIENCE for your store's us1/eu1/au1 region.
> // Set FGA_STORE_ID, FGA_MODEL_ID, FGA_API_TOKEN_ISSUER, FGA_CLIENT_ID, and FGA_CLIENT_SECRET.
> func main() {
>     fgaClient, err := NewSdkClient(&ClientConfiguration{
>         ApiUrl: os.Getenv("FGA_API_URL"),
>         StoreId: os.Getenv("FGA_STORE_ID"),
>         AuthorizationModelId: os.Getenv("FGA_MODEL_ID"),
>         Credentials: &credentials.Credentials{
>             Method: credentials.CredentialsMethodClientCredentials,
>             Config: &credentials.Config{
>                 ClientCredentialsApiTokenIssuer: os.Getenv("FGA_API_TOKEN_ISSUER"),
>                 ClientCredentialsApiAudience: os.Getenv("FGA_API_AUDIENCE"),
>                 ClientCredentialsClientId: os.Getenv("FGA_CLIENT_ID"),
>                 ClientCredentialsClientSecret: os.Getenv("FGA_CLIENT_SECRET"),
>             },
>         },
>     })
>     if err != nil { panic(err) }
>     _ = fgaClient // Use the client for the next request.
> }
> ```

> [tab] .NET
>
> ```csharp theme={null}
> using System.Collections.Generic;
> using OpenFga.Sdk.Client;
> using OpenFga.Sdk.Client.Model;
> using OpenFga.Sdk.Configuration;
> using OpenFga.Sdk.Model;
> using Environment = System.Environment;
>
> // FGA_API_URL and FGA_API_AUDIENCE must match the store's us1/eu1/au1 region.
> var fgaClient = new OpenFgaClient(new ClientConfiguration() {
>   ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
>   StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
>   AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"),
>   Credentials = new Credentials() {
>     Method = CredentialsMethod.ClientCredentials,
>     Config = new CredentialsConfig() {
>       ApiTokenIssuer = Environment.GetEnvironmentVariable("FGA_API_TOKEN_ISSUER"),
>       ApiAudience = Environment.GetEnvironmentVariable("FGA_API_AUDIENCE"),
>       ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"),
>       ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET"),
>     }
>   }
> });
> ```

> [tab] Java
>
> ```java theme={null}
> import dev.openfga.sdk.api.client.OpenFgaClient;
> import dev.openfga.sdk.api.configuration.ClientConfiguration;
> import dev.openfga.sdk.api.configuration.ClientCredentials;
> import dev.openfga.sdk.api.configuration.Credentials;
> import dev.openfga.sdk.api.configuration.ClientCheckOptions;
> import dev.openfga.sdk.api.configuration.ClientBatchCheckOptions;
> import dev.openfga.sdk.api.configuration.ClientWriteOptions;
> import dev.openfga.sdk.api.configuration.ClientListObjectsOptions;
> import dev.openfga.sdk.api.configuration.ClientListUsersOptions;
> import dev.openfga.sdk.api.configuration.ClientReadChangesOptions;
> import dev.openfga.sdk.api.client.model.*;
> import dev.openfga.sdk.api.model.*;
> import java.util.List;
> import java.util.Map;
>
> // FGA_API_URL and FGA_API_AUDIENCE must match the store's us1/eu1/au1 region.
> public class SdkSetupExample {
>     public static void main(String[] args) throws Exception {
>         var config = new ClientConfiguration()
>             .apiUrl(System.getenv("FGA_API_URL"))
>             .storeId(System.getenv("FGA_STORE_ID"))
>             .authorizationModelId(System.getenv("FGA_MODEL_ID"))
>             .credentials(new Credentials(new ClientCredentials()
>                 .apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER"))
>                 .apiAudience(System.getenv("FGA_API_AUDIENCE"))
>                 .clientId(System.getenv("FGA_CLIENT_ID"))
>                 .clientSecret(System.getenv("FGA_CLIENT_SECRET"))));
>         var fgaClient = new OpenFgaClient(config);
>     }
> }
> ```

> [tab] curl
>
> To obtain the [access token](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow):
>
> ```bash theme={null}
> # Requires jq to safely encode credentials as JSON.
> curl -sS -X POST 'https://auth.fga.dev/oauth/token' \
>   -H 'content-type: application/json' \
>   --data "$(jq -n \
>     --arg client_id "$FGA_CLIENT_ID" \
>     --arg client_secret "$FGA_CLIENT_SECRET" \
>     --arg audience "$FGA_API_AUDIENCE" \
>     '{client_id: $client_id, client_secret: $client_secret, audience: $audience, grant_type: "client_credentials"}')"
> # Use the access_token in the response as FGA_BEARER_TOKEN for direct API calls.
> ```

### 02. Get changes for all object types

To get a paginated list of changes that happened in your store:

The result will contain an array of up to 25 tuples, with the operation (`write` or `delete`), and the timestamp in which that operation took place. The result will also contain a continuation token. Save the continuation token in persistent storage between calls so that it is not lost and you do not have to restart from scratch on system restart or on error.

You can then use this token to get the next set of changes:

Once there are no more changes to retrieve, the API will return the same token as the one you sent. Save the token in persistent storage to use at a later time.

> [!NOTE]
>
> * The default page size is 50. The maximum page size allowed is 100.
> * The API response does not expand the tuples. If you wrote a tuple that includes a userset, like `{"user": "group:abc#member", "relation": "owner": "doc:budget"}`, the Read Changes API will return that exact tuple.

### 03. Get changes for a specific object type

Imagine you have the following authorization model:

It is possible to get a list of changes that happened in your store that relate only to one specific object type, like `folder`, by issuing a call like this:

The response will include a continuation token. In subsequent calls, you have to include the token and the `type`. (If you send this continuation token without the `type` parameter set, you will get an error).
