Get all tuple changes
The ReadChanges API returns a paginated list of tuple changes (additions and deletions) that occurred in a given store, sorted by ascending time. The response includes a continuation token that is used to get the next set of changes. If there are no changes after the provided continuation token, the same token is returned in order for it to be used when new changes are recorded.
If the store never had any tuples added or removed, then this token returns empty.
You can use the type parameter to only get the list of tuple changes that affect objects of that type.
When reading a write tuple change, if it was conditioned, the condition is returned.
When reading a delete tuple change, the condition is NOT returned regardless of whether it was originally conditioned or not.
const { OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
});
async function main() {
const body = {
"type": "document"
};
const options = {
"pageSize": 20
};
const response = await fgaClient.readChanges(body, options);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"os"
. "github.com/openfga/go-sdk/client"
)
func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"),
StoreId: os.Getenv("FGA_STORE_ID"),
})
if err != nil {
panic(err)
}
pageSize := int32(20)
body := ClientReadChangesRequest{
Type: "document",
}
options := ClientReadChangesOptions{
PageSize: &pageSize,
}
response, err := fgaClient.ReadChanges(context.Background()).Body(body).Options(options).Execute()
if err != nil {
panic(err)
}
_ = response
}using System.Collections.Generic;
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
var fgaClient = new OpenFgaClient(new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
});
var body = new ClientReadChangesRequest {
Type = "document",
};
var options = new ClientReadChangesOptions {
PageSize = 20,
};
var response = await fgaClient.ReadChanges(body, options);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientReadChangesRequest
async def main():
configuration = ClientConfiguration(
api_url=os.environ.get("FGA_API_URL"),
store_id=os.environ.get("FGA_STORE_ID"),
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientReadChangesRequest(
type="document",
)
options = {"page_size": 20}
response = await fga_client.read_changes(body=body, options=options)
asyncio.run(main())import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.*;
import dev.openfga.sdk.api.client.model.*;
import dev.openfga.sdk.api.model.*;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import dev.openfga.sdk.api.configuration.ClientReadChangesOptions;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL"))
.storeId(System.getenv("FGA_STORE_ID"));
var fgaClient = new OpenFgaClient(config);
var body = new ClientReadChangesRequest()
.type("document");
var options = new ClientReadChangesOptions()
.pageSize(20);
var response = fgaClient.readChanges(body, options).get();
}
}# Set FGA_API_URL to the URL of your OpenFGA server.
# Set FGA_STORE_ID to your store ID.
# These examples use a server with authentication disabled.
# For authenticated servers, see /docs/getting-started/setup-sdk-client.
curl -X GET "$FGA_API_URL/stores/$FGA_STORE_ID/changes?page_size=20&type=document"{
"changes": [
{
"operation": "TUPLE_OPERATION_WRITE",
"timestamp": "2023-11-07T05:31:56Z",
"tuple_key": {
"object": "document:2021-budget",
"relation": "reader",
"user": "user:anne",
"condition": {
"name": "condition1",
"context": {}
}
}
}
],
"continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthenticated",
"message": "unauthenticated"
}{
"code": "forbidden",
"message": "the principal is not authorized to perform the action"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "internal_error",
"message": "Internal Server Error"
}Path Parameters
Query Parameters
Start date and time of changes to read.
Format: ISO 8601 timestamp (e.g., 2022-01-01T00:00:00Z)
If a continuation_token is provided along side start_time, the continuation_token takes precedence over start_time.
Was this page helpful?
const { OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
});
async function main() {
const body = {
"type": "document"
};
const options = {
"pageSize": 20
};
const response = await fgaClient.readChanges(body, options);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"os"
. "github.com/openfga/go-sdk/client"
)
func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"),
StoreId: os.Getenv("FGA_STORE_ID"),
})
if err != nil {
panic(err)
}
pageSize := int32(20)
body := ClientReadChangesRequest{
Type: "document",
}
options := ClientReadChangesOptions{
PageSize: &pageSize,
}
response, err := fgaClient.ReadChanges(context.Background()).Body(body).Options(options).Execute()
if err != nil {
panic(err)
}
_ = response
}using System.Collections.Generic;
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
var fgaClient = new OpenFgaClient(new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
});
var body = new ClientReadChangesRequest {
Type = "document",
};
var options = new ClientReadChangesOptions {
PageSize = 20,
};
var response = await fgaClient.ReadChanges(body, options);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientReadChangesRequest
async def main():
configuration = ClientConfiguration(
api_url=os.environ.get("FGA_API_URL"),
store_id=os.environ.get("FGA_STORE_ID"),
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientReadChangesRequest(
type="document",
)
options = {"page_size": 20}
response = await fga_client.read_changes(body=body, options=options)
asyncio.run(main())import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.*;
import dev.openfga.sdk.api.client.model.*;
import dev.openfga.sdk.api.model.*;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import dev.openfga.sdk.api.configuration.ClientReadChangesOptions;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL"))
.storeId(System.getenv("FGA_STORE_ID"));
var fgaClient = new OpenFgaClient(config);
var body = new ClientReadChangesRequest()
.type("document");
var options = new ClientReadChangesOptions()
.pageSize(20);
var response = fgaClient.readChanges(body, options).get();
}
}# Set FGA_API_URL to the URL of your OpenFGA server.
# Set FGA_STORE_ID to your store ID.
# These examples use a server with authentication disabled.
# For authenticated servers, see /docs/getting-started/setup-sdk-client.
curl -X GET "$FGA_API_URL/stores/$FGA_STORE_ID/changes?page_size=20&type=document"{
"changes": [
{
"operation": "TUPLE_OPERATION_WRITE",
"timestamp": "2023-11-07T05:31:56Z",
"tuple_key": {
"object": "document:2021-budget",
"relation": "reader",
"user": "user:anne",
"condition": {
"name": "condition1",
"context": {}
}
}
}
],
"continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthenticated",
"message": "unauthenticated"
}{
"code": "forbidden",
"message": "the principal is not authorized to perform the action"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "internal_error",
"message": "Internal Server Error"
}