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

# Video Description Price Calculation

> Quote a video description before submitting it. Priced on the machine time the description takes — which grows with the length of the video and with the `preset` — at the model's hourly rate, except on TikTok, where the price is a fixed card by length (up to 1, 2, 3, 5 or 10 minutes; 10 minutes is the maximum) scaled ×0.75 / ×1 / ×1.5 by the `preset`. `include_metadata` adds the same flat surcharge as on transcription, on URL sources only. Provide the source as a URL, an upload, or a known `duration_seconds`.

Estimate the cost of a video description job before submitting it.


## OpenAPI

````yaml openapi-v2.json POST /api/v2/videos/descriptions/price
openapi: 3.1.0
info:
  title: deAPI REST API
  description: >-
    Decentralized AI inference API for image generation, video processing, audio
    transcription, and more.


    ## Rate limits


    Two windows can apply to a request: a per-minute one (RPM) and a per-day one
    (RPD). Every

    throttled response — success or 429 — carries the `X-RateLimit-*` headers,
    so you can pace

    traffic without waiting to be rejected. Each header documents itself: see
    `components/headers`,

    or the headers listed on any response. What follows is only what a header
    cannot say about

    itself.


    Windows open on your first request into a bucket and run their full length
    from that second —

    never to a calendar boundary, in any timezone. That is deliberate: a
    boundary every account

    shares is a boundary every account can double up on.


    **The headers describe the pool *this* request landed in, and
    `X-RateLimit-Source` is what

    identifies it — not `X-RateLimit-Limit` alone.** A per-model limit is keyed
    to the model you

    named, so a request that carried no recognised `model` — rejected at
    validation, an unknown

    slug, an empty body — was counted against your tier pool, and it is the tier
    pool the headers

    then describe. The two pools are fully independent: separate minute window,
    separate day,

    separate `X-RateLimit-Daily-Reset`. This is a consequence of rate limiting
    running *before*

    validation, which is what keeps malformed traffic from reaching the rest of
    the API

    uncounted. Compare headers only across responses carrying the same
    `X-RateLimit-Source`.


    **Buckets are shared in ways worth knowing.** API **v1 and v2 count against
    the same bucket**,

    so migrating grants no fresh allowance and mixed traffic behaves as one
    stream. All `*/price`

    and `*/price-calculation` endpoints share a single quote bucket, separate
    from generation.

    Prompt enhancement (`/v2/prompts/enhancements`) has its own bucket as well,
    so heavy prompt

    work no longer eats into your image throughput.


    **Counting is exact in sequence, best-effort in parallel.** Sent one after
    another, your

    requests are counted precisely: the one that crosses the limit is the one
    that gets 429. Sent

    in parallel, a few beyond the limit can slip through, because the counter is
    read and then

    incremented as two steps and requests already in flight are not yet visible
    to one another.

    The excess is bounded by how many of your own requests are in flight at
    once, and it only

    ever runs in your favour — you are never rejected while below your limit. So
    do not treat

    `X-RateLimit-Remaining` as a reservation: it is a snapshot, and a request
    you sent a

    millisecond ago may already have spent what it shows.


    Requests rejected before authentication (HTTP 401) never reach the limiter
    and carry no

    rate-limit headers at all.
  contact:
    name: deAPI Support
    url: https://deapi.ai
    email: support@deapi.ai
  version: 0.0.1
servers:
  - url: https://api.deapi.ai
    description: Production API Server base URL
security:
  - bearerAuth: []
tags:
  - name: Client API v2
    description: Current client endpoints (OpenAI-aligned noun-based paths)
