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

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




## OpenAPI

````yaml https://raw.githubusercontent.com/openfga/api/refs/heads/main/docs/openapiv3/apidocs.openapi.json get /stores/{store_id}/changes
openapi: 3.0.3
info:
  contact:
    email: community@openfga.dev
    name: OpenFGA
    url: https://openfga.dev
  description: >-
    A high performance and flexible authorization/permission engine built for
    developers and inspired by Google Zanzibar.
  license:
    name: Apache-2.0
    url: https://github.com/openfga/openfga/blob/main/LICENSE
  title: OpenFGA
  version: 1.x
servers: []
security: []
tags:
  - name: AuthZenService
  - name: OpenFGAService
paths:
  /stores/{store_id}/changes:
    get:
      tags:
        - Relationship Tuples
      summary: Get all tuple changes
      description: >
        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.
      operationId: ReadChanges
      parameters:
        - in: path
          name: store_id
          required: true
          schema:
            type: string
        - in: query
          name: type
          required: false
          schema:
            type: string
        - in: query
          name: page_size
          required: false
          schema:
            format: int32
            type: integer
        - in: query
          name: continuation_token
          required: false
          schema:
            type: string
        - description: >-
            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`.
          in: query
          name: start_time
          required: false
          schema:
            format: date-time
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReadChangesResponse'
          description: A successful response.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorMessageResponse'
          description: Request failed due to invalid input.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthenticatedResponse'
          description: Not authenticated.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
          description: Forbidden.
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PathUnknownErrorMessageResponse'
          description: Request failed due to incorrect path.
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AbortedMessageResponse'
          description: Request was aborted due a transaction conflict.
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableContentMessageResponse'
          description: Request timed out due to excessive request throttling.
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InternalErrorMessageResponse'
          description: Request failed due to internal server error.
      x-codeSamples:
        - lang: node
          label: Node.js
          source: >-
            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;
            });
        - lang: go
          label: Go
          source: |-
            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
            }
        - lang: dotnet
          label: .NET
          source: |-
            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);
        - lang: python
          label: Python
          source: |-
            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())
        - lang: java
          label: Java
          source: |-
            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();
                }
            }
        - lang: bash
          label: curl
          source: >-
            # 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"
components:
  schemas:
    ReadChangesResponse:
      properties:
        changes:
          items:
            allOf:
              - $ref: '#/components/schemas/TupleChange'
              - type: object
          type: array
        continuation_token:
          description: The continuation token is identical if there are no new changes.
          example: >-
            eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==
          type: string
      required:
        - changes
      type: object
    ValidationErrorMessageResponse:
      example:
        code: validation_error
        message: Generic validation error
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
      type: object
    UnauthenticatedResponse:
      example:
        code: unauthenticated
        message: unauthenticated
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
      type: object
    ForbiddenResponse:
      example:
        code: forbidden
        message: the principal is not authorized to perform the action
      properties:
        code:
          $ref: '#/components/schemas/AuthErrorCode'
        message:
          type: string
      type: object
    PathUnknownErrorMessageResponse:
      example:
        code: undefined_endpoint
        message: Endpoint not enabled
      properties:
        code:
          $ref: '#/components/schemas/NotFoundErrorCode'
        message:
          type: string
      type: object
    AbortedMessageResponse:
      example:
        code: '10'
        message: transaction conflict
      properties:
        code:
          type: string
        message:
          type: string
      type: object
    UnprocessableContentMessageResponse:
      example:
        code: throttled_timeout_error
        message: timeout due to throttling on complex request
      properties:
        code:
          $ref: '#/components/schemas/UnprocessableContentErrorCode'
        message:
          type: string
      type: object
    InternalErrorMessageResponse:
      example:
        code: internal_error
        message: Internal Server Error
      properties:
        code:
          $ref: '#/components/schemas/InternalErrorCode'
        message:
          type: string
      type: object
    TupleChange:
      properties:
        operation:
          $ref: '#/components/schemas/TupleOperation'
        timestamp:
          format: date-time
          type: string
        tuple_key:
          $ref: '#/components/schemas/TupleKey'
      required:
        - tuple_key
        - operation
        - timestamp
      type: object
    ErrorCode:
      default: no_error
      enum:
        - no_error
        - validation_error
        - authorization_model_not_found
        - authorization_model_resolution_too_complex
        - invalid_write_input
        - cannot_allow_duplicate_tuples_in_one_request
        - cannot_allow_duplicate_types_in_one_request
        - cannot_allow_multiple_references_to_one_relation
        - invalid_continuation_token
        - invalid_tuple_set
        - invalid_check_input
        - invalid_expand_input
        - unsupported_user_set
        - invalid_object_format
        - write_failed_due_to_invalid_input
        - authorization_model_assertions_not_found
        - latest_authorization_model_not_found
        - type_not_found
        - relation_not_found
        - empty_relation_definition
        - invalid_user
        - invalid_tuple
        - unknown_relation
        - store_id_invalid_length
        - assertions_too_many_items
        - id_too_long
        - authorization_model_id_too_long
        - tuple_key_value_not_specified
        - tuple_keys_too_many_or_too_few_items
        - page_size_invalid
        - param_missing_value
        - difference_base_missing_value
        - subtract_base_missing_value
        - object_too_long
        - relation_too_long
        - type_definitions_too_few_items
        - type_invalid_length
        - type_invalid_pattern
        - relations_too_few_items
        - relations_too_long
        - relations_invalid_pattern
        - object_invalid_pattern
        - query_string_type_continuation_token_mismatch
        - exceeded_entity_limit
        - invalid_contextual_tuple
        - duplicate_contextual_tuple
        - invalid_authorization_model
        - unsupported_schema_version
        - cancelled
        - invalid_start_time
      type: string
    AuthErrorCode:
      default: no_auth_error
      enum:
        - no_auth_error
        - auth_failed_invalid_subject
        - auth_failed_invalid_audience
        - auth_failed_invalid_issuer
        - invalid_claims
        - auth_failed_invalid_bearer_token
        - bearer_token_missing
        - unauthenticated
        - forbidden
      type: string
    NotFoundErrorCode:
      default: no_not_found_error
      enum:
        - no_not_found_error
        - undefined_endpoint
        - store_id_not_found
        - unimplemented
      type: string
    UnprocessableContentErrorCode:
      default: no_throttled_error_code
      enum:
        - no_throttled_error_code
        - throttled_timeout_error
      type: string
    InternalErrorCode:
      default: no_internal_error
      enum:
        - no_internal_error
        - internal_error
        - deadline_exceeded
        - already_exists
        - resource_exhausted
        - failed_precondition
        - aborted
        - out_of_range
        - unavailable
        - data_loss
      type: string
    TupleOperation:
      default: TUPLE_OPERATION_WRITE
      enum:
        - TUPLE_OPERATION_WRITE
        - TUPLE_OPERATION_DELETE
      title: buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
      type: string
    TupleKey:
      properties:
        condition:
          $ref: '#/components/schemas/RelationshipCondition'
        object:
          example: document:2021-budget
          maxLength: 256
          type: string
        relation:
          example: reader
          maxLength: 50
          type: string
        user:
          example: user:anne
          maxLength: 512
          type: string
      required:
        - user
        - relation
        - object
      type: object
    RelationshipCondition:
      properties:
        context:
          description: >-
            Additional context/data to persist along with the condition.

            The keys must match the parameters defined by the condition, and the
            value types must

            match the parameter type definitions.
          type: object
        name:
          description: >-
            A reference (by name) of the relationship condition defined in the
            authorization model.
          example: condition1
          maxLength: 256
          type: string
      required:
        - name
      type: object

````