Pricing & Billing
Free tier: 500 renders/month, no cost, never billed. Pay-as-you-go: $0.003 per render above the free limit, no monthly minimum.
A render is billable only when:
- HTTP status is 200 (success)
- AND cache is MISS (not served from cache)
- AND tier is payg (upgrade from free)
Failures (4xx/5xx) are never billed. Cache hits are never billed. This is not an exception — it's the rule.
Free Tier
You get 500 renders per calendar month for free, with no credit card required. Usage is tracked automatically; when you exceed 500, the API returns 402 quota_exceeded and you can upgrade or wait until next month.
Free tier renders:
- Are rate-limited at 60 requests/minute per IP address
- Count against your quota only if they succeed (
status=200) and are not cache hits - Never incur a charge
Upgrade at any time in your dashboard.
Pay-As-You-Go (PAYG)
After 500 renders per month, every additional render costs $0.003.
Monthly cost example:
- 500 renders: $0 (free tier)
- 1,000 renders: $0 + (500 × $0.003) = $1.50
- 10,000 renders: $0 + (9,500 × $0.003) = $28.50
- 50,000 renders: $0 + (49,500 × $0.003) = $148.50
Billing happens automatically:
- Each render is logged with
status,cache_hit, and your tier - Daily at 02:00 UTC, billable renders (200 + cache-miss + payg) are aggregated
- A usage record is sent to your Lemon Squeezy subscription
- You're billed at the end of your billing period (usually monthly)
There is no setup fee, no monthly minimum, and no charge for failures or cache hits.
Quota & Rate Limiting
Free Tier Rate Limit
60 requests per minute per IP address (for public /og endpoints) or per API key (for /v1/*).
If exceeded, the API returns 429 rate_limited:
{
"error": { "code": "rate_limited", "message": "60 requests per minute exceeded" },
"headers": { "Retry-After": "30" }
}
Wait the number of seconds in Retry-After, then retry.
PAYG Tier Rate Limit
600 requests per minute per API key. Same Retry-After behavior.
Free Tier Quota
500 successful, non-cached renders per calendar month. Once exceeded, the API returns 402 quota_exceeded:
{
"error": { "code": "quota_exceeded", "message": "Free tier quota of 500 renders/month exceeded" }
}
Upgrade to PAYG in your dashboard, or wait until the 1st of next month for the quota to reset.
Usage Endpoint
Check your current month's usage with your API key.
GET /v1/usage
Request:
curl -H "Authorization: Bearer sk_live_..." https://api.renderog.app/v1/usage
Response (200 OK):
{
"month": "2026-07",
"renders": 1240,
"quota": 500,
"tier": "payg",
"billed_renders": 740
}
| Field | Type | Notes |
|---|---|---|
month |
string | YYYY-MM format, current calendar month |
renders |
int | Total successful, non-cached renders this month |
quota |
int | Your free quota (usually 500, 0 if no free tier) |
tier |
string | free, payg, or flat |
billed_renders |
int | Renders above quota that incurred a charge |
Calculation:
renders= count of (status 200 + cache miss) this monthbilled_renders= max(0, renders - quota) if tier ispayg- Cost this month =
billed_renders × $0.003
API Key Management
Create, rotate, and revoke API keys from your dashboard or via the POST /v1/keys endpoint.
POST /v1/keys
Rotate your key (create a new one, keep the old one active for 24 hours):
curl -X POST \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "action": "rotate" }' \
https://api.renderog.app/v1/keys
Response (200 OK):
{
"key": "sk_live_a1b2c3d4e5f6...",
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2026-07-22T10:00:00Z",
"message": "New key created. Old key remains active for 24 hours. Store the new key securely."
}
The full key is shown exactly once. Store it immediately; you won't see it again. Only the hash is stored server-side.
Revoke a key (immediately stop accepting it):
curl -X POST \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "action": "revoke", "key_id": "550e8400-e29b-41d4-a716-446655440000" }' \
https://api.renderog.app/v1/keys
Response (200 OK):
{
"message": "Key revoked"
}
Revoked keys are immediately invalid. Requests with revoked keys return 401 invalid_key.
Billing Examples
Example 1: Free Tier (Under Quota)
Scenario: Free tier account, 350 renders in July.
| Field | Value |
|---|---|
renders |
350 |
quota |
500 |
tier |
free |
billed_renders |
0 |
| Cost | $0 |
Example 2: Free Tier (Over Quota)
Scenario: Free tier account, 600 renders in July.
Requesting GET /v1/usage at 550 renders returns 402 quota_exceeded. After upgrade to PAYG:
| Field | Value |
|---|---|
renders |
600 |
quota |
500 |
tier |
payg |
billed_renders |
100 |
| Cost | $0.30 (100 × $0.003) |
Example 3: PAYG Tier (High Volume)
Scenario: PAYG account, 25,000 renders in July.
| Field | Value |
|---|---|
renders |
25,000 |
quota |
500 |
tier |
payg |
billed_renders |
24,500 |
| Cost | $73.50 (24,500 × $0.003) |
Example 4: Cache Hits Not Billed
Scenario: PAYG account, 1,000 total requests in July.
- 600 unique renders (cache miss) → billed
- 400 requests for same URLs (cache hit) → not billed
| Field | Value |
|---|---|
renders |
600 (cache misses only) |
quota |
500 |
tier |
payg |
billed_renders |
100 |
| Cost | $0.30 |
Cache hits are served from Cloudflare's edge in under 5ms and cost nothing.
Example 5: Failures Not Billed
Scenario: PAYG account, 100 requests total.
- 80 successful (200) → billed (if cache miss and over quota)
- 15 bad params (400) → not billed
- 5 rate limit (429) → not billed
Only the 80 successful renders count toward quota and billing.
Best Practices
- Use caching aggressively. The same OG image is cached for 1 year; cache hits cost nothing.
- Batch requests if possible. Avoid hammering the same URL multiple times in rapid succession; wait for the first response to cache.
- Check usage regularly. Call
GET /v1/usageonce a day or weekly to track consumption. - Monitor rate limits. Respect the
Retry-Afterheader; implement exponential backoff for transient failures. - Rotate keys periodically. Use
POST /v1/keysto rotate credentials every few months. - Keep your SIGNING_SECRET secret. Never expose it in client-side code; always sign URLs on the server.
Billing Transparency
Never bill failed renders or cache hits. This is a core promise and cannot change without explicit notice and opt-in. Here's how it's enforced:
- Every request is logged with
status,cache_hit, and the user's tier - A SQL function (
log_and_check_quota) atomically computesbilled = (status=200 AND NOT cache_hit AND tier='payg') - Only rows with
billed=trueare sent to Lemon Squeezy as usage records - You can audit your usage logs in your dashboard
Questions?
- Email: support@renderog.app
- Status: status.renderog.app
- GitHub issues: fgandolfo/renderog/issues
See Error Codes for 402, 401, and other status codes. See Quickstart for signing examples.