# Mitti (formerly SafetyCulture)

> Land a Mitti organisation's inspections, answers, actions, issues and schedules in your warehouse, read with an API token, with nothing to approve.

A Mitti stream lands a Mitti organisation's inspections and their answers, actions, issues, schedules, sites, people and assets in your warehouse, on the schedule you set. Each run reads only the inspections, answers, templates and actions that changed since the last run, the scheduled checks due around today, and the shorter lists whole. Mitti was called SafetyCulture until 11 August 2026: the same organisations, tokens and data, under a new name.

Mitti is a **published source**, like [Postgres](https://docs.sanda-os.com.au/streams/postgres) and [Bite](https://docs.sanda-os.com.au/streams/bite): sanda wrote the code that reads it and runs it as its own, so there is no connector for sam to write or for anyone to approve. Someone in your organisation makes an API token in Mitti, you paste it into sanda, choose what to read, and set a schedule.

:::note
Mitti is in the catalogue once it is switched on for your console, as a card under **Choose a source** that says **Ready now, published by sanda**. A **Mitti (formerly SafetyCulture)** card that says **Syncs through a connection** is the nightly [connection](https://docs.sanda-os.com.au/connections/add-a-connection) instead, not this pull (once the pull is switched on, that card ends in **· nightly**). If that is the only Mitti card, ask sanda support.
:::

## Before you start

- **Your Mitti organisation is on the Premium or Enterprise plan.** Mitti gives its API only to those plans.
- **Someone who can make an API token.** In Mitti that is a person with a full seat and the **Platform management: Organization**, **Platform management: Permissions** and **Platform management: Users** permissions. In sanda, only owners and admins connect an organisation and make a stream on it, because sanda reads it on the whole workspace's behalf.
- **A token that can see everything.** Mitti answers each request with only what the token's service user is allowed to see, and leaves the rest out without saying so. Give the service user **View all data**, or inspections and actions it can't see never reach your warehouse.
- **One organisation per token.** A token reads the organisation it was made in. Someone in several organisations makes a token in each, and connects each as its own organisation.
- **A token that is used stays alive.** A service user's token ends after going unused for the time chosen when it was made, from 31 to 180 days. Any stream that runs on a schedule uses it well inside that. A person's own token works too, but it ends after 30 days unused and when its person leaves the organisation, so a service user's is the better choice.

## Make an API token in Mitti

:::steps
1. **Open Integrations.** In the Mitti web app, click your organisation's name in the lower-left corner and select **Integrations**.
2. **Create a token.** Select the **API tokens** tab, then click **Create API token**.
3. **Fill in its details.** Name it so you know what uses it (`sanda`, say), choose its inactivity expiry, and select the service user's permission sets. Mitti selects every permission at first. If you narrow them, keep **View all data**.
4. **Copy it.** Click **Create token**, then click the token in the window that opens to copy it. Mitti shows it only once.
:::

## Connect the organisation

:::steps
1. **Open Pull.** Go to **Data · Streams**, open the **Pull** tab and press the **Mitti (formerly SafetyCulture)** card under **Choose a source**. The new pull's editor opens on **Connect a Mitti organisation** when none is connected yet. Once one is connected, **Connect an organisation** beside Mitti under **Connected** adds another.
2. **Paste the token** into **API token**. **Name** is optional: it is how the stream's page names the organisation. Left empty, the organisation is named after the token's last four characters, as `Mitti · ••••` and those four.
3. **Press Check and connect.** sanda asks Mitti which organisation the token is for before it keeps anything. A token Mitti refuses, or one for an organisation this workspace has already connected, is a sentence under the form, and nothing is kept.
:::

sanda keeps the token encrypted and only ever sends it to Mitti. It is never shown again, in the console or to sam. **Type it again**, beside the organisation under **Connected**, replaces the token (a new one after the old one expired, say), and the streams on it carry on: the new token must be for the same organisation. **Disconnect** forgets the token, and the streams on it wait until a token is typed again. The token itself works in Mitti until you revoke it there, under **Integrations** and **API tokens**, or it goes unused for longer than its expiry.

## Make a stream

:::steps
1. **Start it.** Press the **Mitti (formerly SafetyCulture)** card under **Choose a source**, or **New pull** and then the Mitti card.
2. **Choose when it runs.** **When it runs** comes first: how often, within which hours, on which days, with every run drawn out and the cost a month beneath. See [when a stream runs](https://docs.sanda-os.com.au/streams/schedules).
3. **Name it.** Its tables are named after it: a stream called `mitti` lands inspections in `raw.mitti__inspections`.
4. **Choose the organisation**, and, if your workspace has more than one warehouse, the warehouse it lands in. Both are chosen once.
5. **Choose what it reads.** Everything but **Activity log** is ticked. Untick what you don't need.
6. **Read history from** is optional: the date the first run starts from. Leave it empty to read the last 730 days.
7. **Days of checks read again** is how many days back each run reads scheduled checks again, so late and missed ones land. It starts at 35 and goes up to 150.
8. **Press Save pull.** Saving reads nothing yet: press **Run now**, or wait for its schedule.
:::

## What it reads

| Tick | Lands in | Each run reads |
|---|---|---|
| **Inspections** | `raw.<stream>__inspections` | The inspections that changed since the last run |
| **Inspection answers** | `raw.<stream>__inspection_items` | The answers of every inspection that changed since the last run |
| **Templates** | `raw.<stream>__templates` | The templates that changed since the last run |
| **Actions** | `raw.<stream>__actions` | The actions that changed since the last run |
| **Action assignees** | `raw.<stream>__action_assignees` | The whole list |
| **Action timeline** | `raw.<stream>__action_timeline_items` | The timeline of every action that changed since the last run |
| **Issues** | `raw.<stream>__issues` | The whole list |
| **Issue assignees** | `raw.<stream>__issue_assignees` | The whole list |
| **Issue timeline** | `raw.<stream>__issue_timeline_items` | The whole list |
| **Schedules** | `raw.<stream>__schedules` | The whole list |
| **Schedule assignees** | `raw.<stream>__schedule_assignees` | The whole list |
| **Schedule occurrences** | `raw.<stream>__schedule_occurrences` | The checks due from 35 days back to 31 days ahead |
| **Sites** | `raw.<stream>__sites` | The whole list |
| **Site members** | `raw.<stream>__site_members` | The whole list |
| **Users** | `raw.<stream>__users` | The whole list |
| **Groups** | `raw.<stream>__groups` | The whole list |
| **Group members** | `raw.<stream>__group_users` | The whole list |
| **Assets** | `raw.<stream>__assets` | The whole list |
| **Activity log** | `raw.<stream>__activity_log_events` | The activity log's new entries since the last run |

In the editor, each one that lands people's names, email addresses or IP addresses says so under its description: *Lands people's contact details.*

### Inspections and their answers

Each run reads the inspections changed since the last run, starting 10 minutes before the newest change the last one saw, so an inspection synced from a phone while the last run was reading isn't missed. Archived inspections and ones still in progress come too: Mitti leaves both out unless it is asked for them, and a warehouse that never sees work in progress undercounts it.

An inspection's answers come with it. Whenever an inspection changes, Mitti sends all of its answers again, and each lands on its own row, one per question, keyed by Mitti's id for that answer in that inspection. `audit_id` names the inspection it belongs to.

### Templates

The forms and checklists your inspections are made from, archived ones included, read when they change. An inspection's `template_id` names its template.

### Actions and issues

Actions are read when they change, as inspections are. An action's timeline (its status changes and comments) is read for every action that changed, so how long a defect took to close is in the warehouse.

Issues, their assignees and their timelines are read whole each run, because Mitti's feeds for them can't be asked for only what changed. Actions' assignees are read whole too, so someone taken off an action has their row marked `_deleted_at`.

### Schedules and scheduled checks

Schedules and their assignees are read whole. **Schedule occurrences** holds each check a schedule asked for, with whether it was done on time, late, missed or skipped. A check's status moves after it is due, so each run reads again every check due from 35 days back (or the stream's **Days of checks read again**) to 31 days ahead. A stream that hasn't run for a while reads back from where it got to.

The first run reads the same window, not the history date: checks due before it aren't read.

### Sites, users, groups and assets

Read whole each run. Sites come with the areas and regions above them, so every site's `parent_id` names a row, and with the sites deleted in Mitti, which keep their row with `deleted` true.

### Activity log

Off on a new stream, and read last. It records who did what in the organisation, deletions included, which the other feeds don't show. An organisation whose Premium plan or trial started on or after 12 August 2026 reads it only on Mitti's Enterprise plan; for one that can't, a run passes it over and says so, and reads everything else.

### Left out

- **Lone Worker jobs.** Lone Worker is a product of its own that not every organisation has, and a stream doesn't read it.
- **The photos and files themselves.** An answer's media land as their ids and references (`media_ids`, `media_hypertext_reference`), not the files.

## What lands in your warehouse

Every field becomes a column, and the whole record is kept in `_record`, as for every [pull](https://docs.sanda-os.com.au/streams/in#where-the-records-land). A few things are worth knowing when you model them:

- **Times are UTC**, as Mitti sends them, and land as times. Convert them to your own time zone in a view.
- **Ids are text**, as Mitti sends them: `audit_…` for an inspection, `template_…` for a template, `user_…` for a user. They join across tables: an answer's `audit_id`, an action's `audit_id` and `site_id`, an occurrence's `audit_id` once its inspection is started.
- **Scores are numbers**, and an inspection's `duration` is in seconds.
- **Some columns hold several values in one piece of text**, as Mitti writes them: an answer's `parent_ids` and `media_ids`, an action's `action_label`, an asset's `fields` (separated by `|`), and a timeline item's `item_data` and an activity entry's `metadata`, which are JSON written as text.
- **How deletions show.** A row a whole list no longer has (an issue, a user, a group) is marked `_deleted_at` and kept. So is a scheduled check that is gone from the days a run reads again. Mitti's inspections and actions feeds say nothing when one is deleted, so a deleted inspection or action stays as it was last read; the activity log is where its deletion shows.

## Change a stream

**Edit**, on the stream's page, changes everything but the organisation and the warehouse. Something you take off keeps its table, with what it landed. A new **Read history from** date takes effect the next time everything is read from the start: press **Load everything again** on the stream's page. A new **Days of checks read again** takes effect on the next run.

## When something goes wrong

| What you see | What to do |
|---|---|
| *Mitti refused the API token sanda reads … with (`401`). It may have expired after going unused, or been revoked.* | The token ended or was revoked. The stream waits, rather than failing again and again. Make a new token in Mitti and press **Type it again** beside the organisation under **Connected**. The first run after catches up |
| *Mitti didn't let this token read assets. Give the service user that permission, or take it off the stream.* (or another table) | The run passed over that table and read the rest. Give the token's service user the permission in Mitti, or take the table off the stream with **Edit** |
| *Mitti didn't let this token read the activity log, which needs Mitti's Enterprise plan for this organisation. Take Activity log off the stream.* | The run passed over the activity log and read the rest. Take **Activity log** off the stream with **Edit**, or move the organisation to Mitti's Enterprise plan |
| Inspections or actions you can see in Mitti are missing | The token's service user can't see them, and Mitti leaves them out without saying so. Give it **View all data** in Mitti, then press **Load everything again** on the stream's page |
| *That organisation is already connected as …* | That organisation has a token already. Press **Type it again** beside it under **Connected** instead |
| *Mitti didn't say which organisation that API token is for, so nothing was saved.* | sanda asks Mitti whose token it is and, when Mitti doesn't say, names the organisation from a template the token can see. This token's service user can't see a single template, so trying again won't help. Give it **View all data** in Mitti, then connect again |
| Mitti asked sanda to slow down | Nothing to do: the run waits until Mitti's minute is up, then carries on |
| Mitti didn't answer, or answered with an error of its own | Nothing to do: the run tries again, and the next run carries on from the last page that landed |

A run that passed over a table says why on the run, under its status. A failed run counts toward the stream pausing itself, as any stream's does. See [runs](https://docs.sanda-os.com.au/streams/runs).

## Limits

- A run makes at most 4 requests a second. Mitti allows one token 800 requests a minute, shared by everything that uses the same token, so a stream leaves room for the rest.
- A request for inspections, their answers, actions, issues, their assignees and timelines, or assets asks for up to 100 records, and one for the activity log up to 250 entries. Templates, sites, users and groups, and the members of sites and groups, come in pages of the size Mitti chooses.
- A request for schedules, their assignees or scheduled checks asks for up to 1,000 schedules or checks. A check assigned to several people comes back as a row for each, so a page can hold more rows than that.
- **Days of checks read again** goes up to 150.
- One run lands at most 20,000,000 records, so a long history is several runs.

A Mitti stream is billed like any pull: a charge for each run that does its work, and the rows it lands past what your edition includes. See [what streams cost](https://docs.sanda-os.com.au/streams#what-streams-cost).

:::links
- [Pull](https://docs.sanda-os.com.au/streams/in): Every way records come into your warehouse on a stream.
- [Stream graphs](https://docs.sanda-os.com.au/streams/graphs): Model what a stream lands, then send the result out, every time it lands.
- [Runs](https://docs.sanda-os.com.au/streams/runs): What each run did, and what to do when one fails.
:::
