revoked_key

revoked_key means the API key in the request was valid once, but someone on your account revoked it. A revoked key stops working at once and cannot be restored. Replace it with an active key; retries with the old key fail forever.

Field Value
HTTP status 401 Unauthorized
error.type authentication_error
error.code revoked_key
retryable false
Credit used No

The error code reference lists all authentication codes.

Example response

{
  "error": {
    "type": "authentication_error",
    "code": "revoked_key",
    "message": "API key has been revoked",
    "retryable": false,
    "docs": "https://docs.renderscreenshot.com/errors/revoked_key"
  },
  "request_id": "req_4fa9e0c3b7d21e86"
}

A revoked key can also be reported as missing_credentials. Both mean "this key does not work", so handle them with one rule: stop, and fix the configuration.

Find which key was revoked

Open API Keys in the dashboard. For each key, the list shows:

  • the prefix and the last four characters, for example rs_live_********************a1B9;
  • Last Used, the time of the last accepted request;
  • a Revoked badge with the time of revocation, for example "Revoked 2 hours ago".

Compare the last four characters with the key your app uses. To print them without exposing the key, run node -e "console.log(process.env.RS_API_KEY.slice(-4))" in the failing environment. If the revocation time matches the moment your errors started, you have found the cause. If nobody on the team revoked it on purpose, treat it as a possible leak, and check where the key was stored.

Replace a key without downtime

Revocation is immediate, so put the new key in place first and revoke the old one last:

  1. Create a new rs_live_ key in the dashboard. Copy it at once; it is shown only one time.
  2. Store it in your secret manager or environment, next to the old key.
  3. Deploy, and confirm that the new key works (see the script below).
  4. Wait until Last Used of the old key stops changing. Then every process uses the new key.
  5. Revoke the old key.

If the old key is already revoked, steps 4 and 5 do not apply: deploy the new key as fast as you can. The security guide describes a regular rotation schedule.

This check confirms a key is accepted. It calls GET /v1/presets, which needs a valid key but does not render anything, so it uses no credit:

// verify-key.mjs  (Node 22): confirm a key is accepted before you revoke the old one.
// GET /v1/presets needs a valid key but renders nothing, so the check uses no credit.
const API = process.env.RS_BASE_URL ?? 'https://api.renderscreenshot.com';
const name = process.argv[2] ?? 'RS_API_KEY';
const key = (process.env[name] ?? '').trim();

const res = await fetch(`${API}/v1/presets`, { headers: { Authorization: `Bearer ${key}` } });
if (res.ok) {
  console.log(`${name} (${key.slice(0, 8)}...${key.slice(-4)}) is accepted`);
} else {
  const body = await res.json().catch(() => null);
  console.error(`${name} rejected: HTTP ${res.status} ${body?.error?.code ?? ''} ${body?.request_id ?? ''}`);
  process.exitCode = 1;
}

Signed URLs and revoked keys

Signed URLs use a key pair: the rs_pub_ key in the URL and the rs_secret_ key that creates the signature. If you revoke the public key, every URL that carries it stops working, including URLs already published in og:image tags and emails. If the account has no active secret key, signed URLs stop working too. Before you revoke either half, create a new pair, sign new URLs with it, and give pages and caches time to pick them up. The publishable keys guide explains the pair.

Handle it in code

A background job must not retry an authentication error. With the Ruby SDK, stop the job and log the request ID:

require 'renderscreenshot'

AUTH_CODES = %w[missing_credentials invalid_api_key revoked_key].freeze

class ScreenshotJob
  def self.client
    @client ||= RenderScreenshot.client(ENV.fetch('RS_API_KEY'))
  end

  def perform(url)
    self.class.client.take(RenderScreenshot::TakeOptions.url(url).preset('og_card'))
  rescue RenderScreenshot::AuthenticationError => e
    raise unless AUTH_CODES.include?(e.code)

    # Same key, same answer on every retry: stop and tell a person.
    warn "[screenshots] API key rejected (#{e.code}, request #{e.request_id}). Pausing the queue."
    raise
  end
end

In Sidekiq or Active Job, re-raise into a queue with no automatic retries, or pause the queue, so that thousands of jobs do not fail one by one.

Tested on 2026-10-15 with Node 22.18 and with Ruby 4.0.7 plus the renderscreenshot gem 1.0.0, against a local mock that returns the API's error envelope for an active key and a revoked key.

  • API keys: key types, creation and revocation.
  • invalidapikey: the key was never valid, for example a typo.

Related in this topic

Was this page helpful?