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

# Build a Pipeline Dashboard

> Trace watched folders through ingestion, batches, agent runs, tasks, and notification delivery with a read-only integration.

Use these endpoints to answer which folder triggered a run, where ingestion failed, how many tiles finished, which tasks need credits, and whether a notification was delivered. The API returns persisted evidence; missing evidence is unknown.

## Give your dashboard a read-only key

In the editor's API key settings, enable **Restricted** and set **Agents**, **Agent runs**, and **Triggers** to **Read**. Leave the other entities at **None**. See [API key permissions](/api/api-key-scopes) for the complete scope list and error contract.

Send `Authorization: Bearer mk_your_api_key` on each request. Start with `GET /whoami` and inspect `scopes`. Set `X-Workspace-Id` to your workspace UUID when observing one workspace. Keys belong to an organization; a workspace header narrows that access. Public API access also requires an eligible paid plan.

## Trace a folder to its run

1. [List storage triggers](/api/observability/list-storage-triggers). Save each trigger's `id`, `agent_id`, provider, root configuration, and `selected_folder_display_path`.
2. [List watched folders](/api/observability/list-watched-folders) for a trigger. `watcher.folder_id` identifies the provider folder. Check `is_active`, watcher `status`, `last_error`, and `deleted_at`. Inactive and deleted watcher records are included unless you filter them.
3. [List ingestion events](/api/observability/list-storage-events). Events with errors may have no batch or run yet. Use `batch_ids` for exact batch links; do not match events to runs by timestamps or filenames.
4. [List storage batches](/api/observability/list-storage-batches) with `trigger_id` and optionally `folder_id`. `agent_state_id` is the run ID. Inspect `stage`, `last_error`, `error_message`, and the authorized `run` snapshot. [Batch items](/api/observability/list-batch-items) link a batch back to its input events.
5. [Read run progress](/api/observability/get-run-progress) using that run ID. Whole-run `node_status_counts` and `completed_node_percent` accompany a page of runtime tiles. Fetch [tasks](/api/observability/list-run-tasks) for complete task evidence.
6. Read [notification configurations](/api/observability/list-notification-configurations) for current settings and [delivery receipts](/api/observability/list-notification-deliveries) for actual sending, delivered, failed, or skipped evidence. Configuration alone does not establish delivery.

### IDs and values

| Value | How to use it |
| - | - |
| Trigger `id` | Pass as `trigger_id`; this is the storage subscription UUID. |
| `watcher.folder_id` | Provider folder string; it is different from the watcher UUID and subscription UUID. |
| Event `drive_parent_id` | Immediate provider parent folder. It can differ from the batch folder when batching by ancestor/subfolder. |
| Batch `batch_folder_node_id` | Folder used to group the batch. The batches `folder_id` filter targets this value. |
| Batch `agent_state_id` | Exact run UUID, or `null` before a run is attached. |
| Progress `nodes[].node_id` | Runtime tile UUID; use as the tasks or notifications `node_id` filter. |
| `completed_node_percent` | Rounded completed tiles / all tiles × 100. It is not an ETA or the fraction of runtime elapsed. Failed/skipped tiles can prevent 100%. |
| Task `progress` / embedded `progress_percent` | Task-reported percentage, not a whole-run percentage. A missing value is unknown. |
| Progress `nodes[].needs_credits` | Whether any persisted task on that tile needs credits, including tasks outside the recent snapshot. |
| `historical_delivery_status` | `unknown_without_receipt`: no receipt means delivery cannot be established. Receipts begin when recording is enabled and do not backfill old notifications. |
| Nullable run `updated_at` | Older rows may have no known update timestamp. Run-row updates do not capture every tile/task update. |

Use [List Pipeline Runs](/api/observability/list-pipeline-runs) for lightweight run discovery at scale. It avoids graph/input/output expansion and supports cursor paging and run-row update watermarks.

For an existing run search, [List All Agent Runs](/api/agent-runs/get-all-agent-runs), [List Agent Runs](/api/agent-runs/get-agent-runs), and [List Trigger Runs](/api/agent-runs/get-trigger-runs) accept `folder_id`, `batch_id`, `batch_key`, `storage_trigger_id`, and `production_id`. These match persisted `triggered_by` metadata; not every run has those fields.

## Poll without losing updates

Every new list endpoint accepts `limit` (default 25, maximum 100) and an opaque `cursor`. Preserve filters and pass `next_cursor` verbatim until it is `null`. Do not construct cursors. Each progress/configuration page counts tiles; a progress tile embeds at most five recent tasks. Whole-run totals are independent of the page.

For an initial history load, paginate a bounded `from`/`to` creation-time window. For subsequent polls:

1. Record the poll start time. Start without a cursor, using the previous `updated_from` watermark with a short overlap.
2. Fetch every page with identical filters. Upsert each record by its stable ID.
3. After every page succeeds, advance the watermark to the poll start time. Keep the previous watermark if any page fails.

Results are not a transaction snapshot. Creation order stays stable, but updates can happen while paging; overlapping polls and ID-based deduplication handle those changes. `updated_from` filters the listed resource's update time. Folder results use the later of the subscription and watcher update time. Progress filters tile updates, while tasks filter task updates: poll the tasks endpoint as well when task changes matter. Batch items have no update watermark and reject `updated_from`; load them when a batch is discovered or changes.

Keep trigger/folder configuration cached, poll active runs more often than completed history, use source and time filters, and limit simultaneous requests. Avoid polling every historical run on every dashboard refresh. A completed run can be refreshed less frequently; treat status values as extensible strings.

## Instructions for an AI agent

You can give an agent this procedure along with the [OpenAPI contract](/openapi.json):

```text theme={null}
Use the Mosaic API at https://api.mosaic.so with the supplied read-only key.
Verify /whoami and scopes first. Keep credentials out of logs and outputs.
Use the supplied workspace UUID in X-Workspace-Id.
Discover storage triggers, then follow folder → event → batch → exact run IDs.
Page every list using next_cursor verbatim; preserve filters and deduplicate by ID.
Use whole-run counts for completion, task evidence for credit/error diagnosis,
and delivery receipts for notification status. Report absent evidence as unknown.
On api_key_scope_required, stop that operation, report required_scope and
resolution, and ask the owner/admin for an appropriately scoped key.
Do not retry a permission failure with the same key or try another endpoint
as a permission workaround. Retry transient 5xx failures with bounded backoff.
```

## Handle errors by meaning

| Response | Agent action |
| - | - |
| `400` | Correct the UUID, cursor, timestamp, or filter. Do not retry an unchanged invalid request. |
| `401` | Supply a valid unrevoked API key. |
| `403`, `code: api_key_scope_required` | Report `required_scope`, `granted_scopes`, and `resolution`. `retryable: false` means the same key cannot solve this. |
| `403`, `code: api_key_scope_unsupported` | Use the documented API contract or contact support; the route is unavailable to restricted keys. |
| Other `403` | Inspect workspace access or paid-plan eligibility; a scope change may not solve it. |
| `404` | The resource is absent or outside the authorized organization/workspace. Do not infer which. |
| `500` | Evidence could not be loaded. Retry with bounded exponential backoff and keep the last successful data marked stale. Do not replace it with healthy/empty results. |

See each endpoint reference for request examples, actual response fields, and example values.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.