Who this is for: Developers tuning SDK flush intervals, DevOps engineers planning capacity, and architects designing high-throughput ingestion pipelines.

1. Overview

The SWT3 API uses a token bucket rate limiter. Each tenant has a bucket that refills at a fixed rate (determined by subscription tier). Requests consume tokens. When the bucket is empty, requests receive HTTP 429 until tokens refill.

Key properties:

2. Tier Limits

TierRate (req/s/instance)Effective (2 instances)MonthlyPrice
OPEN10~20100 anchorsFree
PRO50~100Unlimited$499/mo
ENCLAVE200~400Unlimited$9,500/mo
SOVEREIGN500~1,000UnlimitedContact us

The tier is resolved from your API key's tenant record. Tier lookups are cached for 60 seconds to avoid database overhead on every request.

3. Monthly Anchor Quota

OPEN tier tenants are limited to 100 anchors per calendar month. The counter resets on the 1st of each month at 00:00 UTC.

Upgrading: Tier changes via Stripe take effect instantly. The moment your tenant row updates to PRO, the monthly limit is removed and your per-second rate increases to 50.

4. Public Endpoint Limits

Public endpoints (no authentication required) are rate-limited per IP address:

EndpointLimitWindow
GET /api/v1/verify/public60 requestsPer minute
POST /api/v1/passport/verify10 requestsPer minute
GET /api/v1/passport/status/:id60 requestsPer minute

These limits are generous for typical verification workloads. If you need bulk verification, use the tenant-scoped /api/v1/attest/verify?enclave=true endpoint which verifies all anchors in a single request.

5. How Token Bucket Works

The token bucket algorithm works like this:

  1. Your bucket starts full (capacity = your tier's rate, e.g., 50 for PRO).
  2. Each request costs 1 token (batch requests cost 1 token regardless of batch size).
  3. Tokens refill continuously at your tier's rate (e.g., 50 tokens per second for PRO).
  4. If the bucket has enough tokens, the request proceeds. If not, it returns 429.
  5. The Retry-After header tells you how long until enough tokens refill.

Burst capacity: Your bucket capacity equals your rate. A PRO tenant can send 50 requests in an instant burst, then must wait for refill. This is ideal for SDK flush cycles that send buffered anchors in a batch.

6. Handling 429 Responses

When rate limited, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 2

{ "error": "Rate limit exceeded. Retry after 2s.", "retry_after_seconds": 2 }

Implement exponential backoff with the Retry-After value as the base:

PYTHON
TYPESCRIPT
import time, requests

def witness_with_retry(payload, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            "https://sovereign.tenova.io/api/v1/witness",
            json=payload,
            headers={"Authorization": f"Bearer {API_KEY}"}
        )
        if resp.status_code != 429:
            return resp

        retry_after = int(resp.headers.get("Retry-After", 1))
        wait = retry_after * (2 ** attempt)  # exponential backoff
        time.sleep(min(wait, 30))            # cap at 30 seconds

    return resp  # final attempt result
async function witnessWithRetry(payload: object, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const resp = await fetch("https://sovereign.tenova.io/api/v1/witness", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify(payload)
    });

    if (resp.status !== 429) return resp;

    const retryAfter = parseInt(resp.headers.get("Retry-After") ?? "1");
    const wait = Math.min(retryAfter * Math.pow(2, attempt), 30);
    await new Promise(r => setTimeout(r, wait * 1000));
  }
}
SDK handles this automatically: If you use the Python or TypeScript SDK (recommended), rate limit retries are handled by the built-in dead-letter queue. You do not need to implement retry logic yourself.

7. Optimization Strategies

Use the Batch Endpoint

POST /api/v1/witness/batch accepts up to 500 payloads per request and counts as a single request against your rate limit. This is the highest-leverage optimization.

Increase SDK Flush Interval

The SDK buffers anchors and sends them in batches. A larger flush_interval means more anchors per batch, fewer HTTP requests:

# Default: flush every 30 seconds
witness = Witness(flush_interval=30)

# High-throughput: flush every 60 seconds (more anchors per batch)
witness = Witness(flush_interval=60)

Distribute Across Keys

Rate limits are per-tenant (not per-key). Multiple API keys under the same tenant share the same bucket. To increase throughput, upgrade your tier.

8. Capacity Planning

227 anchors/sec
Benchmarked throughput = 19.6 million anchors per day. 400x current demand headroom.
TierMax Anchors/DayTypical Use Case
OPEN~100 (monthly limit)Evaluation, proof of concept
PRO~4.3MSingle AI system, moderate volume
ENCLAVE~17.3MMultiple AI systems, enterprise volume
SOVEREIGN~43.2MFleet-scale, real-time inference witnessing

These are per-second rate limits extrapolated to 24 hours. Actual throughput depends on payload size, network latency, and batch utilization.

9. Monitoring

SDK-Level

API-Level

Dashboard-Level

See also: API Reference -- Rate Limits | Error Codes Reference | Troubleshooting FAQ -- API