Rate Limiting & Performance

Rate limiting & Performance

To ensure the stability and reliability of the API for everyone, we enforce the following limits:

  • Frequency: You are allowed to make 2 API calls per second, counted per HTTP request. Sending several operations in the same request counts as a single call, so you can send multiple queries in the same request to help with the limit.
  • Mutations per request: A single request can contain at most 10 mutations. This applies to the total number of mutations across all operations in the request, including aliased and batched operations. Queries are not subject to this limit.
  • Timeout: There is a strict 30-second execution timeout. Any request taking longer than 30 seconds to process will be terminated with an error.

Error codes

When a limit is exceeded, the API returns an error with a specific code in the extensions field:

HTTP statusCodeMeaning
429RATE_LIMITEDToo many HTTP requests within the allowed frequency. Includes a retryAfter extension and a Retry-After response header.
400MUTATION_LIMIT_EXCEEDEDMore than 10 mutations were sent in a single request. Includes maxMutations and mutationCount extensions.

Optimization & Fair Use

To prevent timeouts, you must optimize your queries to fetch only the necessary data.

  • Filter by date: Use filters like UPDATED_AT or CREATED_AT to limit the scope.
  • Limit nesting: Avoid requesting deeply nested associations on large lists without pagination.

⚠️ Important:
Resource Usage Policy

Broad, unoptimized queries (e.g., fetching full history without filters) consume excessive server resources. We reserve the right to suspend API access if we detect patterns of abuse or consistently inefficient querying.

Query Optimization Examples

Here is a comparison between a risky query and an optimized one. The key difference lies in the use of date filters in the where argument.

✅ Optimized Query (Good)

This query is fast because it uses a highly selective filter, especially on dates (UPDATED_AT or CREATED_AT), ensuring that the API only processes recent data.

query OptimizedInvoices {
  Invoices(
    where: {
      AND: [
        {
          column: STATUS,
          operator: EQ,
          value: paid
        },
        {
          OR: [
            {
              column: UPDATED_AT,
              operator: GTE,
              value: "2025-12-01 00:00:00" # Filtering by a recent date is key
            },
            {
              column: CREATED_AT,
              operator: GTE,
              value: "2025-12-01 00:00:00"
            }
          ]
        }
      ]
    }
  ) {
    data {
      id
      label
    }
  }
}

✅ Unoptimized Query (Risk of Timeout)

This query is greedy: by omitting all date filters in the where argument, it forces the system to process potentially all historical records to find a match, leading to resource exhaustion and hitting the 30-second timeout.

query UnoptimizedInvoices {
  Invoices(
    where: { # Missing date constraints here
      OR: [
        {
          column: LABEL,
          operator: LIKE,
          value: "I0%"
        }
      ]
      # Without date constraints, this query might scan millions of records.
    }
  ) {
    data {
      id
      label
      # ... plus potentially deeply nested fields on large lists
    }
  }
}