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

# Insert facts

Facts represent your application's authorization data in Oso Cloud.\
This page shows how to **insert facts manually or at runtime** using the API, SDKs, or CLI.

Use this pattern when:

* Testing or iterating on your policy in development.
* Adding or updating roles, relationships, or attributes during runtime.
* Keeping facts **up-to-date** in production with the [Batch API](/reference/api/centralized-authorization-data/post-batch).
* Performing small- to medium-sized inserts (for large-scale sync, see [Sync facts](/develop/facts/sync-facts)).

## Insert facts in development

You can quickly add or remove facts when testing your policy.

### Oso Cloud UI

Use the [**Fact Schema**](https://ui.osohq.com/facts/?tab=schema) in the Oso Cloud UI to quickly add or remove facts when testing or iterating on your policy.

The Fact Schema lists all fact types referenced in your policy; these are the types Oso Cloud expects you to send.

**Add a fact:** Click **`+ Add`** next to a fact type.\
**Remove a fact:** Click **`▼ Show matching facts`**, then **`Delete`** next to the fact.

### CLI

```bash theme={null}
# Give alice the admin role on org:acme
oso-cloud tell has_role User:alice admin Org:acme
```

### SDKs

```python theme={null}
# Python
oso.insert(("has_role", User("alice"), "admin", Org("acme")))
```

```javascript theme={null}
// Node.js
await oso.insert(["has_role", {type: "User", id: "alice"}, "admin", {type: "Org", id: "acme"}]);
```

See [SDK references](/reference/sdks/overview) for full method signatures.

## Insert facts at runtime

When your application creates or updates data, [insert facts](/reference/sdks/facts#insert-facts) to reflect the new state.

Example code below:

```python theme={null}
from oso_cloud import Value

# Insert a single fact
oso.insert((
  "has_role", 
  Value("User", "bob"), 
  "owner", 
  Value("Organization", "acme")
))

# Insert with variables for reuse
user = Value("User", "alice")
repo = Value("Repository", "anvils")
oso.insert(("has_role", user, "maintainer", repo))
```

## Add and remove facts with Batch

Whenever you insert, update, or delete authorization-relevant data in your application, you should mirror that change in Oso Cloud using the `Batch API`. This keeps your authorization facts consistent with your application state.

The dual-writes approach is similar to updating a search index: Oso Cloud maintains an index of authorization data that your policy evaluates against.

For example, when creating a new resource, send facts that represent its relationships and roles:

```python theme={null}
def create_repository(org_id):
    org = Organization(org_id)
    repo = Repository(payload["name"], org)

    # Persist the repository to the database
    session.add(repo)

    # Send facts to Oso Cloud
    with oso.batch() as tx:
        # The parent organization of `repo` is `org`
        tx.insert(("has_relation", repo, "organization", org))
        # The current user gets the `admin` role on the new `repo`
        tx.insert(("has_role", current_user, "admin", repo))

    # Commit once Oso Cloud is updated
    session.commit()

    return repo.as_json(), 201
```

When deleting a resource, remove the corresponding facts:

```python theme={null}
with oso.batch() as tx:
    # Remove all `has_relation` facts for the repository
    tx.delete(("has_relation", repo, None, None))
    # Remove all `has_role` facts for the repository
    tx.delete(("has_role", None, None, repo))

```

## Best practices

* Prefer [batch APIs](/reference/api/centralized-authorization-data/post-batch) for multiple inserts.
* Use descriptive predicates like "has\_role", "is\_banned", or "has\_relation".
  -Avoid inserts for ephemeral data (e.g. request time, IP). Use [context facts](/develop/facts/context-facts) instead.
* Test your facts in the [Explain tab](https://ui.osohq.com/explain) to verify behavior.
