<!-- Generated by `just docs` from proto/automaton/v1/execution.proto, catalog/toolkits. Edit the source, not this file. -->

# Limits

Several things bound a call. Some are yours, written in the policy document; the rest come from the app you are calling. All of them are refusals rather than errors: the call comes back as a normal answer with a code on it, nothing was half done, and the refusal is recorded like any other outcome.

| Limit | Code | Set by | When it fires |
| --- | --- | --- | --- |
| Velocity limit | `velocity_exceeded` | You, in the policy document | A token bucket you wrote is empty. Buckets are per project, per toolkit, or per tool, and every applicable one is tested before any token is spent. |
| Approval gate | `approval_pending` | You, in the policy document | The call matches a rule that says a person releases it. The call is parked, not failed. |
| Spend ceiling | `budget_exhausted` | You, in the policy document | The project or the entity has spent its budget for the current window. |
| Resource lease | `resource_leased` | atmon | Another caller holds the resource this tool declares, so two callers cannot write the same thing at once. |
| Provider budget | `rate_limited` | The external app | The provider's own declared request budget for this project and toolkit is spent. The table below lists the budgets that are declared. |
| Provider incident | `provider_unavailable` | The external app | The provider is in a known incident, so calls to it are refused rather than sent into a failure. |

## What to do about each

| Code | What to do |
| --- | --- |
| `velocity_exceeded` | Retry once the window refills. The detail names the wait in seconds. Nothing was sent and no credential was resolved. |
| `approval_pending` | Retry with the `approval_id` once a person approves it in the console inbox. An approval that nobody answers expires rather than running late. |
| `budget_exhausted` | The detail names the instant the window resets. Raise the ceiling or wait for it. |
| `resource_leased` | Retry. The detail names the holder and when the lease expires. |
| `rate_limited` | Retry after the wait the detail names. atmon never sleeps and never queues on your behalf, so your own timeout budget stays yours. |
| `provider_unavailable` | Retry once the incident closes; the detail names it. |

Every code, including the ones that are not limits, is in [Error codes](./errors.md).

## Declared provider budgets

A toolkit may declare the request budget the external app publishes, and atmon paces against it with one bucket per project and toolkit. A connector that declares none is not unlimited: it is one where we have not written the number down, and a call that exceeds the provider's own limit comes back as `rate_limited` from the provider instead.

| Toolkit | Budget | Counted per |
| --- | --- | --- |
| [Airtable](./toolkits/airtable.md) | 5 requests per 1s | `account` |
| [Box](./toolkits/box.md) | 1000 requests per 1m | `account` |
| [ClickUp](./toolkits/clickup.md) | 100 requests per 1m | `account` |
| [GitHub](./toolkits/github.md) | 5000 requests per 1h | `account` |
| [GitLab](./toolkits/gitlab.md) | 2000 requests per 1m | `account` |
| [Google Sheets](./toolkits/google_sheets.md) | 60 requests per 1m | `account` |
| [QuickBooks](./toolkits/quickbooks.md) | 500 requests per 1m | `account` |
| [Shopify](./toolkits/shopify.md) | 40 requests per 20s | `account` |
| [Slack](./toolkits/slack.md) | 50 requests per 1m | `account` |
| [Stripe](./toolkits/stripe.md) | 100 requests per 1s | `account` |
| [Webflow](./toolkits/webflow.md) | 60 requests per 1m | `account` |
| [Xero](./toolkits/xero.md) | 60 requests per 1m | `account` |

Toolkits not listed here declare no budget. Every connector, listed or not, is in the [app reference](./toolkits/index.md).

## Sizes and shapes

Two limits are not refusals and are worth knowing before you meet them.

- A ranked slate from a search is at most eight tools. Asking for more returns eight.
- A tool result is shaped to the tool's output schema before you see it, so a provider answering with a large document does not arrive in your context whole.
