Skip to content

Rate Limits & Quotas

The Tessellate Renewables API enforces rate limits and monthly quotas to ensure fair usage and service stability.

Subscription Tiers

Tier Monthly Requests Rate Limit Price
Free 100 10/min $0
Starter 5,000 60/min $99 (one-time)
Pro 50,000 300/min $499/year
Enterprise Unlimited 1000/min $1,499/year

Rate Limits

Rate limits are enforced per API key using a sliding window algorithm.

How It Works

  • Window: 60 seconds (sliding)
  • Limit: Based on your tier
  • Scope: Per API key

Response Headers

Every API response includes rate limit headers:

HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 12
Header Description
X-RateLimit-Limit Maximum requests per minute
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Seconds until window resets

Rate Limit Exceeded (429)

When you exceed the rate limit:

{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Maximum 60 requests per minute.",
  "retry_after": 12,
  "limit": 60,
  "window_seconds": 60
}

Best Practice: Implement exponential backoff:

import time
import requests

def make_request_with_retry(url, headers, data, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(url, headers=headers, json=data)

        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 5))
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")

Monthly Quotas

Monthly quotas reset on the 1st of each month at 00:00 UTC.

Response Headers

X-Quota-Limit: 5000
X-Quota-Used: 127
X-Quota-Remaining: 4873
Header Description
X-Quota-Limit Monthly request limit
X-Quota-Used Requests used this month
X-Quota-Remaining Requests remaining this month

Quota Exceeded (402)

When you exceed your monthly quota:

{
  "error": "quota_exceeded",
  "message": "Monthly quota exceeded. 5000/5000 requests used.",
  "current_usage": 5000,
  "limit": 5000,
  "tier": "STARTER",
  "upgrade_url": "/billing/pricing"
}

Note: Status code 402 (Payment Required) indicates you need to upgrade.

Checking Usage

Via API

curl "https://api.tessellaterenewables.com/metering/usage?api_key_id=YOUR_KEY_ID&tier=STARTER"

Response:

{
  "rate_limit": {
    "requests_in_window": 5,
    "window_seconds": 60,
    "limit_per_minute": 60,
    "remaining": 55,
    "tier": "STARTER"
  },
  "quota": {
    "requests_this_month": 127,
    "monthly_limit": 5000,
    "remaining": 4873,
    "percent_used": 2.54,
    "tier": "STARTER",
    "period_start": "2026-01-01T00:00:00Z",
    "period_end": "2026-02-01T00:00:00Z"
  },
  "summary": {
    "total_requests": 127,
    "successful_requests": 125,
    "failed_requests": 2,
    "avg_response_time_ms": 1250.5,
    "success_rate": 0.984
  }
}

Via Dashboard

  1. Log in to tessellaterenewables.com
  2. Navigate to SettingsAPI Usage
  3. View real-time usage metrics and history

Metered Endpoints

The following endpoints count against your quota:

Endpoint Description
POST /solar/optimization/quick Quick optimization
POST /solar/optimization/run Full optimization job
POST /solar/optimization/multi Multi-objective optimization
GET /solar/optimization/{job_id} Get job results
POST /solar/resource Solar resource data
POST /solar/predict Energy prediction
POST /solar/assess Site assessment
POST /solar/report Generate report

Non-Metered Endpoints

These endpoints do not count against your quota:

  • GET /solar/health - Health check
  • GET /metering/* - Usage endpoints
  • GET /billing/* - Billing endpoints
  • GET /auth/* - Authentication endpoints

Handling Limits in Code

Python Example

import os
import time
import requests

class TessellateClient:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://api.tessellaterenewables.com"

    def _request(self, method, path, **kwargs):
        url = f"{self.base_url}{path}"
        headers = kwargs.pop('headers', {})
        headers['X-API-Key'] = self.api_key

        response = requests.request(method, url, headers=headers, **kwargs)

        # Log rate limit info
        limit = response.headers.get('X-RateLimit-Limit')
        remaining = response.headers.get('X-RateLimit-Remaining')
        if limit:
            print(f"Rate limit: {remaining}/{limit}")

        # Handle rate limiting
        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 5))
            print(f"Rate limited. Waiting {retry_after}s...")
            time.sleep(retry_after)
            return self._request(method, path, **kwargs)

        # Handle quota exceeded
        if response.status_code == 402:
            raise Exception("Monthly quota exceeded. Please upgrade your plan.")

        response.raise_for_status()
        return response.json()

    def optimize(self, site, objective='energy'):
        return self._request('POST', '/solar/optimization/quick', json={
            'site': site,
            'objective': objective
        })

JavaScript Example

class TessellateClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.tessellaterenewables.com';
  }

  async request(method, path, body = null) {
    const response = await fetch(`${this.baseUrl}${path}`, {
      method,
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': this.apiKey
      },
      body: body ? JSON.stringify(body) : null
    });

    // Handle rate limiting
    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After') || '5');
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      return this.request(method, path, body);
    }

    // Handle quota exceeded
    if (response.status === 402) {
      throw new Error('Monthly quota exceeded. Please upgrade your plan.');
    }

    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }

    return response.json();
  }
}

Upgrading Your Plan

When you approach or exceed your limits:

  1. Go to SettingsBilling in the dashboard
  2. Click Upgrade Plan
  3. Select a higher tier
  4. Complete payment via Stripe

Or upgrade via API:

curl -X POST https://api.tessellaterenewables.com/billing/create-checkout-session \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tier": "PRO"}'

Tips for Staying Within Limits

  1. Cache results - Don't re-fetch data that hasn't changed
  2. Batch operations - Use multi-objective optimization instead of multiple single runs
  3. Poll efficiently - Use reasonable intervals when checking job status
  4. Monitor usage - Set up alerts before hitting limits

Enterprise Options

For high-volume usage, contact us for:

  • Custom rate limits
  • Dedicated infrastructure
  • SLA guarantees
  • Volume discounts

Email: [email protected]