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

# Per-Second Compute

> How per-second billing works for the live-video-to-video pipeline on Livepeer: fee calculation, ticket generation intervals, and pricing configuration.

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

<CenteredContainer preset="readable90">
  <Tip>The live-video-to-video pipeline bills per wall-clock second of active inference. The Gateway pays based on elapsed time at regular intervals, not per output pixel or per request.</Tip>
</CenteredContainer>

***

The `live-video-to-video` (Cascade) pipeline operates as a persistent streaming session instead of a discrete request-response exchange. Standard per-pixel or per-request billing does not map naturally to this model. Instead, Livepeer uses per-second compute billing for live AI: the Gateway pays for the time the Orchestrator's GPU is actively running inference for the session.

<CustomDivider />

## Fee Calculation

The `LivePaymentSender` interface in go-livepeer handles per-second fee calculation and ticket generation for live AI sessions. It calculates the fee based on:

* **Elapsed seconds** since the last payment was sent
* **Configured cost per hour** advertised by the Orchestrator

```
fee = elapsed_seconds × (cost_per_hour / 3600)
```

This fee is expressed in ETH (wei). The PM mechanism translates it into a ticket with the appropriate face value and win probability so the expected payout equals the computed fee.

Payments are sent at regular intervals during the session. The Orchestrator returns updated ticket parameters after each payment; the Gateway uses those parameters for the next payment in the series.

<CustomDivider />

## Configuring Pricing

Orchestrators set per-second pricing for AI pipelines in `aiModels.json`. The pricing field is `price_per_unit`, and for live AI the unit is one second of inference time:

```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
  {
    "pipeline": "live-video-to-video",
    "model_id": "comfystream",
    "url": "http://127.0.0.1:8188",
    "price_per_unit": 1000000000000000,
    "warm": true
  }
]
```

`price_per_unit` is in wei per second. 1000000000000000 wei = 0.001 ETH per second = 3.6 ETH per hour.

Gateways set a maximum acceptable price via `-maxPricePerUnit`. Orchestrators whose `price_per_unit` exceeds this maximum are excluded from selection for that session.

<CustomDivider />

## State Management

Per-second billing requires stateful bookkeeping: the Gateway must track how much time has elapsed since the last payment and how much ETH has been committed. In the remote signer model, this bookkeeping lives in the signer service instead of the Gateway:

* The Gateway sends `signerState` (the accumulated bookkeeping state from the previous signing call) with each `signTicket` request
* The signer updates the state (records elapsed time, adjusts balance) and returns the updated `signerState` alongside the signed ticket
* The Gateway stores the returned state and sends it with the next request

This design makes the signer stateless across restarts: the Gateway carries the state, and the signer reconstructs its view from the state it receives. If a Gateway sends a null state, the signer creates a fresh session.

Failure to send the correct updated state (or sending stale state) leads to invalid tickets due to repeated nonces or incorrect fee calculations.

<CustomDivider />

## Payment Intervals

The Gateway sends payments at configurable intervals during the session, not per-frame. The interval is set to balance two concerns: payment frequency (more frequent = smaller per-ticket amounts, smaller ETH commitment per interval) and overhead (more frequent = more signing calls and on-chain submissions).

For production live AI workloads, the go-livepeer default payment interval is adequate. Custom Gateway implementations using `livepeer-python-gateway` inherit the interval logic from `LivePaymentSender` in the remote signer.

<Note>
  Per-second compute billing applies specifically to the `live-video-to-video` pipeline. Batch AI pipelines (text-to-image, audio-to-text, etc.) use per-output-unit billing. See the individual pipeline reference pages for recommended pricing.
</Note>

<CustomDivider />

## Related Pages

<CardGroup cols={2}>
  <Card title="Probabilistic Micropayments" icon="coin" href="/v2/developers/guides/payments/probabilistic-micropayments" arrow horizontal>
    How PM tickets and face values translate per-second fees to on-chain settlement.
  </Card>

  <Card title="Remote Signer" icon="key" href="/v2/developers/guides/payments/remote-signer" arrow horizontal>
    How the remote signer manages LivePaymentSender state for off-chain Gateways.
  </Card>

  <Card title="Real-Time AI Overview" icon="video" href="/v2/developers/build/ai-and-agents/realtime-ai/overview" arrow horizontal>
    The Cascade pipeline that uses per-second compute billing.
  </Card>

  <Card title="Alt-Gateway Overview" icon="server" href="/v2/developers/build/alt-gateways/overview" arrow horizontal>
    Python Gateway implementation that integrates with LivePaymentSender.
  </Card>
</CardGroup>