paths:
  /api/v2/videos/descriptions/price:
    post:
      tags:
        - Client API v2
      summary: Estimate the price of a video description
      description: >-
        Quote a video description before submitting it. Priced on the machine
        time the description takes — which grows with the length of the video
        and with the `preset` — at the model's hourly rate, except on TikTok,
        where the price is a fixed card by length (up to 1, 2, 3, 5 or 10
        minutes; 10 minutes is the maximum) scaled ×0.75 / ×1 / ×1.5 by the
        `preset`. `include_metadata` adds the same flat surcharge as on
        transcription, on URL sources only. Provide the source as a URL, an
        upload, or a known `duration_seconds`.
      operationId: estimateVideoDescriptionPrice
      parameters:
        - $ref: '#/components/parameters/AcceptHeader'
      requestBody:
        description: Provide exactly one of video_url, video_file or duration_seconds.
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/VideoDescriptionPriceRequestBody'
      responses:
        '200':
          description: Calculated price for the video description.
          headers:
            X-RateLimit-Policy:
              $ref: '#/components/headers/X-RateLimit-Policy'
            X-RateLimit-Source:
              $ref: '#/components/headers/X-RateLimit-Source'
            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'
            X-RateLimit-Daily-Limit:
              $ref: '#/components/headers/X-RateLimit-Daily-Limit'
            X-RateLimit-Daily-Remaining:
              $ref: '#/components/headers/X-RateLimit-Daily-Remaining'
            X-RateLimit-Daily-Reset:
              $ref: '#/components/headers/X-RateLimit-Daily-Reset'
          content:
            application/json:
              schema:
                properties:
                  data:
                    properties:
                      price:
                        description: Calculated price
                        type: number
                        format: float
                        example: 0.25
                    type: object
                type: object
        '401':
          description: Unauthorized user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/response_error_default'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
      security:
        - bearerAuth: []
