> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voyager.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Estimate a job

> What a job with this body would cost. Reserves nothing; null when unknown; not a price cap (the charge is the
job's real cost). ``can_run`` is false when the plan, model access or balance refuses it, or it is unknown.

An https URL in ``input`` is priced as it is (checked, never downloaded or stored). One exception: a source
recording for a speech, voice or audio model, whose price depends on its length, is imported into your workspace
to measure it (a reference file that expires after 7 days, like any imported reference); send a file_ id from
POST /v1/files to avoid the import.



## OpenAPI

````yaml /openapi/voyager-api.yaml post /estimate
openapi: 3.1.0
info:
  title: Voyager API
  description: >-
    Generate images, video, speech, music, sound effects and 3D with your
    Voyager workspace's credits. Authenticate with `Authorization: Bearer
    vy_live_…`. Every response carries `X-Request-ID` and the
    `X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset` (seconds
    until the window resets) headers; a 429 adds `Retry-After`. Errors share one
    envelope (`ErrorResponse`).
  version: 1.0.0
  x-voyager-agent-prompt: >
    Set up the Voyager API in this project.


    Voyager generates images, video, speech, music, sound effects, 3D and object
    masks with the same models

    and credits as the Voyager app. Docs: https://docs.voyager.so/api 
    (agent-readable:

    https://docs.voyager.so/llms.txt, OpenAPI:
    https://api.voyager.so/v1/openapi.json)


    1. Key: read it from the env var VOYAGER_API_KEY. Never hard-code it or
    commit it; add
       VOYAGER_API_KEY= to .env.example and make sure .env is git-ignored. If it's missing,
       ask me to create one at https://voyager.so/dashboard/api (paid plans).
    2. Base URL https://api.voyager.so/v1, header: Authorization: Bearer
    $VOYAGER_API_KEY

    3. Pick a model: GET
    /models?type=image|video|speech|music|sound_effect|3d|segment. Read
       GET /models/{id} for its input_schema before building a request.
    4. Optional cost check: POST /estimate with the same body as step 5; it
    returns
       estimated_charge (credits) and can_run.
    5. Create: POST /jobs {"model": "<id>", "operation": "<op>", "input": {...}}
    with an Idempotency-Key header
       (a new UUID per logical request; reuse it when retrying the same request).
    6. Wait: GET /jobs/{id}?wait=25 until status is succeeded, failed or
    canceled
       (honor Retry-After / poll_after_ms). Or pass "webhook_url" and verify the
       Standard Webhooks signature with the secret from the dashboard.
    7. Results: job.outputs[].url is a signed link valid for 1 hour; download it
    right
       away, or GET /jobs/{id} again for a fresh link. Files are kept 30 days.
    8. Errors are {"error": {"code","message","retryable",...}}. 402 = out of
    credits or
       not on a paid plan (show error.details.upgrade_url to me). 429 = slow down: wait
       Retry-After seconds. Retry only when retryable is true, with the same Idempotency-Key.

    Minimal example (curl):
      curl -s https://api.voyager.so/v1/jobs \
        -H "Authorization: Bearer $VOYAGER_API_KEY" -H "Content-Type: application/json" \
        -H "Idempotency-Key: $(uuidgen)" \
        -d '{"model":"nano-banana-2.1","operation":"text-to-image","input":{"prompt":"a red fox in snow","aspect_ratio":"16:9"}}'
      curl -s "https://api.voyager.so/v1/jobs/<job id>?wait=25" -H "Authorization: Bearer $VOYAGER_API_KEY"

    Write a small typed client (create → wait → download) with retries as above,
    then

    generate one test image to prove it works and tell me what it cost
    (job.credits.charged;

    if credits.state is still "pending", report job.credits.estimated and say
    it's an estimate).
servers:
  - url: https://api.voyager.so/v1
    description: Production
security: []
paths:
  /estimate:
    post:
      tags:
        - Jobs
      summary: Estimate a job
      description: >-
        What a job with this body would cost. Reserves nothing; null when
        unknown; not a price cap (the charge is the

        job's real cost). ``can_run`` is false when the plan, model access or
        balance refuses it, or it is unknown.


        An https URL in ``input`` is priced as it is (checked, never downloaded
        or stored). One exception: a source

        recording for a speech, voice or audio model, whose price depends on its
        length, is imported into your workspace

        to measure it (a reference file that expires after 7 days, like any
        imported reference); send a file_ id from

        POST /v1/files to avoid the import.
      operationId: estimateJob
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: Accepted and validated; an estimate starts nothing.
            title: Idempotency-Key
          description: Accepted and validated; an estimate starts nothing.
        - name: X-Voyager-Cast-Version
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              1: input.cast takes saved cards with selections and inline
              packages, input.cast_policy and input.cast_plan, and answers carry
              cast_usage. Omit for today's string Cast.
            title: X-Voyager-Cast-Version
          description: >-
            1: input.cast takes saved cards with selections and inline packages,
            input.cast_policy and input.cast_plan, and answers carry cast_usage.
            Omit for today's string Cast.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JobRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Estimate'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '400':
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '401':
          description: Missing, invalid or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '402':
          description: >-
            Billing wall: a paid plan or more credits is needed
            (details.upgrade_url).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '404':
          description: Not found in this workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '422':
          description: The request is well formed but cannot be processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '429':
          description: Rate limited. Retry after Retry-After seconds.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
        '503':
          description: Temporarily unavailable. Retry with backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          headers:
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
      security:
        - bearerAuth: []
components:
  schemas:
    JobRequest:
      properties:
        model:
          type: string
          maxLength: 200
          minLength: 1
          title: Model
          description: A model id from GET /v1/models.
        operation:
          anyOf:
            - type: string
              enum:
                - text-to-image
                - edit
                - text-to-video
                - image-to-video
                - reference-to-video
                - tts
                - music
                - sound-effects
                - text-to-3d
                - image-to-3d
                - image-to-3d-body
                - align-3d
                - segment-image
                - segment-image-data
                - segment-video
                - segment-video-data
                - segment-everything
                - image-embedding
            - type: 'null'
          title: Operation
          description: >-
            One of text-to-image, edit, text-to-video, image-to-video,
            reference-to-video, tts, music, sound-effects, text-to-3d,
            image-to-3d, image-to-3d-body, align-3d, segment-image,
            segment-image-data, segment-video, segment-video-data,
            segment-everything, image-embedding (GET /v1/models/{id} lists a
            model's). Required unless the model runs only one.
        input:
          $ref: '#/components/schemas/JobInput'
          description: >-
            The model's canonical inputs: its input_schema on GET
            /v1/models/{id} (file_ ids or https URLs for media), plus optional
            cast (up to 4 cst_ ids) on image and video operations.
        webhook_url:
          anyOf:
            - type: string
              maxLength: 2048
            - type: 'null'
          title: Webhook Url
          description: >-
            Public https URL that receives job.succeeded / job.failed /
            job.canceled (Standard Webhooks).
        metadata:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Metadata
          description: >-
            Up to 16 string pairs echoed on the job and its webhooks (values ≤
            500 chars).
      additionalProperties: false
      type: object
      required:
        - model
      title: JobRequest
    Estimate:
      properties:
        object:
          type: string
          const: estimate
          title: Object
          default: estimate
          description: Always "estimate".
        model:
          type: string
          title: Model
          description: The model estimated.
        operation:
          type: string
          title: Operation
          description: The operation estimated.
        estimated_charge:
          anyOf:
            - type: number
            - type: 'null'
          title: Estimated Charge
          description: Expected credits for this request; null when unknown.
        required_hold:
          anyOf:
            - type: number
            - type: 'null'
          title: Required Hold
          description: >-
            Credits held when the job is accepted, at today's prices; null when
            unknown.
        available_credits:
          anyOf:
            - type: number
            - type: 'null'
          title: Available Credits
          description: >-
            The workspace's credit balance, as its Voyager dashboard shows it;
            null when unknown.
        can_run:
          type: boolean
          title: Can Run
          description: False when the plan, access or balance refuses it, or it is unknown.
        reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Reason
          description: >-
            Why not, as the error code a create would get: model_not_in_plan,
            model_access_required, insufficient_credits, credits_reloading
            (retry shortly), free_allowance_exhausted, free_window_limit,
            free_media_limit, paid_plan_required, no_voyager_seat,
            model_unavailable; estimate_unavailable when it could not be read.
        upgrade_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Upgrade Url
          description: Where to upgrade the plan or add credits, when that is the reason.
        estimate_basis:
          anyOf:
            - type: string
              const: fallback
            - type: 'null'
          title: Estimate Basis
          description: >-
            "fallback" when nothing prices this request and estimated_charge is
            its model's fallback rate (show it as an estimate); absent
            otherwise. A fallback figure never refuses the job.
        estimate_source:
          anyOf:
            - type: string
              enum:
                - a
                - b
                - c
                - d
                - e
            - type: 'null'
          title: Estimate Source
          description: >-
            With estimate_basis fallback, the rate's evidence: a its own
            settlements, b its provider's published price, c its own other
            prices scaled, d a peer model's, e its media type's default.
        cast_usage:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Cast Usage
          description: >-
            With X-Voyager-Cast-Version: 1 and input.cast: what the Elements
            compile to. Pass its plan as input.cast_plan to create the job only
            if the Elements still compile to it.
      type: object
      required:
        - model
        - operation
        - estimated_charge
        - required_hold
        - available_credits
        - can_run
      title: Estimate
    ErrorResponse:
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
          description: What went wrong.
      type: object
      required:
        - error
      title: ErrorResponse
      description: Every non-2xx answer.
    JobInput:
      title: JobInput
      type: object
      description: >-
        Canonical inputs shared by every model. A model's input_schema (GET
        /v1/models/{id}) lists the ones it takes, their values for that model,
        and its own canonical extras.
      properties:
        prompt:
          type: string
          description: The instruction; `caption` only where it is a string.
        negative_prompt:
          type: string
          description: Negative prompt.
        text:
          type: string
          description: The words spoken.
        aspect_ratio:
          type: string
          description: 'Unit: "W:H" or "auto".'
        resolution:
          type: string
          enum:
            - 360p
            - 480p
            - 540p
            - 720p
            - 768p
            - 1080p
            - 1440p
            - 2k
            - 4k
            - 0.5k
            - 1k
            - 1.5k
          description: Lowercase; others as-is.
        duration_seconds:
          type: number
          description: >-
            The model's values or range; "auto" where the model takes it. Unit:
            seconds.
        count:
          type: integer
          description: Count.
        seed:
          type: integer
          description: Seed.
        generate_audio:
          type: boolean
          description: Generate audio.
        voice_id:
          type: string
          description: Voice id.
        image:
          type: string
          contentMediaType: image/*
          description: >-
            A file_ id from POST /v1/files, or an https URL (imported into your
            workspace first).
        images:
          type: array
          items:
            type: string
            contentMediaType: image/*
          description: >-
            A file_ id from POST /v1/files, or an https URL (imported into your
            workspace first).
        end_image:
          type: string
          contentMediaType: image/*
          description: >-
            A file_ id from POST /v1/files, or an https URL (imported into your
            workspace first).
        video:
          type: string
          contentMediaType: video/*
          description: >-
            A file_ id from POST /v1/files, or an https URL (imported into your
            workspace first).
        audio:
          type: string
          contentMediaType: audio/*
          description: >-
            A file_ id from POST /v1/files, or an https URL (imported into your
            workspace first).
        cast:
          description: 'API only: cst_ ids, at most 4.'
      additionalProperties: true
    ErrorBody:
      properties:
        type:
          $ref: '#/components/schemas/ErrorType'
          description: Stable category to branch on.
        code:
          type: string
          enum:
            - invalid_request
            - invalid_input
            - content_policy
            - upstream_unavailable
            - rate_limited
            - queue_full
            - model_unavailable
            - model_not_found
            - insufficient_credits
            - paid_plan_required
            - model_not_in_plan
            - model_access_required
            - outcome_unknown
            - expired
            - not_found
            - conflict
            - forbidden
            - internal_error
            - catalog_unavailable
            - billing_unavailable
            - no_voyager_seat
            - credits_reloading
            - cast_not_supported
            - voice_cloning_unavailable
            - too_many_references
            - payload_too_large
            - upload_too_large
            - intake_full
            - invalid_url
            - fetch_failed
            - unsupported_file
            - invalid_api_key
            - idempotency_conflict
            - idempotency_in_flight
            - invalid_idempotency_key
            - invalid_cursor
            - invalid_webhook_url
            - method_not_allowed
            - account_unavailable
            - plan_required_for_faces
            - version_conflict
            - slug_taken
            - already_referenced
            - asset_in_use
            - upload_incomplete
            - cancel_unsupported
            - unsupported_model
            - invalid_job_id
            - voice_required
            - observation_timeout
            - reference_unavailable
            - queue_timeout
            - reference_missing
          title: Code
          description: >-
            Stable machine code; never renamed once published (x-voyager-errors
            lists each).
        message:
          type: string
          title: Message
          description: For developers. Not localized.
        doc_url:
          type: string
          title: Doc Url
          description: https://docs.voyager.so/api/errors#<code>
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Request Id
          description: Also in the X-Request-ID header; quote it to support.
        retryable:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Retryable
          description: Whether the same request can succeed later.
        retry_after_ms:
          anyOf:
            - type: integer
            - type: 'null'
          title: Retry After Ms
          description: How long to wait before retrying.
        param:
          anyOf:
            - type: string
            - type: 'null'
          title: Param
          description: >-
            The request field at fault, as a path (e.g. input.resolution); set
            on invalid_input.
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: Code-specific detail, e.g. upgrade_url on a billing wall.
      type: object
      required:
        - type
        - code
        - message
        - doc_url
      title: ErrorBody
    ErrorType:
      type: string
      enum:
        - invalid_request
        - authentication
        - permission
        - not_found
        - conflict
        - rate_limited
        - idempotency_conflict
        - unprocessable
        - upstream_error
        - internal_error
      title: ErrorType
      description: Closed set of high-level categories SDKs branch on.
  headers:
    X-Request-ID:
      description: This request's id (also error.request_id).
      schema:
        type: string
    X-RateLimit-Limit:
      description: >-
        Requests allowed per 60 seconds in this bucket (120 writes or 600 reads
        per minute per key).
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in this window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Seconds until the window resets.
      schema:
        type: integer
    Retry-After:
      description: Seconds to wait before retrying.
      schema:
        type: integer
  securitySchemes:
    bearerAuth:
      type: http
      description: A Voyager API key from https://voyager.so/dashboard/api.
      scheme: bearer
      bearerFormat: vy_live_…

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.