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

# Agent access

> What an AI agent can read and change in Datalyr: the MCP server, the Read and Write API, and the machine-readable docs.

An agent reaches Datalyr two ways. Both answer the same questions about one workspace.
Both can change two kinds of object when a person grants a write scope.

| Way in                                             | Credential                                                       | Best for                                      |
| -------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------- |
| Hosted MCP server at `https://api.datalyr.com/mcp` | OAuth, scope `datalyr:read` plus any write scope a person grants | Claude, Codex, and any client that speaks MCP |
| Read and Write API at `https://api.datalyr.com/v1` | A named API key, `dk_agent_`                                     | Your own code, scripts, and agent frameworks  |

Reading needs `datalyr:read` and nothing else. Writing needs a named key or an OAuth
token that carries the matching write scope. The original workspace Agent key carries
`datalyr:read` forever, so no key already in circulation gained write power.

## Which to pick

Pick MCP when a person drives the client and can complete a browser sign-in. The token
is short-lived, and no key is stored anywhere.

Pick the API when code runs without a person present. See
[Authentication](/api-reference/authentication) to create a key.

## In-app chat is a third surface, and it never writes

The Datalyr dashboard has its own chat agent. It holds 24 read tools and no write tools.
It authenticates with the workspace Agent key, which carries `datalyr:read` only.
The panel has no consent screen, so nobody can grant it more.

## The 35 MCP tools

27 tools read. 8 tools change something or start work. `tools/list` is the authority:
read it at the start of a session and branch on what comes back. Do not hard-code the
tool set.

### The 27 read tools

| Tool                    | Returns                                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `list_workspaces`       | Every workspace you can access. Call this first.                                                                    |
| `get_overview`          | Visitors, pageviews, sessions, custom events, and a time series                                                     |
| `get_traffic`           | A breakdown by referrer, campaign, or page                                                                          |
| `get_devices`           | A breakdown by browser, operating system, or device type                                                            |
| `get_locations`         | A breakdown by country, region, or city                                                                             |
| `get_events`            | Raw events, filtered by name, campaign, country, page, or custom property                                           |
| `list_event_names`      | Distinct event names of the last 30 days                                                                            |
| `list_event_properties` | Custom event properties this workspace sends, with a sample value and type                                          |
| `get_realtime`          | Active visitors, pages, events, revenue, and a minute timeline                                                      |
| `get_attribution`       | Attribution by channel under a chosen model, with an unattributed bucket                                            |
| `list_users`            | Visitors and identified users, with an optional search                                                              |
| `get_user`              | One user's profile, sessions, journey, and conversions                                                              |
| `get_ads`               | Provider-reported spend, delivery, conversions, and ROAS                                                            |
| `get_revenue`           | Revenue, orders, subscriptions, refunds, AOV, and a time series                                                     |
| `get_commerce_metrics`  | Certified revenue, spend, profit, margin, ROAS, and MER                                                             |
| `list_metrics`          | The catalog of metric ids you can query, with units and availability                                                |
| `query_metrics`         | Up to 50 named metrics over a date range, with an optional comparison                                               |
| `get_retention`         | Person-grain retention cohorts, with active persons and revenue per period                                          |
| `get_ltv`               | Cohort LTV: cumulative revenue and revenue per acquired person, optionally split by first-touch acquisition channel |
| `get_funnel`            | An ordered funnel over 2 to 5 event names, with per-step conversion rates                                           |
| `get_tags`              | Tracking-link tag counts and percentages                                                                            |
| `get_workspace`         | Name, domain, timezone, and connected platforms                                                                     |
| `get_onboarding_status` | Plan, whether tracking ever sent an event, live sources, and the next steps                                         |
| `get_usage`             | Plan, current-period event and postback usage, and API usage                                                        |
| `search_docs`           | Matching pages of this documentation, with a link and an excerpt                                                    |
| `get_script_proposals`  | Container-script drafts an agent submitted, and what a human decided                                                |
| `get_export_status`     | One export job's state, and its download URL once the file exists                                                   |

### The 8 tools that write or start work

| Tool                       | Does                                                                          | Scope                     |
| -------------------------- | ----------------------------------------------------------------------------- | ------------------------- |
| `create_conversion_rule`   | Creates a conversion rule. Dry run by default.                                | `datalyr:write:rules`     |
| `update_conversion_rule`   | Edits a conversion rule. Dry run by default.                                  | `datalyr:write:rules`     |
| `delete_conversion_rule`   | Deletes a conversion rule. Dry run by default.                                | `datalyr:write:rules`     |
| `create_link`              | Creates a trackable link. Dry run by default.                                 | `datalyr:write:links`     |
| `update_link`              | Edits a trackable link. Dry run by default.                                   | `datalyr:write:links`     |
| `delete_link`              | Deletes a trackable link. Dry run by default.                                 | `datalyr:write:links`     |
| `propose_container_script` | Submits a container-script draft for a human to review. It publishes nothing. | `datalyr:propose:scripts` |
| `create_export`            | Starts an export job. It returns a job id, never data.                        | `datalyr:read`            |

The setup steps for Claude and Codex are on
[Connect Claude or Codex](/datalyr-mcp).

