Skip to content

Rate Limits

Glyph implements rate limiting to ensure fair usage and maintain service quality. This guide explains how rate limits work and how to handle them in your application.

Rate limits are based on your subscription tier:

TierRequests/MinuteMonthly PDFsPrice
Free550$0
Starter20500$29/mo
Pro605,000$99/mo
Business20025,000$299/mo
EnterpriseCustomUnlimitedContact us

Applies to all API endpoints. Resets every 60 seconds.

Applies only to /v1/generate endpoint. Resets on the 1st of each month.

Every API response includes rate limit headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705320060
HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the limit resets

For the generate endpoint, additional headers show monthly usage:

X-Monthly-Limit: 1000
X-Monthly-Used: 150
X-Monthly-Remaining: 850

HTTP Status: 429 Too Many Requests

{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 45,
"tier": "free",
"limit": 10,
"windowMs": 60000
}

The Retry-After header indicates seconds until you can retry:

Retry-After: 45

HTTP Status: 429 Too Many Requests

{
"error": "Monthly PDF limit exceeded",
"code": "MONTHLY_LIMIT_EXCEEDED",
"limit": 100,
"used": 100,
"tier": "free",
"upgrade": "https://glyph.you/pricing"
}
async function callGlyphAPI(endpoint, data, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(`https://api.glyph.you${endpoint}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Retrying in ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response.json();
}
throw new Error('Max retries exceeded');
}
import time
import requests
from requests.exceptions import HTTPError
def call_glyph_api(endpoint, data, max_retries=3):
for i in range(max_retries):
response = requests.post(
f'https://api.glyph.you{endpoint}',
headers={
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
},
json=data
)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f'Rate limited. Retrying in {retry_after} seconds...')
time.sleep(retry_after)
continue
response.raise_for_status()
return response.json()
raise Exception('Max retries exceeded')

Track the rate limit headers in your application:

function logRateLimits(response) {
console.log({
limit: response.headers.get('X-RateLimit-Limit'),
remaining: response.headers.get('X-RateLimit-Remaining'),
reset: new Date(response.headers.get('X-RateLimit-Reset') * 1000)
});
}

For high-volume applications, queue requests to stay within limits:

class RateLimitedQueue {
constructor(requestsPerMinute) {
this.interval = 60000 / requestsPerMinute;
this.queue = [];
this.processing = false;
}
async add(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
const { fn, resolve, reject } = this.queue.shift();
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
setTimeout(() => {
this.processing = false;
this.process();
}, this.interval);
}
}
// Usage
const queue = new RateLimitedQueue(60); // 60 requests per minute
await queue.add(() => glyphApi.preview(template, data));

Cache preview responses to avoid redundant API calls:

const previewCache = new Map();
async function getPreview(template, data) {
const cacheKey = `${template}-${JSON.stringify(data)}`;
if (previewCache.has(cacheKey)) {
return previewCache.get(cacheKey);
}
const result = await glyphApi.preview(template, data);
previewCache.set(cacheKey, result);
return result;
}

If modifying multiple documents, space out requests:

async function batchModify(sessions, modifications) {
const results = [];
for (const [sessionId, prompt] of Object.entries(modifications)) {
const result = await glyphApi.modify(sessionId, prompt);
results.push(result);
// Wait 1 second between requests to stay well under limit
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}

If you’re consistently hitting rate limits, consider upgrading:

  1. Go to glyph.you/dashboard
  2. Navigate to Billing
  3. Select a higher tier
  4. Your new limits apply immediately
  • Check your current usage in the dashboard
  • Contact support@glyph.you for rate limit increases
  • Enterprise customers: Contact your account manager