Use OpenAI images, transcription and speech with a spend cap
Keylayer prices OpenAI image generations and edits, transcriptions and translations, and speech before they reach OpenAI: tts-1 speech is charged $15 per million characters when the audio returns, and under an estimated cap a 1 MB upload to whisper-1 reserves $0.05. They use https://relay.keylayer.dev/v1 like the rest of OpenAI; the OpenAI page covers setup, the other routes and errors.
| Request | Hard cap | Estimated cap |
|---|---|---|
POST /v1/images/generations or /v1/images/edits on GPT Image 2 and 2.5 |
Worst-case cost | Worst-case cost |
POST /v1/audio/speech on tts-1 or tts-1-hd |
Input cost | Input cost |
POST /v1/audio/speech on gpt-4o-mini-tts with stream_format: "sse" |
Refused (403) | Body-size estimate |
POST /v1/audio/transcriptions or /v1/audio/translations |
Refused (403) | Upload-size estimate |
| Image variations, other image and audio models | Refused (403) | Refused (403) |
Images
GPT Image 2 and 2.5 generations, and edits sent as JSON or multipart form data, reserve their worst case from the request: the prompt at $5 per million text tokens, 73,800 tokens at $8 per million for each input image and the mask, since OpenAI doesn't document how many tokens an input image takes, and the output tokens of the quality and size you ask for, plus 100 for each partial image, at $30 per million and times n. In a multipart edit, each image and image[] part is an input image. An auto or missing quality reserves the model's dearest quality, and an auto or missing size reserves 2880x2880, the largest canvas OpenAI allows: about $0.71 per image with both, where "quality": "high" at 1024x1024 reserves about $0.21. When the response ends, it charges the usage OpenAI reports, or the usage on a stream's completed event, and frees the rest. A response without usage is charged the full reservation, and so is a moderation_blocked error whose moderation_stage isn't input, since OpenAI may bill an image it blocks after generating it.
Under either cap, these image requests get 403 unpriced_operation: models other than gpt-image-2, gpt-image-2.5-sunburst and gpt-image-2.5-flare and their snapshots, such as gpt-image-1.5, chatgpt-image-latest and DALL-E, a quality the model doesn't offer, sizes outside OpenAI's limits, n above 10, more than 3 partial images, a streamed request for more than one image, generations sent as multipart form data, and edit forms with a field OpenAI doesn't document for edits, or a file or a value over 128 KiB where a value goes. An escape hatch lets them through under an estimated cap, charged the body-size estimate. A form Keylayer can't read is always refused.
Image generation in Responses
A hard cap refuses a Responses request that offers the image_generation tool. An estimated cap reserves the body-size estimate plus the dearest image for each tool call allowed: max_tool_calls, or one. A stored prompt, which may turn the tool on, reserves the same.
Keylayer then charges the reported usage, the body-size estimate when the body lists a built-in tool, and each image_generation_call in the output, even a failed one: its output tokens plus 100 per partial image at the model's output price, its revised prompt at $5 per million tokens, and for an edit one 73,800-token input image at the model's input price.
gpt-image-1, the tool's default, and gpt-image-1-mini use OpenAI's token table at $40 per million: 272 to 6,240 tokens by quality and size, so at most about $0.25. gpt-image-1.5 uses that table at $32 per million, and GPT Image 2 and 2.5 the formula above. An auto or unknown size or quality counts as the dearest. An unknown model counts each call as a 2880x2880 image at $40 per million, and a stored prompt or two image tools also count 3 partial images and, unless OpenAI reports a generation, an input image: up to about $1.70.
An edit counts one input image however many you send, and an image from previous_response_id counts only when OpenAI reports an edit. A stream cut short is charged its reservation, which covers one image without max_tool_calls, plus the worst case the same request would have without the tool, if it would have one.
Transcripts
Transcriptions and translations bill by audio length, unknown in advance, so a hard cap refuses them. An estimated cap reserves the upload as 16 kbit/s audio at the model's price per minute, at least 10 seconds, and at most 25 minutes on the gpt-4o models unless the form sets chunking_strategy; 1 MB reserves $0.05 on whisper-1. Keylayer then charges the seconds or tokens OpenAI reports, or a verbose_json response's duration. A response with neither is charged the full reservation, and so is one your client hangs up on that OpenAI hasn't finished 5 seconds later.
text, srt and vtt responses, translations other than verbose_json, whisper-1 or gpt-transcribe streams, undocumented form fields and other models get 403 unpriced_operation; an escape hatch admits them at the full reservation. Unreadable forms are always refused.
Speech
Speech on tts-1 and tts-1-hd costs $15 and $30 per million characters of input. Keylayer counts each UTF-8 byte as a character, so English text is charged what OpenAI bills and accented or non-Latin text up to 4 times as much. It reserves that cost before forwarding, so a hard cap holds it, and charges it when OpenAI returns the audio: 4,096 characters of English, the most OpenAI takes, come to $0.06 on tts-1. An error is free, unless it's a 504 or 524 timeout.
gpt-4o-mini-tts bills by tokens and reports them only at the end of a stream, so Keylayer prices it only with stream_format: "sse", and only under an estimated cap. It reserves a quarter token per byte of the body at $150 per million plus $0.001, about $0.16 for a full 4,096-character input, then charges the input and output tokens the stream's final speech.audio.done event reports, at $0.60 and $12 per million. A stream without them is charged the full reservation, and so is one your client hangs up on that hasn't ended 5 seconds later.
Other speech models, and gpt-4o-mini-tts without stream_format: "sse", get 403 unpriced_operation; an escape hatch lets them through under an estimated cap, charged the body-size estimate. A body Keylayer can't read is always refused.
Forms
Keylayer reads multipart forms as the OpenAI Python, Node and .NET SDKs send them, and gives a form another reader could split differently 403 unpriced_operation under either cap, with or without escape hatches. A part without a filename is a value, sent with no Content-Type or as text/plain with at most charset=utf-8: a value of another type, such as application/json, makes the form unreadable, and so does a file typed multipart/*, a field sent twice unless its name ends in [], or more than 64 parts. An edit's image, image[] or mask sent as a value rather than a file must be one https:// URL, data:image/...;base64, URL or file- id.
Updated