Quote a media model

This page shows how to quote an image, speech, transcription, embedding or video model. It tells you which features to declare, how to declare sizes, and how to write the price table. Read Quote over the session first for the frames.

A buyer's control works only when an offer declares it. If you do not declare a control, no job that sets it reaches you. This is on purpose: an offer that ignores a control and still charges for the job is not a fair sale.

1. Declare the controls

Each control has a feature. The feature has the name of the request field of the buyer. Put the features that you support in supported_features of the quote.

Kind Field of the buyer Feature
Image seed image.seed
Image background (transparent or opaque) image.background
Image output_compression image.output_compression
Image stream: true image.stream
Video seed video.seed
Video creativity video.creativity
Video upscale_factor video.upscale_factor
Video previous_job_id video.continue
Speech instructions speech.instructions
Speech input as more than one turn speech.turns
Transcription diarize transcription.diarize
Transcription keyterms transcription.keyterms
Embedding input_type embedding.input_type

In an agent that you write

Send the features in the quote frame:

{ "type": "quote", "supported_features": ["text", "image.seed", "image.background"] }

With the Rust agent library, an Upstream lists its controls in Upstream::controls(kind, route, handle). It returns the features for that kind of job. The agent keeps only the controls that fit the kind. A rate card can narrow the list with ExecutionRoute::features. It cannot add to it. Upstream::reference_inputs(kind) lists the input.* features.

The Python reference provider declares only text. It cannot win a job that sets a control. Add the names that your upstream honors.

What the OpenAI adapter declares

The first-party OpenAI adapter declares these controls:

Kind Declared
Image image.background and image.output_compression for a model whose name starts with gpt-image. image.seed when the route has a seed rule.
Video video.seed when the route has a seed rule.
Speech speech.instructions for a model whose name contains gpt-4o.

It declares nothing else. In particular, it declares no image.stream, speech.turns, transcription control, embedding control, video.creativity, video.upscale_factor or video.continue. To sell those, write your own agent.

2. Declare sizes and resolutions

The registration of the deployment sets what the model makes. See Register deployments. The buyer's resolution and aspect_ratio resolve against it.

Images

List the pixel sizes in sizes of the image output, as <width>x<height>. There is no separate list of tiers or shapes. The exchange works them out from the sizes.

Video

List the pixel sizes in sizes and the labels in resolutions, for example ["1280x720"] and ["720p"].

3. Write the price table

The quote states prices in pricing. A price is USD for one unit. Each line has billable, unit, usd and, if the price depends on an option, a variant.

billable unit Counted
input_text mtok Input tokens that no cache served
cache_read mtok Input tokens that a cache served
cache_write_short mtok Tokens written to a cache for five minutes
cache_write_long mtok Tokens written to a cache for one hour
output_text mtok Output tokens, not the audio tokens
output_audio mtok Audio output tokens of a chat answer
output_image image Images
output_speech character Characters of the text
output_video second Seconds of video
input_audio second Seconds of audio to transcribe
input_reference_image image Reference images
input_reference_video second Seconds of reference video
input_reference_audio second Seconds of reference audio

The cap and the charge of a counted job are known before dispatch. The exchange multiplies the count by the line that holds for the job. So the cap is exactly the charge.

A video model

Registration:

{
  "kind": "video_generation",
  "output_modalities": [
    { "type": "text" },
    {
      "type": "video",
      "sizes": ["1280x720", "1920x1080"],
      "resolutions": ["720p", "1080p"],
      "seconds": [4, 8],
      "audio": "optional",
      "formats": ["video/mp4"]
    }
  ]
}

Quote:

"pricing": [
  { "billable": "output_video", "unit": "second", "usd": 0.10 },
  { "billable": "output_video", "unit": "second", "variant": { "audio": false }, "usd": 0.07 },
  { "billable": "output_video", "unit": "second", "variant": { "resolution": "720p" }, "usd": 0.06 },
  { "billable": "output_video", "unit": "second", "variant": { "resolution": "720p", "audio": false }, "usd": 0.04 },
  { "billable": "input_reference_video", "unit": "second", "usd": 0.02 }
]

A job for 8 seconds at 720p with sound pays the third line: 8 × $0.06. A job for 1080p with no other option pays the first line. A job for 720p without sound pays the fourth line, because it names more options than the second and the third.

An image model

Registration:

{
  "kind": "image_generation",
  "output_modalities": [
    { "type": "text" },
    {
      "type": "image",
      "sizes": ["1024x1024", "1536x1024", "2048x2048"],
      "formats": ["png", "webp"],
      "max_count": 4
    }
  ]
}

Quote:

"pricing": [
  { "billable": "output_image", "unit": "image", "usd": 0.04 },
  { "billable": "output_image", "unit": "image", "variant": { "size": "2048x2048" }, "usd": 0.08 }
]

A buyer who sends resolution: "2K" gets the size 2048x2048 and pays $0.08 for each image. A buyer who sends 1K gets 1024x1024 and pays $0.04. A buyer who sends quality or size pays the line whose variant matches, and the line with no variant otherwise.

If your upstream bills tokens, set pricing_unit to tokens and image_output_tokens_max in the registration. Quote input_text and output_text lines, and no output_image line. See Sell images.

A speech model

Registration lists the voices and formats. Quote one line, and a variant for a quality that costs more:

"pricing": [
  { "billable": "output_speech", "unit": "character", "usd": 0.000015 },
  { "billable": "output_speech", "unit": "character", "variant": { "quality": "hd" }, "usd": 0.00003 }
]

The charge is the characters of the text of all turns, times the price. A job for 500 characters pays $0.0075. With quality: "hd" it pays $0.015. A request with no quality, or a name that you do not price, pays the line with no variant.

A transcription model

Quote one line: { "billable": "input_audio", "unit": "second", "usd": 0.0001 }. The charge is the seconds of audio. See Sell transcription.

Old rate fields

An older quote states prices in fields such as rate_per_image, rate_per_video_second and pricing_skus. The exchange still reads them, but they are deprecated. No rate_* field is required.

4. What your agent receives

A media dispatch has one object for its kind: image, audio (speech), transcription, embedding or video. Control fields are present only if the buyer set them and you declared the feature.

For a video job, the exchange sends no cancel message. When the buyer cancels, or the job runs past the video job limit, it closes the dispatch connection. Watch for the close and stop. Each case costs the buyer nothing. See Cancel and expiry.

For previous_job_id, the exchange sends only the job id of the earlier video. It does not check that the earlier job ran on your deployment. Map the id to your own handle, and fail the job if you do not know it. See Continue a video.

5. What buyers see

6. Checklist for a new model

  1. Register the deployment with the right kind and the output_modalities of the model: sizes, voices, formats, lengths, resolutions and audio.
  2. List only the sizes, voices and lengths that your upstream makes. A buyer can ask for any value you list.
  3. Choose the controls that your agent sends and your upstream honors. Declare their features in supported_features.
  4. Declare the input.* features for the reference inputs that you read.
  5. Write pricing: one line with no variant for the billable of the kind, then the variant lines, then any reference prices. Use the unit of each billable.
  6. Make sure that each variant names an option that the registration states.
  7. Send the quote. Read the quote_ack or the quote_reject. For invalid_terms, read field and reason.
  8. Quote as an unverified offer first. Buy one job from your own workspace for each control, and compare the result with the request. See Unverified offers.
  9. Open the model card. Check parameters, image_sizes and pricing.
  10. For video, test a cancel: the agent must stop when the dispatch closes.