## What an agent can change, and what stops it

An agent can change conversion rules and trackable links. It can draft a container
script. It cannot do anything else. Tracking domains, filter settings, team membership,
and billing have no agent surface at all.

| Guard                               | Detail                                                                                                      |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Scopes are granted, never inherited | An owner creates a named key with an explicit scope list. The original workspace Agent key never gains one. |
| Dry run is the default              | The six rule and link tools preview by default. Pass `dry_run: false` to apply.                             |
| A preview shows the real effect     | A rule's dry run names the platform, ad account, and asset the rule would fire to.                          |
| Every applied write is recorded     | Read the log at `GET /v1/audit`. Each entry holds the state before the change.                              |
| Every applied write can be reversed | `POST /v1/audit/{auditId}/undo` restores that prior state under the original id.                            |
| Creates take an `Idempotency-Key`   | A retry with the same key and body returns the first response, not a second object.                         |
| Container scripts are propose-only  | No scope publishes a script, and no endpoint approves one. An owner or admin approves it in the dashboard.  |

A container script is arbitrary JavaScript on every page of your site, next to your
checkout. That is why a leaked key can draft one and can never ship one.

## Exports return a job, not a file

`create_export` answers with a job id. Poll `get_export_status` until the state is
`completed`, then read `download.url`.

Two clocks run on a finished export. The signed URL lasts one hour, so fetch it on use
rather than storing it. The file itself is deleted seven days after creation.

## What the HTTP API adds

Every MCP tool maps to a `/v1` endpoint, so the API covers the same ground with three
extras an agent framework often wants. It also carries routes MCP does not expose at all,
including `POST /v1/signup`, `GET /v1/audit`, and the undo path.

| Extra                  | Detail                                                                                                                      |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Exact pagination       | `/events` and `/users` return `limit`, `offset`, and `has_more`. See [Errors and limits](/api-reference/errors-and-limits). |
| Rate-limit budget      | Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`.                                                     |
| An OpenAPI description | The `/v1` schema drives this section, so a client can generate its own bindings.                                            |

## Reading a response safely

These four rules keep an agent from reporting a number that isn't there.

| Rule                                    | Why                                                                                           |
| --------------------------------------- | --------------------------------------------------------------------------------------------- |
| Treat `503` as unknown, never as zero   | `/ads` and `/commerce-metrics` fail loudly rather than answer with a wrong total.             |
| Read `complete` before you read a total | A `200` with `complete: true` is the only answer that covers the range.                       |
| Read `attribution_source`, not `source` | `source` carries the transport during the events-source rename.                               |
| Page until `has_more` is `false`        | A full page is not proof that more rows exist, and a short page is not proof that they don't. |

## Sending events is a different credential

Reading and writing do not share a key or a host. An agent that also sends events uses
the write key against `https://ingest.datalyr.com`. See
[Ingest API](/api-reference/ingest).

The write key reads nothing. Never point `POST /attribution/lookup` at an email address
a user typed into your own product.

## Machine-readable docs

| Path                                     | Holds                                                                           |
| ---------------------------------------- | ------------------------------------------------------------------------------- |
| `https://docs.datalyr.com/llms.txt`      | A short site description and the pages an agent needs first                     |
| `https://docs.datalyr.com/llms-full.txt` | The same index, plus the full text of the MCP, authentication, and errors pages |
| Any page path plus `.md`                 | That one page as Markdown, for example `/api-reference/authentication.md`       |

## Verify

1. Ask your client: `List my Datalyr workspaces.`
2. Confirm the reply names the workspace you expect.
3. Run the `curl` on [Authentication](/api-reference/authentication) with your Agent key.
4. Confirm the response names the same workspace.

## When it doesn't work

| Symptom                                                    | Cause                                                                            | Fix                                                                             |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| The client lists no Datalyr tools                          | The connector is added but not connected.                                        | Open the connector and sign in to Datalyr.                                      |
| A tool you expected is missing                             | Your token or key does not carry the scope that tool needs.                      | Read `tools/list` and ask an owner for a key with that scope.                   |
| `403` with `insufficient_scope`                            | The route needs a scope your credential does not hold.                           | The response names it in `required_scope`. Ask an owner for it.                 |
| A write applied when you wanted a preview                  | You passed `dry_run: false`.                                                     | Reverse it with `POST /v1/audit/{auditId}/undo`.                                |
| `401` from `/v1`                                           | You sent a `dk_` write key.                                                      | Send the `dk_agent_` key.                                                       |
| `429` on every request                                     | The key passed 100 requests in 60 seconds.                                       | Wait for `Retry-After`, which is `60`.                                          |
| `429` sooner than expected, with `X-RateLimit-Degraded: 1` | Our rate-limit store is unreachable, so reads run under a smaller standby limit. | Slow down and retry. See [Errors and limits](/api-reference/errors-and-limits). |
| A total looks too small                                    | The agent read one page and stopped.                                             | Page until `has_more` is `false`.                                               |

## Next

* [Connect Claude or Codex](/datalyr-mcp): add the MCP server to your client.
* [API reference](/api-reference/index): every endpoint and its parameters.
* [Ingest API](/api-reference/ingest): send events over raw HTTP.
