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

# Digital twins

> Stateful clones of external services so sandboxes never hit real APIs

A digital twin is a stateful clone of an external service (Stripe, Slack, GitHub, Dropbox, Google Drive, Google Calendar, Box, Notion, Discord, Waterfall, and more) that replicates the endpoints, webhooks, edge cases, and error modes of the real thing. Twins are how Arga gives every PR a sandbox that behaves like production without touching real APIs.

## Why digital twins?

Real integrations evolve. Static mocks don't, so tests drift from production. And when staging hits real Stripe, Slack, or Notion, state leaks across runs and you can't simulate failures, rate limits, or webhook errors. Digital twins solve both problems.

| Approach      | Stateful | Behavioural | Edge cases | Safe |
| ------------- | -------- | ----------- | ---------- | ---- |
| Real service  | Yes      | Yes         | Yes        | No   |
| Static mocks  | No       | No          | No         | Yes  |
| Digital twins | Yes      | Yes         | Yes        | Yes  |

## Properties

<AccordionGroup>
  <Accordion title="Stateful" icon="database">
    The twin remembers state before an API call and updates state after the call completes. If you create a Stripe customer, subsequent calls reflect that customer's existence — just like the real Stripe API.
  </Accordion>

  <Accordion title="Behavioural" icon="arrows-spin">
    The twin reacts the same way the real service would to an API call, including error responses, rate limits, and side effects. A payment to a non-existent customer returns the same error code Stripe would.
  </Accordion>
</AccordionGroup>

## Supported services

Arga currently supports these sandbox twins. Twins are split into two categories:

* **UI twins** expose a browsable sandbox surface in the Arga UI so you can interact with the twin directly during a run — useful for services with meaningful user-facing state (chats, files, dashboards, checkout pages).
* **Backend twins** intercept outbound API traffic only. They have no UI surface because the underlying service is consumed purely programmatically.

For per-twin support details, known limitations, and MCP tool coverage, see the [twin reference](/concepts/twin-reference). The lists below match the twins currently exposed by the app's provisioning catalog.

### UI twins

