# MediaRuntime operations and safe automation

Reviewed 2026-09-16. This guide describes existing behavior. Consult the
[OpenAPI contract](https://mediaruntime.com/openapi.json) for operation schemas and
the [capability catalog](https://mediaruntime.com/v1/capabilities) for supported presets.

## Rate limits and retries

The gateway applies account/key throttling and additional shared sandbox capacity
limits. Limits depend on the caller and deployment configuration; this guide does
not promise a universal requests-per-minute allowance. Ask
[support](https://mediaruntime.com/contact) about capacity needed for your workload.

- On HTTP `429`, honor `Retry-After` when supplied. The gateway's limiters express
  this delay in seconds. Sandbox errors may use `sandbox_rate_limited` or
  `sandbox_busy` instead of `rate_limited`.
- If no delay is supplied, use capped exponential backoff with jitter and a bounded
  retry budget. Check `error.retryable`; do not retry every error indiscriminately.
- Persist the original job request body and `Idempotency-Key` before submission.
  Reuse both after a timeout, connection failure, or retryable response. A new key
  represents new work and can create another billable job.
- A key is honored for 24 hours and scoped to the account (sandbox keys are scoped
  to the session). Keep the returned `job_id` beyond that retry window.
- A conflicting body with the same key returns HTTP `422`; an in-progress claim
  can return HTTP `409`. Correct invalid input rather than retrying it unchanged.
- Keep `X-Request-Id` or `error.request_id` when asking support to trace a failure.
  Remove API keys, signed media URLs, and private content from shared logs.

See the [error reference](https://mediaruntime.com/docs#errors) and
[job submission guide](https://mediaruntime.com/docs#jobs).

## Job workflow and billing

1. Discover the preset, accepted input type, and processing tier through
   `GET /v1/capabilities`. Manual clipping without captions does not require
   transcription. Clip Candidates generates a transcript when one is not supplied;
   captioned manual clips use a supplied source-timed transcript.
2. Use a fetchable media URL or upload local bytes using `POST /v1/upload-url`.
   Keep the source accessible until the worker has downloaded it.
3. Submit `POST /v1/jobs` with a stable `Idempotency-Key`. This is an execution
   request: it can reserve credit and start billable processing. Automatic estimator
   preflight is part of submission, not a public dry-run operation.
4. Persist `job_id`. `QUEUED` means the job is waiting for execution; worker
   provisioning can delay startup. Poll the existing job for scripts, or verify
   signed terminal webhooks in production. Do not resubmit solely because a job
   remains queued.
5. Inspect terminal status, `billing`, and `usage`. Download successful outputs;
   inspect failed or partial results before deciding whether to submit new work.

MediaRuntime uses prepaid pay-as-you-go billing. Submission estimates usage and
reserves the estimate plus a 15% buffer; terminal settlement releases unused
reservation. Multiple outputs and Premium features can increase usage. The job's
billing snapshot is authoritative, including when processing fails or is partial;
do not infer a refund or a charge from an HTTP retry alone. Public starting prices
are not flat per-job prices. See [pricing](https://mediaruntime.com/pricing) and
[billing documentation](https://mediaruntime.com/docs#billing).

## Output retention and delivery

Delivery links are short-lived credentials. Fetch the job again to obtain current
delivery information while its outputs remain retained. Follow the job's reported
retention and expiry information rather than assuming every account has the same
retention period. Download and store outputs you need before expiry.

An expired signed URL and deleted output bytes are different conditions: refreshing
a link does not restore data after retention cleanup. Preserve stable job and media
identifiers, not signed URLs. Typed analysis endpoints can return a valid report
with no matching candidates; this is distinct from a failed processing job.

### Temporary media cleanup

Account uploads become eligible for cleanup five days after upload. Job output
cleanup waits until both seven days after the job finishes and its reported
expiry have passed (and never removes a newly written output within seven days).
Candidates receive a further 24-hour grace period and are checked by a bounded
hourly task. Active jobs, storage holds and incomplete metadata can delay cleanup.
Keep your own durable copies; use each job's reported expiry for download access.
Sandbox example inputs, hosted sticker packs and persistent account assets are
excluded. Deleted objects may remain recoverable by the operator for seven more
days under storage soft delete. Job history and billing records have separate
retention and are not deleted by this media-cleanup task.

## Action reversibility

- The public media-job API currently has no cancel-job or undo-processing operation.
  Confirm source, output ranges, and billable intent before submitting automation.
- Retrying a terminal webhook sends the notification again; it does not rerun media
  processing. Receivers should handle duplicate event delivery.
- Recipe deletion archives the recipe. Versions are immutable; do not treat recipe
  management as an overwrite of an existing version.
- Sticker collection archive/restore and pack enable/disable are configuration
  operations. Disabling a pack for new discovery preserves historical binding
  information; it does not itself cancel hosted-pack billing.

See [recipes](https://mediaruntime.com/docs#hosted-recipes) and
[Sticker Runtime](https://mediaruntime.com/docs/stickers) for the relevant operations.

## Versioning and release information

Use the published `/v1` contract. `POST /v1/transcode` remains a supported alias for
`POST /v1/jobs` with the same idempotency namespace; no migration deadline currently
applies. New integrations should use `/v1/jobs`.

SDK and CLI release histories are available separately:

- [Node.js SDK releases](https://github.com/ericel/mediaruntime-node-sdk/releases)
- [Python SDK releases](https://github.com/ericel/mediaruntime-python-sdk/releases)
- [CLI releases](https://github.com/ericel/mediaruntime-cli/releases)

Those package releases do not establish an API uptime SLA or a gateway deployment
timeline. Report API problems or suspected security issues privately through
[support](https://mediaruntime.com/contact) or support@mediaruntime.com; include
request IDs and a minimal redacted reproduction, without credentials or private media.

## Local development with real processing

Localhost applications can use the hosted API with their normal account API key.
Processing is billable at the account's normal rates; this is not sandbox mode.
Keep the API key in your server process. The SDK uploads local files; the hosted
service cannot fetch a localhost URL directly.

Set `deliver_webhook: false` on `POST /v1/jobs` to suppress callbacks for that
job, even when the account has a live webhook endpoint. It defaults to `true`.
This also suppresses batch completion callbacks; `/retry-webhook` returns HTTP
409 with code `webhook_delivery_disabled` for an opted-out job. The account's
webhook settings, billing, output retention and email preferences are unchanged.
`GET /v1/jobs/{job_id}` reports `deliver_webhook` so clients can verify the policy.
Poll the saved job ID and use the returned bundle download URL when complete.
A polling timeout does not cancel a job: resume polling that ID instead of
submitting another paid job.

Node SDK (requires the SDK release containing this option):

```js
const job = await media.jobs.create({
  source: "./product-video.mp4",
  outputs: ["video.web"],
  deliverWebhook: false,
});
// Persist job.id before waiting, so a restart can resume media.jobs.wait(job.id).
const result = await job.wait();
if (result.status !== "COMPLETED") throw new Error(`Job ${result.id}: ${result.status}`);
// Download result.bundle.downloadUrl before result.bundle.expiresAt.
```

Python SDK (requires the SDK release containing this option):

```python
job = media.jobs.create(
    source="./product-video.mp4",
    outputs=["video.web"],
    deliver_webhook=False,
)
# Persist job.id before waiting; resume with media.jobs.wait(job.id).
result = job.wait()
if result.status != "COMPLETED":
    raise RuntimeError(f"Job {result.id}: {result.status}")
# Download result.bundle.download_url before result.bundle.expires_at.
```

For submission retries across process restarts, upload once with the SDK's upload
helper, persist its `fileUri` / `file_uri`, and reuse the identical request and
idempotency key within the 24-hour deduplication window. After receiving a job ID,
only poll that job. Do not re-upload or create another job just because waiting
expired. Sticker Runtime requests remain available with the same server-side key
and their usual authorization and billing; this flag only controls job webhooks.
