# Python SDK for OpenFGA

[![pypi](https://img.shields.io/pypi/v/openfga_sdk.svg?style=flat)](https://pypi.org/project/openfga_sdk)
[![Socket Badge](https://badge.socket.dev/pypi/package/openfga-sdk/0.9.8](https://socket.dev/pypi/package/openfga-sdk)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-openfga%2Fpython--sdk-blue.svg?logo=data:image/png;base64, )](https://deepwiki.com/openfga/python-sdk)
[![Release](https://img.shields.io/github/v/release/openfga/python-sdk?sort=semver&color=green)](https://github.com/openfga/python-sdk/releases)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fopenfga%2Fpython-sdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fopenfga%2Fpython-sdk?ref=badge_shield)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/openfga/python-sdk/badge)](https://securityscorecards.dev/viewer/?uri=github.com/openfga/python-sdk)
[![Join our community](https://img.shields.io/badge/slack-cncf_%23openfga-40abb8.svg?logo=slack)](https://openfga.dev/community)
[![X](https://img.shields.io/twitter/follow/openfga?color=%23179CF0&logo=x&style=flat-square "@openfga on X")](https://x.com/openfga)

This is an autogenerated python SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api).

## Table of Contents

- [About OpenFGA](#about)
- [Resources](#resources)
- [Installation](#installation)
- [Getting Started](#getting-started)
  - [Initializing the API Client](#initializing-the-api-client)
  - [Custom Headers](#custom-headers)
  - [Get your Store ID](#get-your-store-id)
  - [Calling the API](#calling-the-api)
    - [Stores](#stores)
      - [List All Stores](#list-stores)
      - [Create a Store](#create-store)
      - [Get a Store](#get-store)
      - [Delete a Store](#delete-store)
    - [Authorization Models](#authorization-models)
      - [Read Authorization Models](#read-authorization-models)
      - [Write Authorization Model](#write-authorization-model)
      - [Read a Single Authorization Model](#read-a-single-authorization-model)
      - [Read the Latest Authorization Model](#read-the-latest-authorization-model)
    - [Relationship Tuples](#relationship-tuples)
      - [Read Relationship Tuple Changes (Watch)](#read-relationship-tuple-changes-watch)
      - [Read Relationship Tuples](#read-relationship-tuples)
      - [Write (Create and Delete) Relationship Tuples](#write-create-and-delete-relationship-tuples)
    - [Relationship Queries](#relationship-queries)
      - [Check](#check)
      - [Batch Check](#batch-check)
      - [Expand](#expand)
      - [List Objects](#list-objects)
      - [Streamed List Objects](#streamed-list-objects)
      - [List Relations](#list-relations)
      - [List Users](#list-users)
    - [Assertions](#assertions)
      - [Read Assertions](#read-assertions)
      - [Write Assertions](#write-assertions)
  - [Retries](#retries)
  - [API Endpoints](#api-endpoints)
  - [Models](#models)
  - [OpenTelemetry](#opentelemetry)
- [Contributing](#contributing)
  - [Issues](#issues)
  - [Pull Requests](#pull-requests)
- [License](#license)

## About

[OpenFGA](https://openfga.dev) is an open source Fine-Grained Authorization solution inspired by [Google's Zanzibar paper](https://research.google/pubs/pub48190/). It was created by the FGA team at [Auth0](https://auth0.com) based on [Auth0 Fine-Grained Authorization (FGA)](https://fga.dev), available under [a permissive license (Apache-2)](https://github.com/openfga/rfcs/blob/main/LICENSE) and welcomes community contributions.

OpenFGA is designed to make it easy for application builders to model their permission layer, and to add and integrate fine-grained authorization into their applications. OpenFGA’s design is optimized for reliability and low latency at a high scale.


## Resources

- [OpenFGA Documentation](https://openfga.dev/docs)
- [OpenFGA API Documentation](https://openfga.dev/api/service)
- [X](https://x.com/openfga)
- [OpenFGA Community](https://openfga.dev/community)
- [Zanzibar Academy](https://zanzibar.academy)
- [Google's Zanzibar Paper (2019)](https://research.google/pubs/pub48190/)

## Installation

### pip install

#### PyPI

The openfga_sdk is available to be downloaded via PyPI, you can install directly using:

```sh
pip3 install openfga_sdk
```
(you may need to run `pip` with root permission: `sudo pip3 install openfga_sdk`)

Then import the package:
```python
import openfga_sdk
```

#### GitHub

The openfga_sdk is also hosted in GitHub, you can install directly using:

```sh
pip3 install https://github.com/openfga/python-sdk.git
```
(you may need to run `pip` with root permission: `sudo pip3 install https://github.com/openfga/python-sdk.git`)

Then import the package:
```python
import openfga_sdk
```

### Setuptools

Install via [Setuptools](https://pypi.python.org/pypi/setuptools).

```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)

Then import the package:
```python
import openfga_sdk
```


## Getting Started

### Initializing the API Client

[Learn how to initialize your SDK](https://openfga.dev/docs/getting-started/setup-sdk-client)

We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be preformed on every request.

> The `OpenFgaClient` will by default retry API requests up to 3 times on 429 and 5xx errors.

#### No Credentials

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient


async def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,  # required
        store_id=FGA_STORE_ID,  # optional, not needed when calling `CreateStore` or `ListStores`
        authorization_model_id=FGA_MODEL_ID,  # Optional, can be overridden per request
    )
    # Enter a context with an instance of the OpenFgaClient
    async with OpenFgaClient(configuration) as fga_client:
        api_response = await fga_client.read_authorization_models()
        await fga_client.close()
        return api_response
```

#### API Token

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient
from openfga_sdk.credentials import CredentialConfiguration, Credentials


async def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,  # required
        store_id=FGA_STORE_ID,  # optional, not needed when calling `CreateStore` or `ListStores`
        authorization_model_id=FGA_MODEL_ID,  # Optional, can be overridden per request
        credentials=Credentials(
            method='api_token',
            configuration=CredentialConfiguration(
                api_token=FGA_API_TOKEN,
            )
        )
    )
    # Enter a context with an instance of the OpenFgaClient
    async with OpenFgaClient(configuration) as fga_client:
        api_response = await fga_client.read_authorization_models()
        await fga_client.close()
        return api_response
```

#### Client Credentials

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient
from openfga_sdk.credentials import Credentials, CredentialConfiguration


async def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,  # required
        store_id=FGA_STORE_ID,  # optional, not needed when calling `CreateStore` or `ListStores`
        authorization_model_id=FGA_MODEL_ID,  # Optional, can be overridden per request
        credentials=Credentials(
            method='client_credentials',
            configuration=CredentialConfiguration(
                api_issuer=FGA_API_TOKEN_ISSUER,
                api_audience=FGA_API_AUDIENCE,
                client_id=FGA_CLIENT_ID,
                client_secret=FGA_CLIENT_SECRET,
            )
        )
    )
    # Enter a context with an instance of the OpenFgaClient
    async with OpenFgaClient(configuration) as fga_client:
        api_response = await fga_client.read_authorization_models()
        await fga_client.close()
        return api_response
```

### Custom Headers

#### Default Headers

You can configure default headers that will be sent with every request by passing them to the `ClientConfiguration`:

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient


async def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,
        store_id=FGA_STORE_ID,
        authorization_model_id=FGA_MODEL_ID,
        headers={
            "X-Custom-Header": "default-value",
            "X-Request-Source": "my-app",
        },
    )

    async with OpenFgaClient(configuration) as fga_client:
        api_response = await fga_client.read_authorization_models()
        return api_response
```

#### Per-Request Headers

You can also send custom headers on a per-request basis by using the `options` parameter. Per-request headers will override any default headers with the same name.

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient
from openfga_sdk.client.models import ClientCheckRequest


async def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,
        store_id=FGA_STORE_ID,
        authorization_model_id=FGA_MODEL_ID,
    )

    async with OpenFgaClient(configuration) as fga_client:
        # Add custom headers to a specific request
        result = await fga_client.check(
            body=ClientCheckRequest(
                user="user:anne",
                relation="viewer",
                object="document:roadmap",
            ),
            options={
                "headers": {
                    "X-Request-ID": "123e4567-e89b-12d3-a456-426614174000",
                    "X-Custom-Header": "custom-value",  # Overrides default header value
                }
            }
        )
        return result
```

#### Synchronous Client

To run outside of an async context, the project exports a synchronous client
from `openfga_sdk.sync` that supports all the credential types and calls,
without requiring async/await.

```python
from openfga_sdk.client import ClientConfiguration
from openfga_sdk.sync import OpenFgaClient


def main():
    configuration = ClientConfiguration(
        api_url=FGA_API_URL,  # required
        store_id=FGA_STORE_ID,  # optional, not needed when calling `CreateStore` or `ListStores`
        authorization_model_id=FGA_MODEL_ID,  # optional, can be overridden per request
    )
    # Enter a context with an instance of the OpenFgaClient
    with OpenFgaClient(configuration) as fga_client:
        api_response = fga_client.read_authorization_models()
        return api_response
```


### Get your Store ID

You need your store id to call the OpenFGA API (unless it is to call the [CreateStore](#create-store) or [ListStores](#list-stores) methods).

If your server is configured with [authentication enabled](https://openfga.dev/docs/getting-started/setup-openfga#configuring-authentication), you also need to have your credentials ready.

### Calling the API

#### Stores

##### List Stores

Get a paginated list of stores.

[API Documentation](https://openfga.dev/api/service#/Stores/ListStores)

```python
# from openfga_sdk.sync import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {"page_size": 25, "continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="}
response = await fga_client.list_stores(options)
# response = ListStoresResponse(...)
# response.stores = [Store({"id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z"})]
```


##### Create Store

Create and initialize a store.

[API Documentation](https://openfga.dev/api/service#/Stores/CreateStore)

```python
# from openfga_sdk import CreateStoreRequest, OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

body = CreateStoreRequest(
    name = "FGA Demo Store",
)
response = await fga_client.create_store(body)
# response.id = "01FQH7V8BEG3GPQW93KTRFR8JB"
```


##### Get Store

Get information about the current store.

[API Documentation](https://openfga.dev/api/service#/Stores/GetStore)

> Requires a client initialized with a storeId

```python
# from openfga_sdk import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

response = await fga_client.get_store()
# response = Store({"id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z"})
```


##### Delete Store

Delete a store.

[API Documentation](https://openfga.dev/api/service#/Stores/DeleteStore)

> Requires a client initialized with a storeId

```python
# from openfga_sdk import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

response = await fga_client.delete_store()
```


#### Authorization Models

##### Read Authorization Models

Read all authorization models in the store.

[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModels)

```python
# from openfga_sdk import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {"page_size": 25, "continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="}
response = await fga_client.read_authorization_models(options)
# response.authorization_models = [AuthorizationModel(id='01GXSA8YR785C4FYS3C0RTG7B1', schema_version = '1.1', type_definitions=type_definitions[...], AuthorizationModel(id='01GXSBM5PVYHCJNRNKXMB4QZTW', schema_version = '1.1', type_definitions=type_definitions[...])]
```


##### Write Authorization Model

Create a new authorization model.

[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/WriteAuthorizationModel)

> Note: To learn how to build your authorization model, check the Docs at https://openfga.dev/docs.

> Learn more about [the OpenFGA configuration language](https://openfga.dev/docs/configuration-language).

> You can use the [OpenFGA Syntax Transformer](https://github.com/openfga/syntax-transformer) to convert between the friendly DSL and the JSON authorization model.

```python
# from openfga_sdk import (
#     Condition, ConditionParamTypeRef, Metadata, ObjectRelation, OpenFgaClient, RelationMetadata,
#     RelationReference, TypeDefinition, Userset, Usersets, WriteAuthorizationModelRequest
# )

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

user_type = TypeDefinition(type="user")

document_relations = dict(
    writer=Userset(this=dict()),
    viewer=Userset(
        union=Usersets(
            child=[
                Userset(this=dict()),
                Userset(computed_userset=ObjectRelation(
                    object="",
                    relation="writer",
                )),
            ],
        ),
    ),
)

document_metadata = Metadata(
        relations=dict(
            writer=RelationMetadata(
                directly_related_user_types=[
                    RelationReference(type="user"),
                    RelationReference(type="user", condition="ViewCountLessThan200"),
                ]
            ),
            viewer=RelationMetadata(
                directly_related_user_types=[
                    RelationReference(type="user"),
                ]
            )
        )
)

document_type = TypeDefinition(
    type="document",
    relations=document_relations,
    metadata=document_metadata
)

conditions = dict(
        ViewCountLessThan200=Condition(
            name="ViewCountLessThan200",
            expression="ViewCount < 200",
            parameters=dict(
                ViewCount=ConditionParamTypeRef(
                    type_name="TYPE_NAME_INT"
                ),
                Type=ConditionParamTypeRef(
                    type_name="TYPE_NAME_STRING"
                ),
                Name=ConditionParamTypeRef(
                    type_name="TYPE_NAME_STRING"
                ),
            )
        )
    )

body = WriteAuthorizationModelRequest(
    schema_version="1.1",
    type_definitions=[
        user_type,
        document_type
    ],
    conditions=conditions
)

response = await fga_client.write_authorization_model(body)
# response.authorization_model_id = "01GXSA8YR785C4FYS3C0RTG7B1"
```


##### Read a Single Authorization Model

Read a particular authorization model.

[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModel)

```python
# from openfga_sdk import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}

response = await fga_client.read_authorization_model(options)
# response.authorization_model =  AuthorizationModel(id='01GXSA8YR785C4FYS3C0RTG7B1', schema_version = '1.1', type_definitions=type_definitions[...])
```

##### Read the Latest Authorization Model

Reads the latest authorization model (note: this ignores the model id in configuration).

[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModel)

```python
# from openfga_sdk import ClientConfiguration, OpenFgaClient

# Create the cofiguration object
# configuration = ClientConfiguration(
#     ...
#     authorization_model_id = FGA_MODEL_ID,
#     ...
# )

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

response = await fga_client.read_latest_authorization_model()
# response.authorization_model =  AuthorizationModel(id='01GXSA8YR785C4FYS3C0RTG7B1', schema_version = '1.1', type_definitions=type_definitions[...])
```


#### Relationship Tuples

##### Read Relationship Tuple Changes (Watch)

Reads the list of historical relationship tuple writes and deletes.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/ReadChanges)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientReadChangesRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "page_size": "25",
    "continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="
}
body = ClientReadChangesRequest(type="document", start_time="2022-01-01T00:00:00Z")

response = await fga_client.read_changes(body, options)
# response.continuation_token = ...
# response.changes = [TupleChange(tuple_key=TupleKey(object="...",relation="...",user="..."),operation=TupleOperation("TUPLE_OPERATION_WRITE"),timestamp=datetime.fromisoformat("..."))]
```

##### Read Relationship Tuples

Reads the relationship tuples stored in the database. It does not evaluate nor exclude invalid tuples according to the authorization model.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/Read)

```python
# from openfga_sdk import OpenFgaClient, ReadRequestTupleKey

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

# Find if a relationship tuple stating that a certain user is a viewer of certain document
body = ReadRequestTupleKey(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)

response = await fga_client.read(body)
# response = ReadResponse({"tuples": [Tuple({"key": TupleKey({"user":"...","relation":"...","object":"..."}), "timestamp": datetime.fromisoformat("...") })]})
```

```python
# from openfga_sdk import OpenFgaClient, ReadRequestTupleKey

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

# Find all relationship tuples where a certain user has a relationship as any relation to a certain document
body = ReadRequestTupleKey(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)

response = await fga_client.read(body)
# response = ReadResponse({"tuples": [Tuple({"key": TupleKey({"user":"...","relation":"...","object":"..."}), "timestamp": datetime.fromisoformat("...") })]})

```

```python
# from openfga_sdk import OpenFgaClient, ReadRequestTupleKey

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

# Find all relationship tuples where a certain user is a viewer of any document
body = ReadRequestTupleKey(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    object="document:",
)

response = await fga_client.read(body)
# response = ReadResponse({"tuples": [Tuple({"key": TupleKey({"user":"...","relation":"...","object":"..."}), "timestamp": datetime.fromisoformat("...") })]})
```

```python
# from openfga_sdk import OpenFgaClient, ReadRequestTupleKey

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

# Find all relationship tuples where any user has a relationship as any relation with a particular document
body = ReadRequestTupleKey(
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)

response = await fga_client.read(body)
# response = ReadResponse({"tuples": [Tuple({"key": TupleKey({"user":"...","relation":"...","object":"..."}), "timestamp": datetime.fromisoformat("...") })]})
```

```python
# from openfga_sdk import OpenFgaClient, ReadRequestTupleKey

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

# Read all stored relationship tuples
body = ReadRequestTupleKey()

response = await api_instance.read(body)
# response = ReadResponse({"tuples": [Tuple({"key": TupleKey({"user":"...","relation":"...","object":"..."}), "timestamp": datetime.fromisoformat("...") })]})
```

##### Write (Create and Delete) Relationship Tuples

Create and/or delete relationship tuples to update the system state.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/Write)

###### Transaction mode (default)

By default, write runs in a transaction mode where any invalid operation (deleting a non-existing tuple, creating an existing tuple, one of the tuples was invalid) or a server error will fail the entire operation.

```python
# from openfga_sdk import OpenFgaClient, RelationshipCondition
# from openfga_sdk.client.models import ClientTuple, ClientWriteRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = ClientWriteRequest(
    writes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="viewer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
            condition=RelationshipCondition(
              name='ViewCountLessThan200',
              context=dict(
                  Name='Roadmap',
                  Type='Document',
              ),
            ),
        ),
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="viewer",
            object="document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5",
        ),
    ],
    deletes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="writer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
)

response = await fga_client.write(body, options)
```

Convenience `write_tuples` and `delete_tuples` methods are also available.

###### Non-transaction mode

The SDK will split the writes into separate requests and send them sequentially to avoid violating rate limits.

```python
# from openfga_sdk import OpenFgaClient, RelationshipCondition
# from openfga_sdk.client.models import ClientTuple, ClientWriteRequest, WriteTransactionOpts

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1",
    "transaction": WriteTransactionOpts(
        disabled=True,
        max_parallel_requests=10, # Maximum number of requests to issue in parallel
        max_per_chunk=1, # Maximum number of requests to be sent in a transaction in a particular chunk
    )
}
body = ClientWriteRequest(
    writes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="viewer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="viewer",
            object="document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5",
            condition=RelationshipCondition(
              name='ViewCountLessThan200',
              context=dict(
                  Name='Roadmap',
                  Type='Document',
              ),
            ),
        ),
    ],
    deletes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="writer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
)

response = await fga_client.write(body, options)
```

###### Conflict Options for Write Operations

OpenFGA v1.10.0+ supports conflict options for write operations to handle duplicate writes and missing deletes gracefully.

**Example: Ignore duplicate writes and missing deletes**

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientTuple, ClientWriteRequest
# from openfga_sdk.client.models.write_conflict_opts import (
#     ClientWriteRequestOnDuplicateWrites,
#     ClientWriteRequestOnMissingDeletes,
#     ConflictOptions,
# )

options = {
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1",
    "conflict": ConflictOptions(
        on_duplicate_writes=ClientWriteRequestOnDuplicateWrites.IGNORE, # Available options: ERROR, IGNORE
        on_missing_deletes=ClientWriteRequestOnMissingDeletes.IGNORE, # Available options: ERROR, IGNORE
    )
}

body = ClientWriteRequest(
    writes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="viewer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
    deletes=[
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="writer",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
)

response = await fga_client.write(body, options)
```

#### Relationship Queries

##### Check

Check if a user has a particular relation with an object.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/Check)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client import ClientCheckRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = ClientCheckRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="writer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    context=dict(
        ViewCount=100
    ),
)

response = await fga_client.check(body, options)
# response.allowed = True
```


##### Batch Check

Similar to [check](#check), but instead of checking a single user-object relationship, accepts a list of relationships to check. Requires OpenFGA version 1.8.0 or greater.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/BatchCheck)

> **Note**: The order of `batch_check` results is not guaranteed to match the order of the checks provided. Use `correlation_id` to pair responses with requests.

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import (
#   ClientTuple,
#   ClientBatchCheckItem,
#   ClientBatchCheckRequest,
# )
# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
checks = [ClientBatchCheckItem(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="editor",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
    context=dict(
        ViewCount=100
    )
), ClientBatchCheckItem(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="admin",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="editor",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ]
), ClientBatchCheckItem(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="creator",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
), ClientBatchCheckItem(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="deleter",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)]

response = await fga_client.batch_check(ClientBatchCheckRequest(checks=checks), options)
# response.result = [{
#   allowed: false,
#   correlation_id: "de3630c2-f9be-4ee5-9441-cb1fbd82ce75",
#   tuple: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "viewer",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#     contextual_tuples: [{
#       user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#       relation: "editor",
#       object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
#     }],
#    context=dict(
#        ViewCount=100
#    )
#   }
# }, {
#   allowed: false,
#   correlation_id: "6d7c7129-9607-480e-bfd0-17c16e46b9ec",
#   tuple: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "admin",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#     contextual_tuples: [{
#       user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#       relation: "editor",
#       object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
#     }]
#   }
# }, {
#   allowed: false,
#   correlation_id: "210899b9-6bc3-4491-bdd1-d3d79780aa31",
#   tuple: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "creator",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#   },
#   error: {
#       input_error: "validation_error",
#       message: "relation 'document#creator' not found"
#   }
# }, {
#   allowed: true,
#   correlation_id: "55cc1946-9fc3-4710-bd40-8fe2687ed8da",
#   request: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "deleter",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#   }},
# ]
```

If you are using an OpenFGA version less than 1.8.0, you can use `client_batch_check`,
which calls `check` in parallel. It will return `allowed: false` if it encounters an error, and will return the error in the body.
If 429s or 5xxs are encountered, the underlying check will retry up to 3 times before giving up.

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client import ClientCheckRequest
# from openfga_sdk.client.models import ClientTuple
# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = [ClientCheckRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="editor",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ],
    context=dict(
        ViewCount=100
    )
), ClientCheckRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="admin",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="editor",
            object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
        ),
    ]
), ClientCheckRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="creator",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
), ClientCheckRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="deleter",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)]

response = await fga_client.client_batch_check(body, options)
# response.responses = [{
#   allowed: false,
#   request: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "viewer",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#     contextual_tuples: [{
#       user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#       relation: "editor",
#       object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
#     }],
#    context=dict(
#        ViewCount=100
#    )
#   }
# }, {
#   allowed: false,
#   request: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "admin",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#     contextual_tuples: [{
#       user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#       relation: "editor",
#       object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
#     }]
#   }
# }, {
#   allowed: false,
#   request: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "creator",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#   },
#   error: <FgaError ...>
# }, {
#   allowed: true,
#   request: {
#     user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
#     relation: "deleter",
#     object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
#   }},
# ]
```


#### Expand

Expands the relationships in userset tree format.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/Expand)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientExpandRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = ClientExpandRequest(
    relation="viewer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
)

response = await fga_client.expand(body. options)
# response = ExpandResponse({"tree": UsersetTree({"root": Node({"name": "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer", "leaf": Leaf({"users": Users({"users": ["user:81684243-9356-4421-8fbf-a4f8d36aa31b", "user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"]})})})})})
```

#### List Objects

List the objects of a particular type a user has access to.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/ListObjects)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientListObjectsRequest, ClientTuple

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = ClientListObjectsRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    type="document",
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="writer",
            object="document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5",
        ),
    ],
    context=dict(
        ViewCount=100
    )
)

response = await fga_client.list_objects(body)
# response.objects = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"]
```

#### Streamed List Objects

List the objects of a particular type a user has access to, using the streaming API.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/StreamedListObjects)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientListObjectsRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

results = []

documents = ClientListObjectsRequest(
    type="document",
    relation="writer",
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
)

async for response in fga_client.streamed_list_objects(request):
    results.append(response)

# results = ["document:...", ...]
```

#### List Relations

List the relations a user has on an object.

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientListRelationsRequest

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}
body = ClientListRelationsRequest(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    relations=["can_view", "can_edit", "can_delete", "can_rename"],
    contextual_tuples=[  # optional
        ClientTuple(
            user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
            relation="writer",
            object="document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5",
        ),
    ],
    context=dict(
        ViewCount=100
    )
)

response = await fga_client.list_relations(body, options)

# response.relations = ["can_view", "can_edit"]
```

#### List Users

List the users who have a certain relation to a particular type.

[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/ListUsers)

```python
from openfga_sdk import OpenFgaClient
from openfga_sdk.models.fga_object import FgaObject
from openfga_sdk.client.models import ClientTuple
from openfga_sdk.client.models.list_users_request import ClientListUsersRequest

configuration = ClientConfiguration(
    api_url=FGA_API_URL,
    # ...
)

async with OpenFgaClient(configuration) as api_client:
    options = {
        "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
    }

    request = ClientListUsersRequest(
        object=FgaObject(type="document", id="2021-budget"),
        relation="can_read",
        user_filters=[
            UserTypeFilter(type="user"),
            UserTypeFilter(type="team", relation="member"),
        ],
        context={},
        contextual_tuples=[
            ClientTuple(
                user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
                relation="editor",
                object="folder:product",
            ),
            ClientTuple(
                user="folder:product",
                relation="parent",
                object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
            ),
        ],
    )

    response = await api_client.list_users(request, options)

    # response.users = [{object: {type: "user", id: "81684243-9356-4421-8fbf-a4f8d36aa31b"}}, {userset: { type: "user" }}, ...]
```

#### Assertions

##### Read Assertions

Read assertions for a particular authorization model.

[API Documentation](https://openfga.dev/api/service#/Assertions/Read%20Assertions)

```python
# from openfga_sdk import OpenFgaClient

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}

response = await fga_client.read_assertions(options)
```

##### Write Assertions

Update the assertions for a particular authorization model.

[API Documentation](https://openfga.dev/api/service#/Assertions/Write%20Assertions)

```python
# from openfga_sdk import OpenFgaClient
# from openfga_sdk.client.models import ClientAssertion

# Initialize the fga_client
# fga_client = OpenFgaClient(configuration)

options = {
    # You can rely on the model id set in the configuration or override it for this specific request
    "authorization_model_id": "01GXSA8YR785C4FYS3C0RTG7B1"
}

body = [ClientAssertion(
    user="user:81684243-9356-4421-8fbf-a4f8d36aa31b",
    relation="viewer",
    object="document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
    expectation=True,
)]

response = await fga_client.write_assertions(body, options)
```


### Retries

If a network request fails with a 429 or 5xx error from the server, the SDK will automatically retry the request up to 3 times with a minimum wait time of 100 milliseconds between each attempt.

To customize this behavior, create a `RetryParams` object and assign values to the `max_retry` and `min_wait_in_ms` constructor parameters. `max_retry` determines the maximum number of retries (up to 15), while `min_wait_in_ms` sets the minimum wait time between retries in milliseconds.

Apply your custom retry values by passing the object to the `ClientConfiguration` constructor's `retry_params` parameter.

```python
from openfga_sdk import ClientConfiguration, OpenFgaClient
from openfga_sdk.configuration import RetryParams
from os import environ

async def main():
    # Configure the client with custom retry settings
    config = ClientConfiguration(
        api_url=environ.get("FGA_API_URL"),
        retry_params=RetryParams(max_retry=3, min_wait_in_ms=250)
    )

    # Create a client instance and read authorization models
    async with OpenFgaClient(config) as client:
        return await client.read_authorization_models()
```


### API Endpoints

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*OpenFgaApi* | [**batch_check**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#batch_check) | **POST** /stores/{store_id}/batch-check | Send a list of &#x60;check&#x60; operations in a single request
*OpenFgaApi* | [**check**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#check) | **POST** /stores/{store_id}/check | Check whether a user is authorized to access an object
*OpenFgaApi* | [**create_store**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#create_store) | **POST** /stores | Create a store
*OpenFgaApi* | [**delete_store**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#delete_store) | **DELETE** /stores/{store_id} | Delete a store
*OpenFgaApi* | [**expand**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#expand) | **POST** /stores/{store_id}/expand | Expand all relationships in userset tree format, and following userset rewrite rules.  Useful to reason about and debug a certain relationship
*OpenFgaApi* | [**get_store**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#get_store) | **GET** /stores/{store_id} | Get a store
*OpenFgaApi* | [**list_objects**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#list_objects) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with
*OpenFgaApi* | [**list_stores**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#list_stores) | **GET** /stores | List all stores
*OpenFgaApi* | [**list_users**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#list_users) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type.
*OpenFgaApi* | [**read**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules
*OpenFgaApi* | [**read_assertions**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#read_assertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID
*OpenFgaApi* | [**read_authorization_model**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#read_authorization_model) | **GET** /stores/{store_id}/authorization-models/{id} | Return a particular version of an authorization model
*OpenFgaApi* | [**read_authorization_models**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#read_authorization_models) | **GET** /stores/{store_id}/authorization-models | Return all the authorization models for a particular store
*OpenFgaApi* | [**read_changes**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#read_changes) | **GET** /stores/{store_id}/changes | Return a list of all the tuple changes
*OpenFgaApi* | [**streamed_list_objects**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#streamed_list_objects) | **POST** /stores/{store_id}/streamed-list-objects | Stream all objects of the given type that the user has a relation with
*OpenFgaApi* | [**write**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#write) | **POST** /stores/{store_id}/write | Add or delete tuples from the store
*OpenFgaApi* | [**write_assertions**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#write_assertions) | **PUT** /stores/{store_id}/assertions/{authorization_model_id} | Upsert assertions for an authorization model ID
*OpenFgaApi* | [**write_authorization_model**](https://github.com/openfga/python-sdk/blob/main/docs/OpenFgaApi.md#write_authorization_model) | **POST** /stores/{store_id}/authorization-models | Create a new authorization model



### Models

## Documentation For Models

 - [AbortedMessageResponse](https://github.com/openfga/python-sdk/blob/main/docs/AbortedMessageResponse.md)
 - [Any](https://github.com/openfga/python-sdk/blob/main/docs/Any.md)
 - [Assertion](https://github.com/openfga/python-sdk/blob/main/docs/Assertion.md)
 - [AssertionTupleKey](https://github.com/openfga/python-sdk/blob/main/docs/AssertionTupleKey.md)
 - [AuthErrorCode](https://github.com/openfga/python-sdk/blob/main/docs/AuthErrorCode.md)
 - [AuthorizationModel](https://github.com/openfga/python-sdk/blob/main/docs/AuthorizationModel.md)
 - [BatchCheckItem](https://github.com/openfga/python-sdk/blob/main/docs/BatchCheckItem.md)
 - [BatchCheckRequest](https://github.com/openfga/python-sdk/blob/main/docs/BatchCheckRequest.md)
 - [BatchCheckResponse](https://github.com/openfga/python-sdk/blob/main/docs/BatchCheckResponse.md)
 - [BatchCheckSingleResult](https://github.com/openfga/python-sdk/blob/main/docs/BatchCheckSingleResult.md)
 - [CheckError](https://github.com/openfga/python-sdk/blob/main/docs/CheckError.md)
 - [CheckRequest](https://github.com/openfga/python-sdk/blob/main/docs/CheckRequest.md)
 - [CheckRequestTupleKey](https://github.com/openfga/python-sdk/blob/main/docs/CheckRequestTupleKey.md)
 - [CheckResponse](https://github.com/openfga/python-sdk/blob/main/docs/CheckResponse.md)
 - [Computed](https://github.com/openfga/python-sdk/blob/main/docs/Computed.md)
 - [Condition](https://github.com/openfga/python-sdk/blob/main/docs/Condition.md)
 - [ConditionMetadata](https://github.com/openfga/python-sdk/blob/main/docs/ConditionMetadata.md)
 - [ConditionParamTypeRef](https://github.com/openfga/python-sdk/blob/main/docs/ConditionParamTypeRef.md)
 - [ConsistencyPreference](https://github.com/openfga/python-sdk/blob/main/docs/ConsistencyPreference.md)
 - [ContextualTupleKeys](https://github.com/openfga/python-sdk/blob/main/docs/ContextualTupleKeys.md)
 - [CreateStoreRequest](https://github.com/openfga/python-sdk/blob/main/docs/CreateStoreRequest.md)
 - [CreateStoreResponse](https://github.com/openfga/python-sdk/blob/main/docs/CreateStoreResponse.md)
 - [Difference](https://github.com/openfga/python-sdk/blob/main/docs/Difference.md)
 - [ErrorCode](https://github.com/openfga/python-sdk/blob/main/docs/ErrorCode.md)
 - [ExpandRequest](https://github.com/openfga/python-sdk/blob/main/docs/ExpandRequest.md)
 - [ExpandRequestTupleKey](https://github.com/openfga/python-sdk/blob/main/docs/ExpandRequestTupleKey.md)
 - [ExpandResponse](https://github.com/openfga/python-sdk/blob/main/docs/ExpandResponse.md)
 - [FgaObject](https://github.com/openfga/python-sdk/blob/main/docs/FgaObject.md)
 - [ForbiddenResponse](https://github.com/openfga/python-sdk/blob/main/docs/ForbiddenResponse.md)
 - [GetStoreResponse](https://github.com/openfga/python-sdk/blob/main/docs/GetStoreResponse.md)
 - [InternalErrorCode](https://github.com/openfga/python-sdk/blob/main/docs/InternalErrorCode.md)
 - [InternalErrorMessageResponse](https://github.com/openfga/python-sdk/blob/main/docs/InternalErrorMessageResponse.md)
 - [Leaf](https://github.com/openfga/python-sdk/blob/main/docs/Leaf.md)
 - [ListObjectsRequest](https://github.com/openfga/python-sdk/blob/main/docs/ListObjectsRequest.md)
 - [ListObjectsResponse](https://github.com/openfga/python-sdk/blob/main/docs/ListObjectsResponse.md)
 - [ListStoresResponse](https://github.com/openfga/python-sdk/blob/main/docs/ListStoresResponse.md)
 - [ListUsersRequest](https://github.com/openfga/python-sdk/blob/main/docs/ListUsersRequest.md)
 - [ListUsersResponse](https://github.com/openfga/python-sdk/blob/main/docs/ListUsersResponse.md)
 - [Metadata](https://github.com/openfga/python-sdk/blob/main/docs/Metadata.md)
 - [Node](https://github.com/openfga/python-sdk/blob/main/docs/Node.md)
 - [Nodes](https://github.com/openfga/python-sdk/blob/main/docs/Nodes.md)
 - [NotFoundErrorCode](https://github.com/openfga/python-sdk/blob/main/docs/NotFoundErrorCode.md)
 - [NullValue](https://github.com/openfga/python-sdk/blob/main/docs/NullValue.md)
 - [ObjectRelation](https://github.com/openfga/python-sdk/blob/main/docs/ObjectRelation.md)
 - [PathUnknownErrorMessageResponse](https://github.com/openfga/python-sdk/blob/main/docs/PathUnknownErrorMessageResponse.md)
 - [ReadAssertionsResponse](https://github.com/openfga/python-sdk/blob/main/docs/ReadAssertionsResponse.md)
 - [ReadAuthorizationModelResponse](https://github.com/openfga/python-sdk/blob/main/docs/ReadAuthorizationModelResponse.md)
 - [ReadAuthorizationModelsResponse](https://github.com/openfga/python-sdk/blob/main/docs/ReadAuthorizationModelsResponse.md)
 - [ReadChangesResponse](https://github.com/openfga/python-sdk/blob/main/docs/ReadChangesResponse.md)
 - [ReadRequest](https://github.com/openfga/python-sdk/blob/main/docs/ReadRequest.md)
 - [ReadRequestTupleKey](https://github.com/openfga/python-sdk/blob/main/docs/ReadRequestTupleKey.md)
 - [ReadResponse](https://github.com/openfga/python-sdk/blob/main/docs/ReadResponse.md)
 - [RelationMetadata](https://github.com/openfga/python-sdk/blob/main/docs/RelationMetadata.md)
 - [RelationReference](https://github.com/openfga/python-sdk/blob/main/docs/RelationReference.md)
 - [RelationshipCondition](https://github.com/openfga/python-sdk/blob/main/docs/RelationshipCondition.md)
 - [SourceInfo](https://github.com/openfga/python-sdk/blob/main/docs/SourceInfo.md)
 - [Status](https://github.com/openfga/python-sdk/blob/main/docs/Status.md)
 - [Store](https://github.com/openfga/python-sdk/blob/main/docs/Store.md)
 - [StreamResultOfStreamedListObjectsResponse](https://github.com/openfga/python-sdk/blob/main/docs/StreamResultOfStreamedListObjectsResponse.md)
 - [StreamedListObjectsResponse](https://github.com/openfga/python-sdk/blob/main/docs/StreamedListObjectsResponse.md)
 - [Tuple](https://github.com/openfga/python-sdk/blob/main/docs/Tuple.md)
 - [TupleChange](https://github.com/openfga/python-sdk/blob/main/docs/TupleChange.md)
 - [TupleKey](https://github.com/openfga/python-sdk/blob/main/docs/TupleKey.md)
 - [TupleKeyWithoutCondition](https://github.com/openfga/python-sdk/blob/main/docs/TupleKeyWithoutCondition.md)
 - [TupleOperation](https://github.com/openfga/python-sdk/blob/main/docs/TupleOperation.md)
 - [TupleToUserset](https://github.com/openfga/python-sdk/blob/main/docs/TupleToUserset.md)
 - [TypeDefinition](https://github.com/openfga/python-sdk/blob/main/docs/TypeDefinition.md)
 - [TypeName](https://github.com/openfga/python-sdk/blob/main/docs/TypeName.md)
 - [TypedWildcard](https://github.com/openfga/python-sdk/blob/main/docs/TypedWildcard.md)
 - [UnauthenticatedResponse](https://github.com/openfga/python-sdk/blob/main/docs/UnauthenticatedResponse.md)
 - [UnprocessableContentErrorCode](https://github.com/openfga/python-sdk/blob/main/docs/UnprocessableContentErrorCode.md)
 - [UnprocessableContentMessageResponse](https://github.com/openfga/python-sdk/blob/main/docs/UnprocessableContentMessageResponse.md)
 - [User](https://github.com/openfga/python-sdk/blob/main/docs/User.md)
 - [UserTypeFilter](https://github.com/openfga/python-sdk/blob/main/docs/UserTypeFilter.md)
 - [Users](https://github.com/openfga/python-sdk/blob/main/docs/Users.md)
 - [Userset](https://github.com/openfga/python-sdk/blob/main/docs/Userset.md)
 - [UsersetTree](https://github.com/openfga/python-sdk/blob/main/docs/UsersetTree.md)
 - [UsersetTreeDifference](https://github.com/openfga/python-sdk/blob/main/docs/UsersetTreeDifference.md)
 - [UsersetTreeTupleToUserset](https://github.com/openfga/python-sdk/blob/main/docs/UsersetTreeTupleToUserset.md)
 - [UsersetUser](https://github.com/openfga/python-sdk/blob/main/docs/UsersetUser.md)
 - [Usersets](https://github.com/openfga/python-sdk/blob/main/docs/Usersets.md)
 - [ValidationErrorMessageResponse](https://github.com/openfga/python-sdk/blob/main/docs/ValidationErrorMessageResponse.md)
 - [WriteAssertionsRequest](https://github.com/openfga/python-sdk/blob/main/docs/WriteAssertionsRequest.md)
 - [WriteAuthorizationModelRequest](https://github.com/openfga/python-sdk/blob/main/docs/WriteAuthorizationModelRequest.md)
 - [WriteAuthorizationModelResponse](https://github.com/openfga/python-sdk/blob/main/docs/WriteAuthorizationModelResponse.md)
 - [WriteRequest](https://github.com/openfga/python-sdk/blob/main/docs/WriteRequest.md)
 - [WriteRequestDeletes](https://github.com/openfga/python-sdk/blob/main/docs/WriteRequestDeletes.md)
 - [WriteRequestWrites](https://github.com/openfga/python-sdk/blob/main/docs/WriteRequestWrites.md)



### OpenTelemetry

This SDK supports producing metrics that can be consumed as part of an [OpenTelemetry](https://opentelemetry.io/) setup. For more information, please see [the documentation](https://github.com/openfga/python-sdk/blob/main/docs/opentelemetry.md)

## Contributing

See [CONTRIBUTING](./CONTRIBUTING.md) for details.

## Author

[OpenFGA](https://github.com/openfga)

## License

This project is licensed under the Apache-2.0 license. See the [LICENSE](https://github.com/openfga/python-sdk/blob/main/LICENSE) file for more info.

The code in this repo was auto generated by [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) from a template based on the [python legacy template](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/python-legacy), licensed under the [Apache License 2.0](https://github.com/OpenAPITools/openapi-generator/blob/master/LICENSE).

