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:

  1. Each render is logged with status, cache_hit, and your tier
  2. Daily at 02:00 UTC, billable renders (200 + cache-miss + payg) are aggregated
  3. A usage record is sent to your Lemon Squeezy subscription
  4. 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 month
  • billed_renders = max(0, renders - quota) if tier is payg
  • 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

  1. Use caching aggressively. The same OG image is cached for 1 year; cache hits cost nothing.
  2. Batch requests if possible. Avoid hammering the same URL multiple times in rapid succession; wait for the first response to cache.
  3. Check usage regularly. Call GET /v1/usage once a day or weekly to track consumption.
  4. Monitor rate limits. Respect the Retry-After header; implement exponential backoff for transient failures.
  5. Rotate keys periodically. Use POST /v1/keys to rotate credentials every few months.
  6. 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 computes billed = (status=200 AND NOT cache_hit AND tier='payg')
  • Only rows with billed=true are sent to Lemon Squeezy as usage records
  • You can audit your usage logs in your dashboard

Questions?

See Error Codes for 402, 401, and other status codes. See Quickstart for signing examples.