| Twin                                                          | What it stands in for                                                                                                                                             | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`discord`](/concepts/twin-reference#discord)                 | Discord API v10 (`discord.com`, `api.discord.com`, `discordapp.com`)                                                                                              | Intercepts Discord API v10 operations including guilds, channels, messages, reactions, threads, members, roles, bans, invites, webhooks, emojis, stickers, scheduled events, stage instances, auto-moderation rules, soundboard sounds, guild templates, and user endpoints. The Create Message endpoint (`POST /channels/{channel_id}/messages`) accepts `multipart/form-data` requests with file attachments — uploaded files are recorded as attachment objects on the message with `id`, `filename`, `size`, `url`, `proxy_url`, and `content_type` fields, matching the real Discord API response shape. You can send message content via a `payload_json` field or a plain `content` form field alongside one or more `files[n]` (or `file`) parts. Supports deterministic seeding, bot-token authentication, configurable [server boost levels](/concepts/digital-twins#discord-twin-boost-levels) (controlling file upload size and emoji slot limits), and event delivery with webhook subscriptions.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| [`dropbox`](/concepts/twin-reference#dropbox)                 | Dropbox API v2 (`api.dropboxapi.com`, `content.dropboxapi.com`, `notify.dropboxapi.com`)                                                                          | Intercepts Dropbox API v2 operations including files (list, upload, download, copy, move, delete, search, revisions, tags), sharing (shared links, shared folders, file members), file requests, file properties, team management (members, groups, team folders, legal holds, namespaces, devices, linked apps, sharing allowlist, audit log), and admin controls. Supports upload sessions, batch operations, webhook deliveries, and event replay. Seeded with a starter folder tree and team members for deterministic testing. Enforces [account tier-based storage quotas](/concepts/digital-twins#dropbox-twin-account-tiers) — uploads that exceed the quota return an `insufficient_space` error.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| [`github`](/concepts/twin-reference#github)                   | GitHub API (`api.github.com`, `github.com`, `raw.githubusercontent.com`), GitHub CLI (`gh`), and [GitHub MCP server](https://github.com/github/github-mcp-server) | Intercepts GitHub REST API operations including repositories, file contents (branch-aware), raw file downloads from `raw.githubusercontent.com/{owner}/{repo}/{ref}/{path}` and `github.com/{owner}/{repo}/raw/{ref}/{path}` (served as public content without a bearer token and resolving slash-containing branch names), pull requests (with merge and reviewer requests), issues, branches (with protection rules), commits, check runs, check suites, git references, labels (repo-level and issue-level), pull request reviews and review comments, commit statuses, search (repositories, users, issues, code), organizations, users, GitHub App endpoints (installations, access tokens, repository listings, app metadata, and the manifest registration flow for creating multiple GitHub Apps at runtime), and webhooks. Adds GitHub CLI (`gh`) and GitHub MCP server compatibility: the GitHub Enterprise-style `/api/v3/...` REST prefix and the `/api/graphql` endpoint are accepted alongside the standard paths, with extended REST coverage for `/meta`, `/rate_limit`, `/zen`, repository archives, releases, gists, notifications, projects v2, Actions workflows, runs, jobs, artifacts, cache, variables, and secrets, codespaces, user SSH/signing/GPG keys, starred repositories, sub-issues and issue types, security advisories, Dependabot alerts, and code- and secret-scanning alerts. Exposes a GraphQL surface at `POST /graphql` (also reachable through `POST /api/graphql`) covering the queries and mutations used by `gh` and the GitHub MCP server, backed by the same store as the REST handlers. Supports deterministic seeding (repos, files, issues, PRs, and GitHub App configuration), multi-app installations scoped to their owning GitHub App, token authentication with OAuth scope enforcement (parent scopes automatically grant children), configurable default token scopes, OAuth flows, and webhook delivery with signed payloads for push, pull request, check run, and check suite events.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| [`google_calendar`](/concepts/twin-reference#google-calendar) | Google Calendar API (`www.googleapis.com`, `calendar.googleapis.com`)                                                                                             | Intercepts Google Calendar v3 operations including calendars, calendar list, events, ACL rules, settings, free/busy queries, colors, and webhook deliveries (with watch support for events, ACL, calendar list, and settings resources).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| [`google_drive`](/concepts/twin-reference#google-drive)       | Google Drive API (`www.googleapis.com`, `content.googleapis.com`)                                                                                                 | Intercepts Google Drive v3 operations including files (list, get, create, update, copy, delete, export, watch), permissions, revisions, comments, replies, shared drives, change feeds, and resumable uploads. Serves a discovery document compatible with the official Google API client libraries. File resources include the full set of common fields (capabilities, links, ownership, thumbnails) expected by the Google Drive SDK. Enforces OAuth scope requirements on every API call with hierarchical scope expansion (for example, `drive` implies `drive.readonly`, `drive.file`, and `drive.metadata`). Enforces [storage tier-based quotas](/concepts/digital-twins#google-drive-twin-storage-tiers) — uploads that exceed the quota return a `storageQuotaExceeded` error.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| [`notion`](/concepts/twin-reference#notion)                   | Notion API (`api.notion.com`, `notion.so`)                                                                                                                        | Intercepts Notion API operations for pages, databases, blocks, users, and search. Enforces [workspace plan-based limits](/concepts/digital-twins#notion-twin-workspace-plans) on file uploads and guest counts. Supports capability-based access control on user endpoints with granular email visibility (`read_user_information_with_email`, `read_user_information_no_email`, `no_user_information`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| [`slack`](/concepts/twin-reference#slack)                     | Slack Web API, Slack CLI, Slack MCP, and OAuth                                                                                                                    | Intercepts Slack Web API operations including channels, messages (including `chat.scheduleMessage`, `chat.scheduledMessages.list`, and `chat.deleteScheduledMessage`), users (including `users.lookupByEmail`), conversations, reactions (including `reactions.get`), pins (`pins.list`), bookmarks (`bookmarks.list`), do-not-disturb (`dnd.info`), modal views (`views.open`, `views.update`), and files (upload, external upload, info, list, delete). `chat.postMessage` accepts Block Kit `blocks` payloads even when fallback `text` is blank or whitespace, matching real Slack — `no_text` is only returned when both `text` and `blocks` are empty. Submitted `blocks` are stored and echoed back from `conversations.history` and `conversations.replies`. Auth methods include `api.test`, `auth.test`, `auth.revoke`, and `auth.teams.list`. Supports `conversations.open` for opening or creating direct-message channels. Completing an external file upload via `files.completeUploadExternal` automatically creates a channel message with the uploaded files attached (including a `file_share` subtype event), matching real Slack behavior. File uploads enforce tier-based size limits (see [tier limits](#slack-twin-tier-limits) below) — all tiers default to a 1 GB cap, and you can switch tiers via the admin API to test tier-specific behavior. The twin also supports [workspace-level constraints](#slack-twin-workspace-constraints) for disabling file uploads entirely, enforcing storage quotas, and simulating rate limits. Uploaded files are downloadable from `/files/{file_id}`. Preserves the `Authorization` header so you can test token-scoped behavior, including `xoxe.`-prefixed enterprise tokens. Enforces OAuth scope requirements on every authenticated API call — tokens missing the required scope for a method receive a `missing_scope` error (see [configurable token scopes](#slack-twin-configurable-token-scopes)). Supports the OAuth 2.0 authorization code grant flow (`/oauth/v2/authorize` and `/api/oauth.v2.access`), allowing you to test Slack "Add to Slack" install flows end-to-end without touching the real Slack OAuth servers. Bot and user token scopes are [configurable](#slack-twin-configurable-token-scopes) via scenario seeding. Also exposes the Slack CLI app-management surface (manifest validate/create/update/export, app status, developer install/uninstall, app delete, connections, hosted package upload placeholders, and hosted environment variables) plus secondary CLI families (activities, auth tickets and token rotation, app approvals, external auth, datastores, workflow triggers, function permissions, collaborators, icons, certified installs, and developer sandboxes) — point the Slack CLI at the twin by setting `SLACK_API_URL` to the twin's `/api/` base. A Slack MCP Streamable HTTP endpoint is available at `/mcp` (JSON-RPC 2.0 `initialize`, `tools/list`, `tools/call`) with OAuth protected resource metadata at `/.well-known/oauth-protected-resource/mcp` and authorization server metadata at `/.well-known/oauth-authorization-server`; the MCP tool surface (`slack_search_messages`, `slack_search_messages_and_files`, `slack_send_message`, `slack_read_channel`, `slack_list_channels`, `slack_list_users`, `slack_create_canvas`, and related Slack-shaped tools) shares state with the Web API surface. |
| [`stripe`](/concepts/twin-reference#stripe)                   | Stripe API (`api.stripe.com`, `files.stripe.com`, `connect.stripe.com`)                                                                                           | Intercepts Stripe API v1 operations including customers, payment methods, payment intents, setup intents, charges, refunds, disputes, subscriptions, invoices, invoice items, credit notes, products, prices, plans, coupons, promotion codes, tax rates, shipping rates, tokens, sources, payouts, balance, balance transactions, billing meters, meter events, meter event summaries, events, files, file links, checkout sessions, payment links, quotes, billing portal sessions, subscription items, subscription schedules, usage records, customer balance transactions, tax IDs, webhook endpoints, mandates, and test clocks. Supports idempotency keys, Stripe-compatible webhook delivery with signed payloads, test card numbers for simulating declines and 3D Secure flows, and browser-facing pages for checkout, a multi-page dashboard (home, payments, subscriptions, invoices, balances), product catalog, and customer management.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |

### Backend twins

| Twin                                                    | What it stands in for                                                                                                                  | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`box`](/concepts/twin-reference#box)                   | Box API (`api.box.com`, `upload.box.com`, `app.box.com`)                                                                               | Intercepts Box v2.0 operations including files, folders, users, search, events, and webhooks. Supports deterministic seeding and OAuth flows.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| [`linear`](/concepts/twin-reference#linear)             | Linear GraphQL API (`api.linear.app`, `linear.app`)                                                                                    | Intercepts the Linear GraphQL endpoint (`POST /graphql`) covering queries and mutations for teams, projects, cycles, issues, labels, comments, workflow states, users, organization, and webhooks. Authenticates personal API keys (raw value in `Authorization`, no `Bearer` prefix) and OAuth 2.0 tokens (`Authorization: Bearer <token>`) issued by `/oauth/authorize`, `/oauth/token`, and `/oauth/revoke`. Maintains `@linear/sdk` wire compatibility: returns `__typename` on every entity, emits relations as `{ id }` in default selections, and surfaces error envelopes whose `extensions.type` matches the lowercase strings the SDK dispatches on (`"authentication error"`, `"invalid input"`, `"ratelimited"`, `"feature not accessible"`). Webhook deliveries include `Linear-Signature` (lowercase-hex HMAC-SHA256), `Linear-Delivery`, `Linear-Event`, and `Linear-Timestamp` headers, with manual flush and replay through `/admin/webhook-events`.                                                                                                                                                                                                                                                                                                                                                                                                                              |
| [`salesforce`](/concepts/twin-reference#salesforce)     | Salesforce Platform REST API (`*.salesforce.com`, `*.force.com`, `*.my.salesforce.com`, `login.salesforce.com`, `test.salesforce.com`) | Intercepts Salesforce REST API operations under `/services/data/v{version}/` including REST discovery (`/services/data`, `/limits`, `/limits/recordCount`), sObject CRUD for Accounts, Contacts, Cases, EmailTemplates, EmailMessages, Users, and related standard objects (`GET`, `POST`, `PATCH`, `DELETE` by ID, plus `describe`, `describe/layouts`, `describe/compactLayouts`, `listviews`, relationship traversal, and updated/deleted feeds), SOQL (`/query`, `/queryAll`, `/query/{locator}`), SOSL (`/search`, `/parameterizedSearch`, `/search/scopeOrder`, `/search/layout`), composite requests (`/composite`, `/composite/batch`, `/composite/graph`, `/composite/tree/{sobject}`), Bulk API v2 job shells (`/jobs/query`, `/jobs/ingest`), invocable actions (`/actions`, `/actions/standard`, `/actions/custom`) for support-style case creation and sending email from templates, and a Tooling API surface for sobjects, queries, and basic discovery. Supports OAuth 2.0 token exchange (`/services/oauth2/token`, `/oauth2/token`), `userinfo`, identity URLs (`/id/{org_id}/{user_id}`), and bearer-token authentication. Admin endpoints (`POST /admin/reset`, `GET /admin/state`, `POST /admin/clock`) provide deterministic seeding and clock control. State starts empty by default — seed accounts, contacts, cases, and templates through scenario seeding or API calls. |
| [`jira`](/concepts/twin-reference#jira)                 | Jira Cloud REST API v3 (`*.atlassian.net`)                                                                                             | Intercepts Jira Cloud REST API v3 operations including issues (create, get, update, delete, bulk create, transitions, changelog, edit metadata), projects, comments, worklogs, attachments, issue links, issue properties, votes, watchers, search and JQL search (`/rest/api/3/search`, `/rest/api/3/search/jql`, `/rest/api/3/search/count`), users (`myself`, search, bulk, assignable, view-issue), components, versions, remote links, filters, dashboards, groups (and group members), fields, priorities, resolutions, statuses, status categories, issue types, server info, attachments metadata, and webhooks (`/rest/api/3/webhook`). Includes Agile (Jira Software) endpoints under `/rest/agile/1.0/` for boards, sprints, board sprints, and backlog issue moves. Routes are also reachable via the `/rest/api/2/` and `/rest/api/latest/` aliases. Comments and descriptions are stored as [Atlassian Document Format (ADF)](https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/) — plain strings sent on input are auto-wrapped in a minimal ADF document. Supports the OAuth 2.0 authorization code grant flow with token issuance, [scope enforcement](#authentication-handling), JQL search, deterministic seeding, and webhook delivery with HMAC-signed payloads.                                                                                    |
| [`waterfall`](/concepts/twin-reference#waterfall)       | Waterfall API (`api.waterfall.io`)                                                                                                     | Intercepts Waterfall API operations for company search, people search, enrichment, verification, and account endpoints. Starts empty by default and uses a UUID-shaped API key for local and sandbox testing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| [`unified`](/concepts/twin-reference#unified)           | Unified API (`api.unified.to`)                                                                                                         | Use this only when your app talks to Unified.to rather than directly to an upstream provider. Seeds integration connections that proxy to Slack, Google Mail, Google Drive, Google Calendar, Box, Notion, and Dropbox. For actual provider data (channels, files, pages, repos, etc.), use the provider-specific twin instead.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| [`unstructured`](/concepts/twin-reference#unstructured) | Unstructured API (`api.unstructuredapp.io`, `platform.unstructuredapp.io`)                                                             | Intercepts Unstructured API operations including document partitioning, workflow management, source and destination CRUD, and job execution. Supports deterministic seeding and API key authentication.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |

Twins and integrations are different:

* Use [integrations](/integrations) to connect context sources that help Arga understand your stack.
* Use digital twins to intercept outbound traffic during sandbox validation.

If you rely on a service not yet supported, [book a demo](https://cal.com/akiratong/30min?overlayCalendar=true) and we'll discuss building a twin for your stack.

## Stub alerting

Not every endpoint in a digital twin has a full stateful implementation. Endpoints that are not yet statefully implemented return **stub responses** — schema-valid mock data generated from the service's API specification. Stub responses are clearly marked so you can distinguish them from real stateful behavior:

* **`X-Twin-Stub` header** — set to `"true"` on every stub response.
* **`_twin_stub` field** — a boolean (`true`) injected into the JSON response body.
* **`_twin_warning` field** — a human-readable string explaining which endpoint is stubbed.

When the response would normally be a JSON array, it is wrapped in an object with `_twin_stub`, `_twin_warning`, and a `data` key containing the original array.

```json theme={null}
{
  "_twin_stub": true,
  "_twin_warning": "This endpoint (GET /repos/{owner}/{repo}/topics) is stubbed and returns mock data. Do not rely on this response in production tests.",
  "data": []
}
```

You can use the `X-Twin-Stub` header to programmatically detect stub responses in your test suite and fail tests that rely on stubbed data.

### Tracking stub hits

The GitHub twin exposes an admin endpoint to audit which stubbed endpoints were called during a session:

```bash theme={null}
GET <admin_url>/admin/stub-hits
```

**Response**

```json theme={null}
{
  "total_hits": 5,
  "unique_endpoints": 2,
  "summary": [
    {"endpoint": "GET /repos/{owner}/{repo}/topics", "hits": 3},
    {"endpoint": "GET /repos/{owner}/{repo}/languages", "hits": 2}
  ],
  "recent": [
    {
      "method": "GET",
      "path_template": "/repos/{owner}/{repo}/topics",
      "actual_path": "/repos/acme/web-app/topics",
      "timestamp": "2026-03-21T12:00:00Z"
    }
  ]
}
```

| Field                | Type      | Description                                                                  |
| -------------------- | --------- | ---------------------------------------------------------------------------- |
| `total_hits`         | `integer` | Total number of stub endpoint calls since the last clear.                    |
| `unique_endpoints`   | `integer` | Number of distinct stubbed endpoints called.                                 |
| `summary`            | `array`   | Deduplicated list of endpoints with hit counts, sorted by most-called first. |
| `summary[].endpoint` | `string`  | HTTP method and path template of the stubbed endpoint.                       |
| `summary[].hits`     | `integer` | Number of times this endpoint was called.                                    |
| `recent`             | `array`   | The 20 most recent stub hits with full details.                              |

To clear the stub hit log:

```bash theme={null}
POST <admin_url>/admin/stub-hits/clear
```

Returns `{"ok": true}` on success.

## How Arga uses digital twins

When Arga spins up a sandbox for a PR, it forks only the services the PR touches and routes all their external API calls through the appropriate digital twin. The rest of your stack stays on your production services. This means:

1. **No real side effects** — A PR that sends a Slack notification or charges a Stripe card won't do either during testing.
2. **Deterministic results** — Tests produce consistent outcomes regardless of external service availability.
3. **Edge case coverage** — Twins can simulate failure modes (timeouts, rate limits, malformed responses) that are hard to trigger against real services.

## Authentication handling

When requests are routed through a digital twin, Arga controls which headers are forwarded to the twin.

For most twins, the `Authorization` header is stripped from proxied requests because the twin doesn't need real credentials — it simulates the service regardless of auth tokens.

The **Slack twin** is an exception. Slack API calls include the `Authorization` header when forwarded to the twin, allowing the twin to validate token-scoped behaviour such as bot-token versus user-token permission differences. This means your sandbox tests exercise the same authentication paths your code uses in production, without touching the real Slack API.

The Slack twin enforces **OAuth scope requirements** on every authenticated API call. Each Slack Web API method requires a specific scope (for example, `chat.postMessage` requires `chat:write`, `conversations.list` requires `channels:read`). If a token does not include the required scope, the twin returns a `missing_scope` error — matching real Slack behaviour:

```json theme={null}
{
  "ok": false,
  "error": "missing_scope",
  "needed": "chat:write",
  "provided": "channels:read,channels:history"
}
```

Tokens with the wildcard scope `*` bypass scope checks and are accepted for any method. You can selectively disable scopes using the `disabled_scopes` config field — any scope in the disabled list is removed from the effective scope set before enforcement, even if the token originally had it.

The Slack twin also supports the full **OAuth 2.0 authorization code grant** flow. When `SLACK_TWIN_BASE_URL` is set, Arga routes OAuth requests (`/oauth/v2/authorize` and `/api/oauth.v2.access`) through the twin so you can test "Add to Slack" install flows, token exchange, and scope negotiation in a sandbox. Issued tokens (`xoxb-` for bots, `xoxp-` for users, and `xoxe.`-prefixed enterprise tokens) are fully functional within the twin and can be used for subsequent API calls like `auth.test` and `search.messages`. The scopes granted to tokens issued via the OAuth flow are determined by the twin's configurable `oauth_bot_scopes` and `oauth_user_scopes` settings (see [configurable token scopes](#slack-twin-configurable-token-scopes) below).

The **GitHub twin** preserves the `Authorization` header and enforces **OAuth scope requirements** on API calls. Each API route requires a specific scope (for example, `POST /repos/{owner}/{repo}/issues` requires `repo`, `GET /user` requires `read:user`). Parent scopes automatically grant their children — `repo` implies `repo:status`, `repo_deployment`, `repo:invite`, `public_repo`, and `security_events`; `admin:repo_hook` implies `write:repo_hook` and `read:repo_hook`; and so on. If a token does not include a required scope, the twin returns a 403 matching GitHub's real API response shape:

```json theme={null}
{
  "message": "Resource not accessible by personal access token",
  "documentation_url": "https://docs.github.com/rest"
}
```

You can configure the default token scopes via the `default_token_scopes` config field. Scopes can also be selectively disabled using the `disabled_scopes` config field — any scope in the disabled list is removed from the effective scope set, even if the token originally had it.

The **Google Drive twin** also enforces **OAuth scope requirements** on every API call. Each Drive API operation requires at least one of a set of accepted scopes (for example, `files.create` requires `drive` or `drive.file` or `drive.appdata`). Parent scopes automatically grant their children — `drive` implies `drive.readonly`, `drive.file`, `drive.appdata`, `drive.metadata`, and `drive.scripts`. If a token lacks any accepted scope for an operation, the twin returns a `403 insufficientPermissions` error matching the real Google Drive API. You can selectively disable scopes using the `disabled_scopes` config field.

The **Notion twin** enforces **capability-based access** on user info endpoints. The twin recognizes three user-information capability levels: `read_user_information_with_email` (full access including email), `read_user_information_no_email` (user info without email), and `no_user_information` (no access). The legacy `read_user_information` capability is treated as equivalent to `read_user_information_with_email`. If a token has no user info capability, user endpoints (`/v1/users`, `/v1/users/me`, `/v1/users/{user_id}`) return a `403 restricted_resource` error. You can selectively disable capabilities using the `disabled_capabilities` config field.

The **Stripe twin** also preserves the `Authorization` header. The twin validates that API keys use a recognized prefix (`sk_test_`, `sk_live_`, `rk_test_`, or `rk_live_`) and returns Stripe-compatible authentication errors for missing or invalid keys. This means your code's Stripe authentication logic runs the same way in the sandbox as it does in production.

The **Jira twin** preserves the `Authorization` header and requires every non-public request to use a `Bearer` token. Requests missing or with a malformed `Authorization` header receive a `401` matching Jira's real API response shape:

```json theme={null}
{
  "errorMessages": ["Client must be authenticated to access this resource."],
  "errors": {}
}
```

The twin enforces **OAuth 2.0 scope requirements** on every API call. Each route requires a specific scope — for example, `POST /rest/api/3/issue` requires `write:jira-work`, `GET /rest/api/3/myself` requires `read:jira-user`, and `POST /rest/api/3/component` requires `manage:jira-project`. Parent scopes automatically grant their children: `write:jira-work` implies `read:jira-work`, `manage:jira-project` implies `read:jira-work`, and `manage:jira-configuration` implies `read:jira-work` and `manage:jira-project`. Tokens that lack a required scope receive a `403` with a missing-scope message:

```json theme={null}
{
  "errorMessages": ["The user does not have permission. Missing scope: write:jira-work"],
  "errors": {}
}
```

The default token scopes are `read:jira-work`, `write:jira-work`, `read:jira-user`, `manage:jira-project`, `manage:jira-webhook`, and `manage:jira-configuration`. Configure these via the `default_token_scopes` config field, or selectively remove scopes via `disabled_scopes` — any scope in the disabled list is removed from the effective scope set even if a token would otherwise grant it. Tokens issued through the OAuth 2.0 flow (`/authorize` and `/oauth/token`) carry the scopes negotiated during authorization.

## Slack twin tier limits

The Slack twin enforces tier-based file upload size limits, letting you test how your application handles free-tier restrictions and paid-tier upgrades. The twin also supports tier-dependent workspace constraints: message history limits, app install limits, and workflow availability.

| Tier            | Default max file size | Message history | Workflows |
| --------------- | --------------------- | --------------- | --------- |
| `free`          | 1 GB                  | 90 days         | Disabled  |
| `pro`           | 1 GB                  | Unlimited       | Enabled   |
| `business_plus` | 1 GB                  | Unlimited       | Enabled   |
| `enterprise`    | 1 GB                  | Unlimited       | Enabled   |
| `paid`          | 1 GB                  | Unlimited       | Enabled   |

When a file upload exceeds the current tier's limit, the twin returns a `file_too_large` error with details about the active tier and cap:

```json theme={null}
{
  "ok": false,
  "error": "file_too_large",
  "tier": "free",
  "max_file_bytes": 1073741824,
  "attempted_bytes": 2048
}
```

This error is returned both when calling `files.getUploadURLExternal` with a `length` that exceeds the cap, and when uploading file content that exceeds the cap during the external upload step.

### Switching tiers

Use the admin API to switch between tiers:

```bash theme={null}
# Get current tier
GET <admin_url>/admin/tier
```

**Response**

```json theme={null}
{
  "tier": "free",
  "max_file_bytes": 1073741824,
  "free_max_file_bytes": 1073741824,
  "paid_max_file_bytes": 1073741824
}
```

```bash theme={null}
# Switch tier
POST <admin_url>/admin/tier
Content-Type: application/json

{"tier": "paid"}
```

**Response**

```json theme={null}
{
  "ok": true,
  "tier": "paid",
  "max_file_bytes": 1073741824
}
```

| Field                 | Type      | Description                                                                                                 |
| --------------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
| `tier`                | `string`  | Current tier: `"free"`, `"pro"`, `"business_plus"`, `"enterprise"`, or `"paid"`.                            |
| `max_file_bytes`      | `integer` | Maximum file size in bytes for the active tier.                                                             |
| `free_max_file_bytes` | `integer` | Maximum file size in bytes for the free tier.                                                               |
| `paid_max_file_bytes` | `integer` | Maximum file size in bytes for the paid tier (applies to `pro`, `business_plus`, `enterprise`, and `paid`). |

## Slack twin workspace constraints

The Slack twin supports workspace-level settings that let you simulate how your application handles disabled file uploads, storage quota limits, and rate limiting. Configure these via [scenario seeding](/features/custom-scenarios#slack-workspace-constraints) or the [admin API](#patch-config-preserve-state).

### File upload toggle

Set `file_uploads_enabled` to `false` to simulate a workspace where an admin has disabled file uploads. Any call to `files.getUploadURLExternal` returns a `file_uploads_disabled` error:

```json theme={null}
{
  "ok": false,
  "error": "file_uploads_disabled"
}
```

File uploads are enabled by default.

### Storage quotas

Set `max_storage_bytes` to enforce a workspace-level storage quota. The twin tracks total storage usage (the sum of `storage_used_bytes` and all uploaded file content) and rejects new uploads when the quota would be exceeded. A call to `files.getUploadURLExternal` with a `length` that would push usage over the quota returns a `storage_limit_reached` error:

```json theme={null}
{
  "ok": false,
  "error": "storage_limit_reached"
}
```

| Field                | Type              | Default           | Description                                                                                                       |
| -------------------- | ----------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------- |
| `max_storage_bytes`  | `integer \| null` | `null` (no limit) | Maximum total storage in bytes for the workspace. Set to `null` to disable the quota.                             |
| `storage_used_bytes` | `integer`         | `0`               | Pre-existing storage usage in bytes. Use this to simulate a nearly-full workspace without uploading actual files. |

For example, setting `max_storage_bytes` to `500` and `storage_used_bytes` to `400` means only 100 bytes of new uploads are allowed before the quota is reached.

### Rate limiting

Set `rate_limiting_enabled` to `true` and provide a `rate_limits` map to simulate per-method rate limiting. When a method exceeds its configured request limit within the time window, the twin returns a `ratelimited` error:

```json theme={null}
{
  "ok": false,
  "error": "ratelimited"
}
```

| Field                                      | Type      | Default | Description                                                   |
| ------------------------------------------ | --------- | ------- | ------------------------------------------------------------- |
| `rate_limiting_enabled`                    | `boolean` | `false` | Whether rate limiting is active.                              |
| `rate_limits`                              | `object`  | `{}`    | Map of method names to rate limit rules.                      |
| `rate_limits.<method>.window_seconds`      | `integer` | —       | Time window in seconds for the rate limit.                    |
| `rate_limits.<method>.max_requests`        | `integer` | —       | Maximum number of requests allowed within the window.         |
| `rate_limits.<method>.retry_after_seconds` | `integer` | —       | Value returned in the `Retry-After` header when rate limited. |

## Slack twin configurable token scopes

You can customize the OAuth scopes granted to bot and user tokens in the Slack twin. This lets you test how your application handles missing permissions — for example, verifying that your app gracefully handles a `missing_scope` error when a required scope is not granted.

<Note>Bot tokens always receive `chat:write` and `files:write` as minimum scopes, even if your seed configuration specifies a narrower set. The twin automatically adds these scopes to any bot token that lacks them. This ensures that bots can always send messages and upload files. To test `missing_scope` errors for `chat:write` or `files:write`, use a **user** token instead.</Note>

### Default scopes

The twin ships with these default scopes:

| Token type                 | Default scopes                                                                                                                                                                                                                                              |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bot (`oauth_bot_scopes`)   | `channels:history`, `channels:manage`, `channels:read`, `chat:write`, `bookmarks:read`, `commands`, `dnd:read`, `files:read`, `files:write`, `pins:read`, `reactions:read`, `reactions:write`, `search:read`, `team:read`, `users:read`, `users:read.email` |
| User (`oauth_user_scopes`) | `search:read`, `channels:read`, `channels:history`, `groups:history`, `im:history`                                                                                                                                                                          |

### Configuring scopes via scenario seeding

Pass `oauth_bot_scopes`, `oauth_user_scopes`, or `tokens` in the Slack twin's seed configuration to override the defaults:

```json theme={null}
{
  "slack": {
    "channels": [{"name": "general"}],
    "oauth_bot_scopes": ["chat:write", "channels:read"],
    "oauth_user_scopes": ["search:read", "channels:read", "channels:history"],
    "tokens": [
      {
        "token": "xoxb-custom-token",
        "user_id": "UTWINBOT",
        "scopes": ["chat:write", "channels:read", "files:write"],
        "is_bot": true
      }
    ]
  }
}
```

| Field               | Type              | Description                                                                                                                                                                                                                                                                                                                                      |
| ------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `oauth_bot_scopes`  | `array of string` | Scopes granted to bot tokens issued via the OAuth flow. Overrides the default bot scope list.                                                                                                                                                                                                                                                    |
| `oauth_user_scopes` | `array of string` | Scopes granted to user tokens issued via the OAuth flow. Overrides the default user scope list.                                                                                                                                                                                                                                                  |
| `tokens`            | `array of object` | Explicit token records to register in the twin. Each token has a `token` string, `user_id`, `scopes` array, and `is_bot` boolean. Use this to create tokens with specific scope combinations for testing permission edge cases. Bot tokens always receive `chat:write` and `files:write` as minimum scopes regardless of the scopes you specify. |

When you configure a narrower set of scopes, any API call requiring a scope not in the list returns the `missing_scope` error described in [authentication handling](#authentication-handling). Note that bot tokens always retain `chat:write` and `files:write` even when you specify a narrower scope list — see the note above.

### Scope requirements by API method

The Slack twin enforces the following scope requirements:

| API method                                                                                                                                                                                                                                                                                       | Required scope                          |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- |
| `chat.postMessage`, `chat.postEphemeral`, `chat.update`, `chat.delete`, `chat.meMessage`, `chat.scheduleMessage`, `chat.scheduledMessages.list`, `chat.deleteScheduledMessage`                                                                                                                   | `chat:write`                            |
| `conversations.create`, `conversations.invite`, `conversations.kick`, `conversations.archive`, `conversations.unarchive`, `conversations.rename`, `conversations.setPurpose`, `conversations.setTopic`, `conversations.leave`, `conversations.open`, `conversations.close`, `conversations.mark` | `channels:manage`                       |
| `conversations.join`                                                                                                                                                                                                                                                                             | `channels:join`                         |
| `conversations.list`, `conversations.info`, `conversations.members`                                                                                                                                                                                                                              | `channels:read`                         |
| `conversations.history`, `conversations.replies`                                                                                                                                                                                                                                                 | `channels:history`                      |
| `files.upload`, `files.getUploadURLExternal`, `files.completeUploadExternal`, `files.delete`, `files.sharedPublicURL`, `files.revokePublicURL`                                                                                                                                                   | `files:write`                           |
| `files.info`, `files.list`                                                                                                                                                                                                                                                                       | `files:read`                            |
| `reactions.add`, `reactions.remove`                                                                                                                                                                                                                                                              | `reactions:write`                       |
| `reactions.get`, `reactions.list`                                                                                                                                                                                                                                                                | `reactions:read`                        |
| `search.messages`, `search.files`, `search.all`                                                                                                                                                                                                                                                  | `search:read`                           |
| `users.info`, `users.list`, `users.identity`, `users.getPresence`                                                                                                                                                                                                                                | `users:read`                            |
| `users.setPresence`, `users.profile.set`                                                                                                                                                                                                                                                         | `users:write`                           |
| `users.profile.get`                                                                                                                                                                                                                                                                              | `users.profile:read`                    |
| `users.lookupByEmail`                                                                                                                                                                                                                                                                            | `users:read.email`                      |
| `team.info`                                                                                                                                                                                                                                                                                      | `team:read`                             |
| `team.accessLogs`                                                                                                                                                                                                                                                                                | `admin`                                 |
| `pins.add`, `pins.remove`                                                                                                                                                                                                                                                                        | `pins:write`                            |
| `pins.list`                                                                                                                                                                                                                                                                                      | `pins:read`                             |
| `bookmarks.add`, `bookmarks.edit`, `bookmarks.remove`                                                                                                                                                                                                                                            | `bookmarks:write`                       |
| `bookmarks.list`                                                                                                                                                                                                                                                                                 | `bookmarks:read`                        |
| `reminders.add`, `reminders.complete`, `reminders.delete`                                                                                                                                                                                                                                        | `reminders:write`                       |
| `reminders.info`, `reminders.list`                                                                                                                                                                                                                                                               | `reminders:read`                        |
| `usergroups.create`, `usergroups.disable`, `usergroups.enable`, `usergroups.update`, `usergroups.users.update`                                                                                                                                                                                   | `usergroups:write`                      |
| `usergroups.list`, `usergroups.users.list`                                                                                                                                                                                                                                                       | `usergroups:read`                       |
| `dnd.setSnooze`, `dnd.endSnooze`, `dnd.endDnd`                                                                                                                                                                                                                                                   | `dnd:write`                             |
| `dnd.info`, `dnd.teamInfo`                                                                                                                                                                                                                                                                       | `dnd:read`                              |
| `emoji.list`                                                                                                                                                                                                                                                                                     | `emoji:read`                            |
| `canvases.create`, `canvases.edit`, `conversations.canvases.create`                                                                                                                                                                                                                              | `canvases:write`                        |
| `views.open`, `views.publish`, `views.push`, `views.update`                                                                                                                                                                                                                                      | `commands`                              |
| `groups.create`, `groups.invite`                                                                                                                                                                                                                                                                 | `groups:write` / `groups:write.invites` |
| `groups.history`, `groups.replies`                                                                                                                                                                                                                                                               | `groups:history`                        |
| `groups.list`, `groups.info`                                                                                                                                                                                                                                                                     | `groups:read`                           |
| `im.open`, `im.close`, `im.mark`                                                                                                                                                                                                                                                                 | `im:write`                              |
| `im.history`, `im.replies`                                                                                                                                                                                                                                                                       | `im:history`                            |
| `im.list`                                                                                                                                                                                                                                                                                        | `im:read`                               |
| `mpim.open`, `mpim.close`, `mpim.mark`                                                                                                                                                                                                                                                           | `mpim:write`                            |
| `mpim.history`, `mpim.replies`                                                                                                                                                                                                                                                                   | `mpim:history`                          |
| `mpim.list`                                                                                                                                                                                                                                                                                      | `mpim:read`                             |

Methods not listed (such as `api.test` and `auth.test`) do not require a specific scope.

## Slack twin admin endpoints

The Slack twin exposes admin endpoints for inspecting and managing twin state during a session.

### Get config

```bash theme={null}
GET <admin_url>/admin/config
```

Returns the current twin configuration, including token registrations, scope settings, tier, and seed data.

**Response**

```json theme={null}
{
  "seed": 1,
  "team_id": "TTWIN0001",
  "team_name": "Default Workspace",
  "team_domain": "slack-twin",
  "tier": "free",
  "tokens": [
    {
      "token": "xoxb-F9SXMECOSFOGYR3XKXWN",
      "user_id": "UTWINBOT",
      "scopes": ["channels:history", "channels:manage", "channels:read", "chat:write", "files:read", "files:write", "reactions:write", "search:read", "team:read", "users:read"],
      "is_bot": true
    }
  ],
  "channels": [],
  "users": [
    {"id": "UTWINBOT", "name": "slack-twin-bot", "real_name": "Slack Twin Bot", "is_bot": true},
    {"id": "UTWINUSR", "name": "slack-twin-user", "real_name": "Slack Twin User", "is_bot": false}
  ]
}
```

### Replace config (full reset)

```bash theme={null}
PUT <admin_url>/admin/config
Content-Type: application/json
```

Replace the entire twin configuration and **reset all store state** (channels, messages, files, etc.). Use this when you need a clean slate.

**Request body**

A full `SlackTwinConfig` object. Any fields you omit revert to their defaults.

**Response**

```json theme={null}
{
  "ok": true,
  "config": { "...full config..." }
}
```

<Warning>This endpoint resets the store. Any channels, messages, or files created during the session are lost. If you only need to update specific config fields (such as token scopes) without losing seeded data, use `PATCH /admin/config` instead.</Warning>

### Patch config (preserve state)

```bash theme={null}
PATCH <admin_url>/admin/config
Content-Type: application/json
```

Update individual config fields **without resetting the store**. Seeded channels, messages, and files remain intact. This is useful when you need to change token scopes or other settings mid-session after data has already been seeded.

**Request body**

A partial JSON object containing only the fields you want to update. Fields you omit keep their current values.

```json theme={null}
{
  "tokens": [
    {
      "token": "xoxb-F9SXMECOSFOGYR3XKXWN",
      "user_id": "UTWINBOT",
      "scopes": ["chat:write", "channels:read"],
      "is_bot": true
    }
  ]
}
```

**Response**

```json theme={null}
{
  "ok": true,
  "config": { "...updated config..." }
}
```

<Tip>Use `PATCH` when you want to restrict token scopes after seeding sample data. For example, seed a workspace with channels and messages, then patch the config to narrow the bot token's scopes and verify your app handles `missing_scope` errors gracefully.</Tip>

### List users

```bash theme={null}
GET <admin_url>/admin/users
```

Returns all users in the twin workspace along with their associated tokens.

**Response**

```json theme={null}
{
  "users": [
    {
      "id": "UTWINBOT",
      "name": "slack-twin-bot",
      "real_name": "Slack Twin Bot",
      "is_bot": true,
      "deleted": false,
      "team_id": "TTWIN",
      "tokens": [
        {
          "token": "xoxb-F9SXMECOSFOGYR3XKXWN",
          "is_bot": true,
          "scopes": ["channels:history", "channels:manage", "channels:read", "chat:write", "files:read", "files:write", "reactions:write", "search:read", "team:read", "users:read"]
        }
      ]
    },
    {
      "id": "UTWINUSR",
      "name": "slack-twin-user",
      "real_name": "Slack Twin User",
      "is_bot": false,
      "deleted": false,
      "team_id": "TTWIN",
      "tokens": [
        {
          "token": "xoxp-slack-twin-user-token",
          "is_bot": false,
          "scopes": ["channels:history", "channels:manage", "channels:read", "chat:write", "files:read", "files:write", "reactions:write", "search:read", "team:read", "users:read"]
        }
      ]
    }
  ]
}
```

| Field                     | Type              | Description                            |
| ------------------------- | ----------------- | -------------------------------------- |
| `users`                   | `array`           | List of user objects in the workspace. |
| `users[].id`              | `string`          | User identifier.                       |
| `users[].name`            | `string`          | Username.                              |
| `users[].real_name`       | `string \| null`  | Display name.                          |
| `users[].is_bot`          | `boolean`         | Whether the user is a bot.             |
| `users[].deleted`         | `boolean`         | Whether the user has been deactivated. |
| `users[].team_id`         | `string`          | Workspace team identifier.             |
| `users[].tokens`          | `array`           | Tokens associated with this user.      |
| `users[].tokens[].token`  | `string`          | The token string.                      |
| `users[].tokens[].is_bot` | `boolean`         | Whether this is a bot token.           |
| `users[].tokens[].scopes` | `array of string` | OAuth scopes granted to this token.    |

### File downloads

Uploaded files are accessible via direct download endpoints:

```bash theme={null}
GET <twin_url>/files/{file_id}
GET <twin_url>/files/{file_id}/download
```

Both endpoints return the file content with the appropriate MIME type and a `Content-Disposition` header for download. Returns `404` if the file does not exist.

## Google Drive twin storage tiers

The Google Drive twin enforces storage quota limits based on a configurable storage tier, letting you test how your application handles quota-exceeded errors.

| Tier      | Storage quota |
| --------- | ------------- |
| `free`    | 15 GB         |
| `basic`   | 100 GB        |
| `premium` | 2 TB          |
| `ai_pro`  | 5 TB          |

When a file upload would exceed the tier's storage quota, the twin returns a `403 storageQuotaExceeded` error matching the real Google Drive API:

```json theme={null}
{
  "error": {
    "code": 403,
    "message": "The user's Drive storage quota has been exceeded.",
    "errors": [
      {
        "domain": "global",
        "reason": "storageQuotaExceeded",
        "message": "The user's Drive storage quota has been exceeded."
      }
    ]
  }
}
```

The `about.get` endpoint reflects the effective storage quota limit in its `storageQuota.limit` field.

### Switching storage tiers

Use the admin API to get or set the storage tier:

```bash theme={null}
# Get current tier
GET <admin_url>/admin/storage-tier
```

**Response**

```json theme={null}
{
  "storage_tier": "free",
  "storage_quota_limit": 15000000000,
  "storage_used_bytes": 1024
}
```

```bash theme={null}
# Switch tier
POST <admin_url>/admin/storage-tier
Content-Type: application/json

{"storage_tier": "premium"}
```

**Response**

```json theme={null}
{
  "storage_tier": "premium",
  "storage_quota_limit": 2000000000000,
  "storage_used_bytes": 1024
}
```

You can also override the quota limit directly via the `storage_quota_limit` config field, which takes precedence over the tier-based default.

## Dropbox twin account tiers

The Dropbox twin enforces storage quota limits based on a configurable account tier.

| Tier           | Storage quota |
| -------------- | ------------- |
| `basic`        | 2 GB          |
| `plus`         | 2 TB          |
| `professional` | 3 TB          |
| `business`     | 5 TB          |

When a file upload would exceed the tier's quota, the twin returns an `insufficient_space` error matching the real Dropbox API:

```json theme={null}
{
  "error_summary": "path/insufficient_space/..",
  "error": {".tag": "path", "reason": {".tag": "insufficient_space"}}
}
```

The `get_space_usage` endpoint reflects the allocated quota based on the active tier.

### Switching account tiers

Use the admin API to get or set the account tier:

```bash theme={null}
# Get current tier
GET <admin_url>/admin/account-tier
```

**Response**

```json theme={null}
{
  "connection_id": "...",
  "account_tier": "basic",
  "used_bytes": 0,
  "allocated_bytes": 2000000000,
  "available_bytes": 2000000000
}
```

```bash theme={null}
# Switch tier
POST <admin_url>/admin/account-tier
Content-Type: application/json

{"tier": "plus"}
```

**Response**

```json theme={null}
{
  "connection_id": "...",
  "account_tier": "plus",
  "used_bytes": 0,
  "allocated_bytes": 2000000000000,
  "available_bytes": 2000000000000
}
```

## Notion twin workspace plans

The Notion twin enforces workspace plan-based limits, letting you test how your application handles different plan tiers.

| Plan         | Max file upload | Max guests |
| ------------ | --------------- | ---------- |
| `free`       | 5 MB            | 10         |
| `plus`       | 5 GB            | 100        |
| `business`   | 5 GB            | 250        |
| `enterprise` | 5 GB            | Unlimited  |

When a file upload exceeds the plan's size limit, the twin returns a validation error. The twin also supports the `disabled_capabilities` config field for selectively disabling API capabilities.

### Switching workspace plans

Use the admin API to get or set the workspace plan:

```bash theme={null}
# Get current plan
GET <admin_url>/admin/workspace-plan
```

**Response**

```json theme={null}
{
  "workspace_plan": "free",
  "limits": {"max_file_upload_bytes": 5242880, "max_guests": 10}
}
```

```bash theme={null}
# Switch plan
POST <admin_url>/admin/workspace-plan
Content-Type: application/json

{"workspace_plan": "business"}
```

**Response**

```json theme={null}
{
  "ok": true,
  "workspace_plan": "business",
  "limits": {"max_file_upload_bytes": 5368709120, "max_guests": 250}
}
```

## Discord twin boost levels

The Discord twin supports configurable server boost levels that control resource limits.

| Boost level | Max file upload | Max emoji slots |
| ----------- | --------------- | --------------- |
| `0`         | 25 MB           | 50              |
| `1`         | 25 MB           | 100             |
| `2`         | 50 MB           | 150             |
| `3`         | 100 MB          | 250             |

Configure the boost level via the `guild_boost_level` config field. The `max_file_upload_bytes` and `max_emoji_slots` fields can also be set independently to override the boost-level defaults.

## Slack twin conversations.open

The Slack twin supports the `conversations.open` API method for opening or creating direct-message channels.

```bash theme={null}
POST <twin_url>/api/conversations.open
```

**Request body**

| Field     | Type     | Required    | Description                                                                                                                                                               |
| --------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `users`   | `string` | Conditional | Comma-separated list of user IDs to include in the DM. Required when `channel` is not provided. The authenticated user is automatically added if not already in the list. |
| `channel` | `string` | Conditional | Channel ID of an existing DM to reopen. When provided, `users` is ignored.                                                                                                |

**Response (new DM)**

```json theme={null}
{
  "ok": true,
  "channel": {
    "id": "G0000000001",
    "name": "dm-UTWINBOT_UTWINUSR",
    "is_private": true,
    "members": ["UTWINBOT", "UTWINUSR"]
  },
  "already_open": false,
  "no_op": false
}
```

**Response (existing DM)**

```json theme={null}
{
  "ok": true,
  "channel": {
    "id": "G0000000001",
    "name": "dm-UTWINBOT_UTWINUSR",
    "is_private": true,
    "members": ["UTWINBOT", "UTWINUSR"]
  },
  "already_open": true,
  "no_op": true
}
```

| Field          | Type      | Description                           |
| -------------- | --------- | ------------------------------------- |
| `channel`      | `object`  | The opened or created channel object. |
| `already_open` | `boolean` | `true` if the DM already existed.     |
| `no_op`        | `boolean` | `true` if no new channel was created. |