components:
  parameters:
    AcceptHeader:
      name: Accept
      in: header
      required: true
      schema:
        type: string
        default: application/json
        enum:
          - application/json
  schemas:
    VideoDescriptionPriceRequestBody:
      description: >-
        Exactly ONE input source per request — `video_url`, `video_file` or
        `duration_seconds` — hence the three variants below. They are mutually
        exclusive, not a menu of optional fields: sending two of them is a 422.
        `platform` belongs to the `duration_seconds` variant alone. `model` and
        `preset` apply to all three, and are validated exactly as on POST
        /api/v2/videos/descriptions, so a quote is never returned for a request
        the job endpoint would reject.
      oneOf:
        - title: From a video URL
          required:
            - video_url
            - model
          properties:
            video_url:
              description: >-
                URL of the video to quote. Mutually exclusive with `video_file`
                and `duration_seconds`; `platform` must NOT be sent with it, as
                it is derived from the URL. Quotes from a TikTok URL are refused
                (the lookup itself costs money) — quote TikTok by
                `duration_seconds` + `platform: tiktok` instead.
              type: string
              example: https://www.youtube.com/watch?v=jNQXAC9IVRw
            preset:
              description: >-
                The preset you will submit. It sets how much machine time the
                description takes (`detail` is roughly 7× `fast` per hour of
                material), which is what the price follows; on a TikTok, where
                the price is a fixed card, it multiplies the card ×0.75 / ×1 /
                ×1.5 for `fast` / `balanced` / `detail`. Omitted quotes at the
                model default (`balanced`). Ignored on a model without
                `info.features.supports_presets`.
              type:
                - string
                - 'null'
              example: balanced
              enum:
                - fast
                - balanced
                - detail
                - null
            include_metadata:
              description: >-
                Whether the job will ask for source metadata. Carries a flat
                surcharge on URL sources (an upload always returns null metadata
                and is never charged), so pass it exactly as you will pass it to
                POST /api/v2/videos/descriptions.
              type:
                - boolean
                - 'null'
              example: false
              default: false
            model:
              description: The model to use.
              type: string
              example: Marlin_2B
          type: object
          not:
            anyOf:
              - required:
                  - duration_seconds
              - required:
                  - video_file
              - required:
                  - platform
        - title: From an uploaded file
          required:
            - video_file
            - model
          properties:
            video_file:
              description: >-
                Video file to quote. Mutually exclusive with `video_url` and
                `duration_seconds`. Only the duration is read from it here.
              type: string
              format: binary
            preset:
              description: >-
                The preset you will submit. It sets how much machine time the
                description takes (`detail` is roughly 7× `fast` per hour of
                material), which is what the price follows; on a TikTok, where
                the price is a fixed card, it multiplies the card ×0.75 / ×1 /
                ×1.5 for `fast` / `balanced` / `detail`. Omitted quotes at the
                model default (`balanced`). Ignored on a model without
                `info.features.supports_presets`.
              type:
                - string
                - 'null'
              example: balanced
              enum:
                - fast
                - balanced
                - detail
                - null
            include_metadata:
              description: >-
                Whether the job will ask for source metadata. Carries a flat
                surcharge on URL sources (an upload always returns null metadata
                and is never charged), so pass it exactly as you will pass it to
                POST /api/v2/videos/descriptions.
              type:
                - boolean
                - 'null'
              example: false
              default: false
            model:
              description: The model to use.
              type: string
              example: Marlin_2B
          type: object
          not:
            anyOf:
              - required:
                  - duration_seconds
              - required:
                  - video_url
              - required:
                  - platform
        - title: From a known duration
          required:
            - duration_seconds
            - model
          properties:
            duration_seconds:
              description: >-
                Source duration in seconds. Mutually exclusive with `video_url`
                and `video_file`. This mode never fetches the source.
              type: number
              example: 600
              minimum: 0.1
            platform:
              description: >-
                The platform the source comes from. Valid ONLY on this variant,
                where there is no URL to derive it from — with `video_url` or
                `video_file` it is rejected. It changes the price: `tiktok` is
                quoted on the fixed length card (and capped at 10 minutes),
                every other value on machine time, and `platform` also decides
                whether `include_metadata` carries its surcharge — only platform
                sources can return metadata. A duration-only quote that omits it
                is priced as an upload, so for a URL job it can come in under
                the amount actually charged.
              type:
                - string
                - 'null'
              example: youtube
              enum:
                - youtube
                - twitter
                - twitch
                - kick
                - tiktok
                - null
            preset:
              description: >-
                The preset you will submit. It sets how much machine time the
                description takes (`detail` is roughly 7× `fast` per hour of
                material), which is what the price follows; on a TikTok, where
                the price is a fixed card, it multiplies the card ×0.75 / ×1 /
                ×1.5 for `fast` / `balanced` / `detail`. Omitted quotes at the
                model default (`balanced`). Ignored on a model without
                `info.features.supports_presets`.
              type:
                - string
                - 'null'
              example: balanced
              enum:
                - fast
                - balanced
                - detail
                - null
            include_metadata:
              description: >-
                Whether the job will ask for source metadata. Carries a flat
                surcharge on URL sources (an upload always returns null metadata
                and is never charged), so pass it exactly as you will pass it to
                POST /api/v2/videos/descriptions.
              type:
                - boolean
                - 'null'
              example: false
              default: false
            model:
              description: The model to use.
              type: string
              example: Marlin_2B
          type: object
          not:
            anyOf:
              - required:
                  - video_file
              - required:
                  - video_url
    response_error_default:
      properties:
        data:
          description: Information from success endpoint
          type: object
        message:
          description: Error general message
          type: string
        errors:
          description: Information about errors
          type: array
          items: {}
        statusCode:
          description: Status code
          type: integer
      type: object
    response_error_rate_limit:
      description: Rate limit exceeded response
      properties:
        message:
          description: Error message
          type: string
          example: Too Many Attempts.
      type: object
  headers:
    X-RateLimit-Policy:
      description: >-
        Every window that applies, as `<limit>;w=<seconds>` elements. Always
        present on a throttled response, so a single element means there is no
        daily limit — do not infer that from the absence of the Daily-* headers.
        `300;w=60` is minute-only; `3;w=60, 100;w=86400` is both.
      schema:
        type: string
        example: 3;w=60, 100;w=86400
    X-RateLimit-Source:
      description: >-
        Where the limit came from, so you know what would change it:

        `tier` — your account tier's rate for this endpoint;

        `fallback` — no rate configured for this tier and endpoint, degraded
        default in force;

        `model` — a per-model override for the model in the request, unaffected
        by your tier

        (only when the request carried a recognised `model`, otherwise the tier
        pool applies);

        `static` — a flat limit outside the tier system, identical for every
        account.


        If you ever see `fallback`, tell us: it means no rate is configured for
        that tier and endpoint.
      schema:
        type: string
        example: tier
        enum:
          - tier
          - fallback
          - model
          - static
    X-RateLimit-Limit:
      description: Maximum requests allowed per minute (RPM)
      schema:
        type: integer
        example: 3
    X-RateLimit-Remaining:
      description: Remaining requests in current minute window
      schema:
        type: integer
        example: 2
    X-RateLimit-Reset:
      description: >-
        Epoch second at which the minute (RPM) window refills. Fixed window —
        the value does not drift as you spend the quota. Describes the same
        window as X-RateLimit-Limit, including on a daily rejection.
      schema:
        type: integer
        example: 1755800460
    X-RateLimit-Daily-Limit:
      description: Maximum requests allowed per day (RPD)
      schema:
        type: integer
        example: 100
    X-RateLimit-Daily-Remaining:
      description: Remaining requests in current day window
      schema:
        type: integer
        example: 95
    X-RateLimit-Daily-Reset:
      description: >-
        Epoch second at which the daily (RPD) window refills — 86400 s after the
        first request that opened this bucket's window, not a calendar midnight.
        Present only when a daily limit applies.
      schema:
        type: integer
        example: 1755846000
    X-RateLimit-Type:
      description: >-
        Which window rejected the request: `minute` (RPM) or `daily` (RPD). Sent
        only on 429.
      schema:
        type: string
        example: minute
        enum:
          - minute
          - daily
    Retry-After:
      description: >-
        Seconds until the window that rejected you frees up (60 for minute, up
        to 86400 for daily). Counted from when that window opened, not to a
        calendar boundary. Sent only on 429.
      schema:
        type: integer
        example: 60
  responses:
    ValidationError:
      description: >-
        Validation failed. Common errors include: model does not exist, model
        does not support the inference type for this endpoint, the model is not
        available on your plan (it requires a higher tier than your account has
        — upgrade to use it), or invalid request parameters.
      content:
        application/json:
          schema:
            properties:
              message:
                description: General error message
                type: string
                example: The selected model does not support Text To Image.
              errors:
                description: >-
                  Detailed validation errors by field. A model your plan does
                  not cover is reported on the "model" field with the message
                  "This model is not available on your plan. Please upgrade to
                  access it." Such a model is also omitted from GET /models.
                type: object
                example:
                  model:
                    - >-
                      This model is not available on your plan. Please upgrade
                      to access it.
            type: object
    RateLimitExceeded:
      description: >-
        Rate limit exceeded. Check X-RateLimit-Type header to determine if
        minute (RPM) or daily (RPD) limit was hit.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Daily-Limit:
          $ref: '#/components/headers/X-RateLimit-Daily-Limit'
        X-RateLimit-Daily-Remaining:
          $ref: '#/components/headers/X-RateLimit-Daily-Remaining'
        X-RateLimit-Type:
          $ref: '#/components/headers/X-RateLimit-Type'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Daily-Reset:
          $ref: '#/components/headers/X-RateLimit-Daily-Reset'
        X-RateLimit-Source:
          $ref: '#/components/headers/X-RateLimit-Source'
        X-RateLimit-Policy:
          $ref: '#/components/headers/X-RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/response_error_rate_limit'
  securitySchemes:
    bearerAuth:
      type: http
      description: >-
        Sanctum personal access token, sent as `Authorization: Bearer <token>`.
        The token is opaque — it carries no claims and no embedded expiry, so do
        not attempt to decode it. Issue and revoke tokens from your account
        dashboard.
      scheme: bearer

````