API reference

Convert a file. Follow the job.

Choose a profile, submit presigned source and destination URLs, and follow the job to completion. Add a verification URL so silken can check an upload whose outcome is uncertain. Use the tuning reference to choose encode settings and evaluate tone controls on your source files. For a team rollout, Talk to sales or Book a meeting.

Quickstart

Submit your first file job.

Start without billing or storage: Try it in 2 minutes with a test key, or import the Postman collection.

Presign a GET URL for the source and a PUT URL for the output in your storage. Provide a separate verification URL for the output; it is used only when an upload’s outcome is uncertain. Authenticate with Authorization: Bearer <key> or X-API-Key. See the privacy notice for temporary processing files, retention and cleanup.

01 / Start
  1. Key. Create an API key in the dashboard.
  2. Presign. Sign a GET for the source, a PUT for the output and a verify URL.
  3. POST. Send POST /v1/jobs with a profile and the three URLs.
  4. Verify the webhook. Check the signature on the completion event, as shown under Signed webhooks.
  5. Read the result. GET /v1/jobs/{id} reports the job; the file is in your storage.

Before you start key, origin, storage URLs

  1. Key. Create an API key in the dashboard and export it as SILKEN_API_KEY. It is shown once.
  2. API origin. https://silken.io is the canonical public API origin. Native routes use /v1; MediaConvert clients use that origin as their endpoint override.
  3. Two presigned URLs for objects in your own bucket: a GET for the source and a PUT for the output. With AWS S3 the CLI signs the GET (add --endpoint-url for R2 or another S3-compatible store); a PUT is signed with an SDK.
aws s3 presign s3://my-bucket/in.mp4 --expires-in 7200
python3 -c "import boto3; print(boto3.client('s3').generate_presigned_url('put_object', Params={'Bucket':'my-bucket','Key':'out.mp4'}, ExpiresIn=7200))"

Use aws s3 presign s3://my-bucket/out.mp4 for verify_url once the object exists, or sign a HEAD for the same key. Run these on a machine that has credentials for the bucket.

curl -X POST "https://silken.io/v1/jobs" \
  -H "Authorization: Bearer $SILKEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile":     "hdr_to_sdr_1080p",
    "input_url":   "https://acct.r2.cloudflarestorage.com/in.mp4?X-Amz-Signature=…",
    "output_url":  "https://acct.r2.cloudflarestorage.com/out.mp4?X-Amz-Signature=…",
    "verify_url":  "https://acct.r2.cloudflarestorage.com/out.mp4?X-Amz-Signature=…",
    "webhook_url": "https://you.example.com/hooks/silken"
  }'

verify_url — read this before your first job the usual trap

When your storage answers the upload with success, silken records that response as a successful delivery and does not read the object back. If an upload’s outcome is uncertain — the connection drops, or no answer arrives — silken checks that the object is present and has the expected size before it completes or bills the job. A presigned PUT is often write-only, and cannot be read back — so that check needs somewhere to look.

  • Send verify_url: a presigned GET or HEAD for the same object. This is the path to prefer, and it is what the samples above do.
  • Omit it only if your output_url is itself readable. We probe it, and if it is, we use it for that check.
  • If neither is readable, a job asking for the default durability: "verified" is rejected up front with 400 verification_unavailable rather than failing later. Send durability: "best_effort" to accept an unverifiable delivery.

Both URLs must also outlive the job. If the output URL expires before delivery, the job waits in awaiting_destination — see the lifecycle section.

A created job comes back as the job resource — id, profile, status, billable_seconds, output_bytes, attempt, timestamps, and your tuning echoed back when you sent any.

Surface

Core integration endpoints.

Public endpoints need no key; every other request carries your API key.

02 / Endpoints
  • POST/v1/jobsSubmit a conversion. Returns the job resource.
  • GET/v1/jobsList account jobs; filter by status, profile, key or date; follow next_cursor.
  • POST/v1/jobs/{id}/cancelRequest durable cancellation; returns 200 when canceled or 202 while stopping.
  • GET/v1/usage?period=YYYY-MMUsage, settled costs and promotional totals for a billing period.
  • GET/v1/invoicesInvoice history; limit and cursor pagination.
  • GET/v1/jobs/{id}Read one job.
  • POST/v1/jobs/{id}/destinationSupply a fresh output URL when the first expired.
  • POST/v1/webhooksSet the default completion callback and its secret.
  • GET/v1/job-optionsThis account’s enabled capabilities, profiles and limits.
  • GET/v1/profilesList profiles and the tuning fields each accepts. · public
  • GET/v1/tuningThe tuning schema — every field, type and range. · public
  • GET/v1/statusAggregate API, queue and recently observed worker status. · public
  • GET/v1/openapi.yamlComplete OpenAPI 3.1 contract for every registered route. · public
  • GET/healthzLiveness. · public

List, cancel, usage and per-job costs

GET /v1/jobs supports status (including comma-separated or repeated values), profile, key_id, since, until, limit and cursor. Dates use RFC 3339. Results sort by creation time, newest first; carry the same filters when following next_cursor.

POST /v1/jobs/{id}/cancel returns 200 for completed cancellation or 202 while a worker stops. Read the job until its terminal state. Cancellation does not make already delivered outputs disappear.

GET /v1/usage?period=YYYY-MM returns billable jobs, output bytes, profile totals, charge breakdowns and separate promotional usage. It distinguishes accruing, settlement-pending, settled and metered seconds. Historical periods without priced charge lines return amount_microdollars: null.

POST /v1/jobs/quote validates a scalar or ladder request and returns its reservation quote without creating a job or reserving funds. It accepts the same tuning as job creation; quote composite output groups separately.

GET /v1/jobs/{id} returns quote (reservation ceilings), usage_breakdown (measured charge lines after settlement) and pricing_version (the frozen accepted price book). Each line identifies its kind, seconds, rate, amount in microdollars and output index where relevant. An absent measured breakdown means it has not settled; use provider invoices for the final bill.

The complete OpenAPI contract also documents account, billing, keys, source inspection, outputs, playback and webhook administration routes. Browser sessions require CSRF on writes; API keys use bearer or X-API-Key authentication.

GET /v1/status is public and aggregate only. Worker counts mean authenticated requests recently observed at this gateway, by granted file/ladder/progressive class; a worker can appear in several classes. Counts reset on gateway restart. Queue accepting means storage reachable, not that every account or format is eligible.

Control

Per-request tuning.

Omit tuning or send {} for the published profile; both produce byte-identical output. Out-of-range values return invalid_tuning with the field name and are never silently clamped.

03 / Tuning
# Same job, steered: a filmic curve, local contrast restored,
# and the delivery grade disabled.
curl -X POST "https://silken.io/v1/jobs" \
  -H "Authorization: Bearer $SILKEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile":    "hdr_to_sdr_1080p",
    "input_url":  "…",
    "output_url": "…",
    "tuning": {
      "tone": {
        "method":          "hable",
        "gamut":           "perceptual",
        "local_contrast":  0.6,
        "chroma_recovery": "capped",
        "chroma_strength": 0.35
      },
      "grade":  false,
      "dither": "tpdf",
      "crf":    20
    }
  }'

tuning.tone.highlight_detail: true enables optional Highlight detail for HDR-to-SDR outputs. It keeps more texture in bright highlights and adds 10% of the base output-minute rate, before speed and volume discounts. Omit it for the unchanged default. Standard and Fast only. It requires the reference look and auto or luma_hermite method; other looks, local contrast, chroma recovery, grade references, SDR profiles and the metadata/supplied-SDR grade routes reject it. Sources must be PQ/HLG YUV at 10 bits or above; RGB and dynamic-metadata profile 5 inputs are refused after source inspection. With the enhancement enabled, HLG uses reference method 11 rather than default method 12. For ladders, set it under each rendition’s tuning; native ladders require matching values. Jobs echo the setting and itemise highlight_detail in quotes and usage. Enhanced jobs wait for a worker whose engine qualified the option.

To keep HDR10 or HLG, request hdr_1080p_hevc or hdr_4k_hevc in a VOD ladder alongside SDR versions. The HEVC Main10 versions retain the source transfer, BT.2020 colour and static mastering/light-level metadata. Each version has its own VIDEO-RANGE and codec in the HLS master. HDR versions use the HEVC +50% output price, with no extra HDR fee. Standard and Fast only; SDR sources are refused by name. Availability follows the worker’s HDR render qualification.

Tone controls HDR→SDR profiles; applicability is validated against the source

Field
Accepts
What it does
tone.highlight_detail
true · false
Highlight detail keeps more texture in bright highlights. Optional, off by default; adds 10% of the base rate per tone-mapped output minute before speed and volume discounts. Standard and Fast only. Requires the reference look; incompatible tone overrides and grade references are rejected. PQ/HLG YUV sources only; RGB and unsupported source layouts are refused after inspection.
tone.style
natural · reference · bright · vivid · cinematic
The look. reference (the default) maps light the way colourists grade SDR from HDR: mid-tones independent of the mastering metadata, colorimetric chroma, closest to colourist grades in our tests. natural is the previous standard mapping (with the delivery grade); setting knee or black_point without a style selects it. bright is slightly lighter; vivid is 1.2x chroma; cinematic is darker and muted. Fine-tune with tone.exposure and tone.saturation.
tone.exposure
-2 – 2
Exposure offset in stops applied on top of the style. Positive is brighter mid-tones. 0 is off.
tone.saturation
0 – 2
Saturation multiplier applied on top of the style. 1 is off.
tone.method
auto · luma_hermite · hable · ictcp · max_channel
Tone curve. auto picks the BT.2390 luma-Hermite path, or the authored curve when the source carries one.
tone.gamut
clip · perceptual · desaturate
How BT.2020 colour outside BT.709 is handled: hard clip, perceptual compression, or desaturation toward luma.
tone.knee
0 – 2
Where the highlight shoulder starts. 0 keeps the spec default.
tone.black_point
0 – 0.5
Shadow-toe adaptation applied inside the tone curve. 0 disables it.
tone.peak
metadata · dynamic
Where the source peak comes from: the file's own metadata, or measured per frame.
tone.local_contrast
0 – 2
Local-contrast restore strength. 0 is off; a global curve flattens fine detail and this puts it back.
tone.chroma_recovery
off · boost · capped
Saturation restore for colour dulled by the luma curve. capped bounds it to the gamut hull.
tone.chroma_strength
0 – 1
Strength of that restore. Requires tone.chroma_recovery.
dither
off · ordered · tpdf
Dither applied on the way down to 8-bit. tpdf is the default. Compare the result on your own footage and target screens.
grade
true · false
Our delivery grade: shadow remap, skin-band chroma ease and highlight separation. On by default with tone.style natural only; set true to add it to another look, false to drop it.

Output controls all profiles

Field
Accepts
What it does
width
16 – 7680
Output width override. Even numbers only.
height
16 – 7680
Output height override. Even numbers only.
crf
0 – 63
Encoder quality. Lower is bigger and better.
preset
ultrafast · superfast · veryfast · faster · fast · medium · slow · slower · veryslow · 0 · 1 · 2 · 3 · 4 · 5 · 6 · 7 · 8 · 9 · 10 · 11 · 12 · 13
Encoder speed/size trade-off. Preset words for H.264, numbers for AV1.
max_bitrate_kbps
100 – 100000
Video bitrate ceiling in kbit/s on top of crf (capped CRF, two-second buffer). H.264 profiles only.

Sending a tone control with a profile that does not tone-map is an error rather than a no-op, so you never believe a setting took effect when it could not.

Machine-readable

Discover current profiles and capabilities.

The API serves the same schema so settings UIs can follow added controls.

04 / Discovery
# Every accepted field, its type, its range, and whether it needs a
# tone-mapping profile. Build a settings UI from this instead of
# hard-coding the list.
curl "https://silken.io/v1/tuning"

# Which fields a given profile will accept:
curl "https://silken.io/v1/profiles"

GET /v1/job-options is authoritative for your account’s profiles, rendition count and currently qualified workers. Output records carry expiry. A capability in the implementation matrix is usable only when advertised as available. HEVC/AAC MP4 and VP9/Opus WebM file recipes, HLS/DASH packaging, caption conversion, multi-audio, watermarking and loudness normalisation all depend on live admission.

Use audio.loudness.standard with ebu_r128 (-23 LUFS) or atsc_a85 (-24 LUFS), and optional audio.loudness.true_peak_dbtp, only where admitted. DRM uses SPEKE v2 and CENC cbcs; production admission was unavailable on 15 October 2026. See capabilities.

Economy: native API only, SDR H.264 + AAC, MP4/HLS through 1080p. No HDR conversion, captions, DRM or progressive delivery. Standard and Fast support admitted advanced features and the 99.5% public SLA; an order form can select 99.9%.

Posters, thumbnails and scrub previews

Add thumbnails to a file or VOD ladder request. Select JPEGs with times: [0, 12.5, 30] or interval: 10, and set width and height (defaults 320 × 180). Stills preserve the rendered picture's aspect inside that box. Times refer to the output timeline and must be before its end.

"thumbnails": { "interval": 10, "width": 320, "height": 180, "sprite": true }

sprite: true adds paged 5 × 5 JPEG sheets and thumbnails/scrub.vtt. Each cue references a sheet's #xywh region for player scrub previews. Clear native VOD ladders also accept iframes: true, which adds an HLS I-frame playlist and its master reference.

Completed jobs and signed webhooks list every preview_assets member with its path, kind, image dimensions and download URL. Ladder previews travel with the video package to your destination, or its hosted origin. File JPEGs and sprites use authenticated hosted downloads for seven days; the video still goes to your file destination.

Preview output is included, with no additional charge line. Check matrix.capabilities[id=thumbnails_sprites].available in live job options before offering it. Standard and Fast support previews when an enabled worker qualifies for the requested delivery mode. Economy excludes the additional image decoding work; progressive delivery and encrypted preview output are refused. The API schema publishes accepted image sizes and sample counts.

Completion

Signed webhooks.

Each delivery has Silken-Signature: t=<unix-seconds>,v1=<hex>, an HMAC-SHA256 of "<t>.<raw body>" keyed with the webhook secret. Check timestamp freshness and compare the digest in constant time.

05 / Webhooks
import crypto from "node:crypto"

// Header:  Silken-Signature: t=<unix-seconds>,v1=<hex>
// Signed:  HMAC-SHA256(secret, `${t}.${rawBody}`)
//
// Body, verbatim:
// { "job_id": "job_…", "status": "completed", "profile": "hdr_to_sdr_1080p",
//   "billable_minutes": 12.4, "output_bytes": 418293114, "timestamp": 1756800000 }
//
// billable_minutes is the DURATION of the output, measured before your free
// allowance — not an amount owed. A job inside the free tier still reports a
// positive number. Record it; bill from your invoice.
app.post("/hooks/silken", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("Silken-Signature") || ""
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")))
  const t = Number(parts.t)

  // Reject anything older than five minutes, so a captured call can't be replayed.
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(401)

  const expected = crypto
    .createHmac("sha256", process.env.SILKEN_WEBHOOK_SECRET)
    .update(`${t}.`)
    .update(req.body)
    .digest("hex")

  const got = Buffer.from(parts.v1 || "", "hex")
  const want = Buffer.from(expected, "hex")
  if (got.length !== want.length || !crypto.timingSafeEqual(got, want)) {
    return res.sendStatus(401)
  }

  const event = JSON.parse(req.body)
  if (event.status === "completed") {
    // The output is already in your bucket, at the output_url you presigned.
    // The minutes are how long that output is, not what it cost.
    recordOutputMinutes(event.job_id, event.billable_minutes)
  }
  res.sendStatus(200)
})

billable_minutes is the duration of the output we delivered, measured before your free allowance is applied. A job covered entirely by the allowance still reports a positive number and still costs nothing, so it is a figure to record against the job — not an amount to charge anyone. What you owe is on your invoice.

What status can be delivery statuses

The status on a delivery is its own set. Three values are sent, and only two of them (completed and failed) appear in the job lifecycle table below under the same name.

status
What it means
completed
The output was delivered to your destination and metered. Carries an event_id.
destination_expired
The output is ready but the destination you gave has expired, and the job is waiting for a replacement. One per renewal deadline, each with its own event_id.
failed
The job will not finish. The body carries the reason as `error`, in the same words the dashboard shows the customer. Sent as the job ends, so it carries no event_id.

Correlate on job_id, deduplicate on event_id. They are not the same key: one job can send a destination_expired for every renewal deadline it passes and then a completed, each with its own event_id, while a retry of one event repeats its event_id unchanged. The two statuses sent as the job ends carry no event_id at all.

Delivery and retries when your endpoint is down

The sender's contract, so you can size your handler against it rather than discover it in production. A slow endpoint is retried; one that answers 400 is not.

Rule
What the sender does
Attempts
5
Backoff
starts at 500 ms, doubles each attempt
Success
any status below 300
Stops retrying
any 4xx except 429 — we treat it as a rejection, not an outage
Keeps retrying
429, 5xx and transport errors, until the attempts are spent
Redirects
followed to 5 hops, each re-checked against the destination guard
Signature
Silken-Signature: t=<unix>,v1=<hex>, HMAC-SHA256 over "<t>.<raw body>"

Retry timing includes the time each request takes as well as the backoff, and depends on the delivery path, so an endpoint that is down for a deploy may miss the event. Reconcile job state through GET /v1/jobs/{id}; do not rely on a single callback.

What a job does

Scalar file-job lifecycle.

These states describe a standalone file-delivery job, which is durable once admitted. Progressive and complete-file ladder outputs report their own publication and settlement state.

06 / Lifecycle
State
What it means
queued
Accepted and waiting for a worker. Also where a job returns after a retry or a destination replacement.
processing
A worker holds the lease and is downloading, converting or encoding.
uploading
Converted; writing to your presigned PUT URL.
verifying
The upload’s outcome was uncertain; checking that the object is present, with the expected size, at your verification URL.
uploaded
Delivered. Awaiting the finalize step that meters it and fires the webhook.
finalizing
Metering and webhook delivery in progress.
awaiting_destination
The output could not be confirmed at the URL you gave us. Supply a fresh one — see below.
needs_finalize
Legacy and transient. Nothing silken runs writes this any more; a worker binary left over from a rolling deploy still can, and the current worker claims such a job and drives it to a terminal state by itself within one lease TTL. Keep polling it and expect completed or failed. Nothing is asked of you.
completed
Delivered, metered, webhook sent.
failed
Terminal. A failed file-delivery job records no conversion usage.

When the output URL expires the case people hit

Presigned URLs have a lifetime, and a long job can outlive one. If an upload’s outcome is uncertain and we cannot confirm the object at the URL you gave us, the job moves to awaiting_destination rather than failing, and waits up to 24 hours for a replacement:

  • Send POST /v1/jobs/{id}/destination with a fresh output_url and verify_url. Both are required, and both are re-checked against the destination guard.
  • The job returns to queued and re-renders from the source. We do not keep the previous scratch output, so nothing is resumed from a temporary file we cannot prove still exists.
  • Wrong state gives 409 invalid_job_state; another customer's job gives 404.
  • If the 24 hours elapse, the job fails, and it is still never billed. The error says so in full: that silken transcoded the job but could not deliver the output, that the destination you supplied was no longer usable, that no replacement arrived before the deadline, and that the job is not billed. Resubmit with a destination that will outlive the transcode.

Keep both URLs valid for the job's processing window, and prefer a longer expiry on the PUT than you think you need.

Limits and retries

Limits are set per account.

Request rate, concurrency and job size are agreed per account. GET /v1/job-options returns the values that apply to yours.

07 / Limits

Retries

  • Transient failures — download, conversion, probing — requeue up to 3 attempts with no added delay; the worker picks the job straight back up.
  • Permanent failures fail on the first hit: an unknown profile, a source whose readable duration exceeds the job’s admitted maximum, an output longer than that maximum, or a destination URL the guard rejects outright. If a source’s duration cannot be read, the conversion bound still applies; validate the resulting file.
  • Finalizing — metering and webhook — has its own budget of 10 attempts with backoff doubling from 1 second to a 1-hour cap. Exhausting it fails the job, and never charges for it. The error says what that means: the transcode ran and the output WAS delivered to your destination, and it is silken's own completion bookkeeping that did not finish. Check your destination before resubmitting — the file should already be there.
  • A dead worker loses its lease after 5 minutes. The job is reclaimed and resumes from its last durable state rather than starting over, and every write is fenced on a lease epoch so a revived worker cannot overwrite newer state.
Billing mechanics

Metered on delivered output.

Delivered file duration, not source or wall time.

08 / Billing
  • The measurement is the duration of the output file, probed after it is written.
  • Duration is measured separately from charges. A 2.5-second output meters 2.5 seconds. There is no per-job floor.
  • What reaches your invoice can round, depending on how you buy. On a card subscription output charges are rounded up to microdollars, then summed by one money meter. If you buy through AWS Marketplace, which accepts only whole units, your charges on the same rate card are accumulated per UTC hour and the hour's total is rounded up to a whole unit of $0.00001 — once for the hour, not once per job, so an hour is never more than $0.00001 above its exact charge. Terms §08 sets out both.
  • A failed file-delivery job records no conversion usage. Progressive jobs can accrue usage for the published portion even if they later fail. Complete-file ladders charge for successful delivered renditions, including those in a partially completed job. Check the job’s recorded usage. The ledger row is keyed by job id, so a retry cannot double-charge.
  • The free tier is 1,000 output minutes per customer each calendar month, for standard SDR H.264 outputs at up to 30 fps, applied automatically. Tone mapping is included. Eligible Economy and Standard SDR H.264 output uses the allowance; HEVC, VP9, AV1, high-frame-rate and Fast output remains chargeable. The period is the UTC calendar month; a new month starts a new allowance. Billing must be set up before your own jobs are accepted (402 billing_required); the allowance then comes off first.
  • Prices charge delivered output minutes only, with no input fee. The configured price book publishes SD, HD and UHD tiers, additive codec/frame-rate extras, and Economy, Standard and Fast speed multipliers. The rate and version recorded when a job is accepted govern silken’s usage ledger and spend calculations; silken calculates settled charges; your payment provider bills them. View the price book.
Formats

Profiles define conversion.

Every HDR source, HDR10 or HLG, goes through the tone curve, and the tone controls apply to it. SDR profiles downscale without one. Every job names a profile that specifies the codec.

09 / Profiles
Profile
Output
Codecs
hdr_to_sdr_4k
Source size, SDR · tone-mapped
H.264 + AAC in mp4, CRF 20
hdr_to_sdr_1080p
1080p SDR · tone-mapped
H.264 + AAC in mp4, CRF 21
hdr_to_sdr_4k_av1
Source size, SDR · tone-mapped
AV1 (SVT) + Opus in mp4, CRF 22
hdr_to_sdr_1080p_av1
1080p SDR · tone-mapped
AV1 (SVT) + Opus in mp4, CRF 23
sdr_1080p
1080p SDR
H.264 + AAC in mp4, CRF 21
sdr_1080p_av1
1080p SDR
AV1 (SVT) + Opus in mp4, CRF 23
sdr_720p
720p SDR
H.264 + AAC in mp4, CRF 22
sdr_720p_av1
720p SDR
AV1 (SVT) + Opus in mp4, CRF 28

Width, height, CRF and preset are all overridable per job through tuning, so a profile is a starting point rather than a fixed SKU.

Optional hosted outputs

The number of renditions a self-serve ladder may have is set per account and listed in job options. Progressive SDR playback requires live admission. Check GET /v1/job-options for the modes available to your account before choosing this workflow. If capability discovery is unavailable, retry it before choosing a hosted output mode; keep the selection you made and treat readiness as unknown. Billing and capacity still apply at admission.

One progressive SDR rendition

curl "$SILKEN_ORIGIN/v1/jobs" -H "Authorization: Bearer $SILKEN_KEY" -H 'Content-Type: application/json' -H 'Idempotency-Key: progressive-example-1' --data '{"input_url":"https://source/clip.mp4","profile":"sdr_720p","max_output_seconds":60,"output":{"mode":"hls_fmp4_v1"}}'

Requires an eligible enabled account and a positive duration within the ceiling GET /v1/job-options reports for your account. Do not include destination URLs, tuning or durability overrides. Poll GET /v1/jobs/{id}. Resolve publication.manifest_url against the API origin. Use native HLS or hls.js; the dashboard supports both. A manifest is a read capability: keep it secret and respect expires_at.

{"output_mode":"hls_fmp4_v1","status":"processing","publication":{"publication_state":"open","revision":2,"published_seconds":4,"expected_seconds":60,"billing_state":"accruing"}}

Playback may begin before completion. Signed job.output_ready, job.output_progress and terminal webhooks carry the same publication snapshot. Deduplicate events and accept only increasing revisions within each asset generation. A late ready event cannot replace a newer terminal snapshot. ENDLIST means closed, including partial output; inspect coverage and terminal reason.

Multiple completed outputs

curl "$SILKEN_ORIGIN/v1/jobs" -H "Authorization: Bearer $SILKEN_KEY" -H 'Content-Type: application/json' -H 'Idempotency-Key: ladder-example-1' --data '{"input_url":"https://source/clip.mp4","max_output_seconds":60,"renditions":[{"key":"1080p","profile":"sdr_1080p"},{"key":"720p","profile":"sdr_720p"}]}'

Use at least two unique nonempty keys, within the key-length limit and no more rungs than GET /v1/job-options reports for your account. A ladder has one bounded common duration; each rung may have supported tuning. Set destination to an s3://bucket/prefix/ for a native VOD package delivered to registered S3 (IAM role), R2, B2 or Wasabi storage. Omit it for seven-day hosted retention by default. Do not combine renditions with scalar profile, output_url, top-level tuning, durability or output. The first rung is the anchor and must have the highest standalone rate. HDR choices appear only when advertised.

Status and terminal webhooks expose kind: "ladder" and ladder.renditions[]: key, profile, status, error, duration_us, bytes, rate_class, microdollars_per_minute and output_url. Downloads require account authentication and appear after settlement; successful outputs from partial jobs remain usable. Without a destination, complete-file ladder results are held for seven days by default after settlement, subject to your account’s retention; progressive output expires seven days after the stream closes.

One two-rung job is one parent job and two successful outputs. Rates are configured quotes, retained by pricing version and rung class; no fixed ladder prices or savings are promised here. Reserve every output at its maximum supported rate; there is no source charge. Usage reports settled charges from frozen rates; historical periods without priced lines show cost unavailable. Usage distinguishes accruing, settlement-pending, settled and metered seconds. Charges follow published output and recorded metered usage, never viewer watch time; provider invoices are authoritative.

Failure modes

Errors identify the field.

The conversion endpoints use { "error": "…", "code": "…" }; contact and meeting endpoints return their own validation responses. Retry 429 and 5xx after the Retry-After delay when one is sent; fix the request for other 4xx codes.

10 / Errors
Code
Status
Meaning
missing_api_key / invalid_api_key
401
No key was sent, or the key is unknown or revoked. Send Authorization: Bearer <key> or X-API-Key.
billing_required
402
Billing must be set up before your own jobs are accepted.
spend_cap_exceeded
402
The account’s monthly spend cap is reached, when one is set.
concurrency_limit
429
Too many jobs in flight for the account. Wait for one to finish and resubmit.
rate_limited
429
Too many requests. Wait the number of seconds in the Retry-After header, then retry.
unknown_profile
400
No such profile. GET /v1/profiles lists them.
invalid_tuning
400
A tuning field is out of range, not a known value, or not applicable to the profile. The message names the field, e.g. tuning.tone.knee: must be between 0 and 2.
missing_url
400
An ordinary file-delivery submission requires both input_url and output_url.
invalid_input_url / invalid_output_url
400
The URL failed the destination guard.
verification_unavailable
400
Neither verify_url nor a readable output_url was supplied, and the job asked for durability: "verified". Send a verify_url, or ask for durability: "best_effort".
invalid_job_state
409
The job is not awaiting a destination.
not_found
404
No such job for this key.
MediaConvert compatibility

Point your AWS client at silken.

Use https://silken.io as the endpoint override. This implements a defined subset of the MediaConvert REST API, not every AWS setting. Check your job file before switching a workflow.

11 / Compatibility

Authentication and endpoint discovery

Sign with AWS SigV4: service mediaconvert, region us-east-1. Use your silken API key as both the AWS access key ID and secret access key. Both are secrets. Do not use AWS IAM credentials or a session token for this client. Bucket credentials are separate. Requests must sign the host and date; keep your clock accurate. DescribeEndpoints is supported for clients that discover an endpoint first.

import os, boto3
key = os.environ['SILKEN_API_KEY']
mc = boto3.client('mediaconvert',
    endpoint_url='https://silken.io', region_name='us-east-1',
    aws_access_key_id=key, aws_secret_access_key=key)
print(mc.describe_endpoints()['Endpoints'])
# Supply a supported job to mc.create_job(**job).
# Complete runnable examples: examples/python and examples/go.
# Use a dedicated profile; do not overwrite your bucket credentials.
AWS_ACCESS_KEY_ID="$SILKEN_API_KEY" \
AWS_SECRET_ACCESS_KEY="$SILKEN_API_KEY" \
AWS_SESSION_TOKEN= AWS_SECURITY_TOKEN= \
aws mediaconvert describe-endpoints \
  --region us-east-1 --endpoint-url https://silken.io

With aws-sdk-go-v2, set mediaconvert.Options.BaseEndpoint = aws.String("https://silken.io") and credentials.NewStaticCredentialsProvider(key, key, ""), with region us-east-1. Python and Go runnable samples include native and MediaConvert submissions.

OperationRouteContract
DescribeEndpointsPOST /2017-08-29/endpointsReturns https://silken.io; DEFAULT and GET_ONLY both return the configured endpoint.
CreateJobPOST /2017-08-29/jobsSupported settings only; ClientRequestToken provides idempotency. Returns job with SUBMITTED status.
GetJobGET /2017-08-29/jobs/{id}Account-scoped job status, output details and safe error; source URL settings are redacted on reads.
ListJobsGET /2017-08-29/jobsmaxResults, nextToken, status, Default queue, DESCENDING order. Filters apply within each page; follow nextToken even when a page is empty.
SearchJobsGET /2017-08-29/searchList filters plus exact inputFile.
CancelJobDELETE /2017-08-29/jobs/{id}Native cancellation, including composite output groups; success is an empty object.
Presets/2017-08-29/presets[/{name}]List/Get/Create/Update/Delete custom account-owned presets; no AWS system preset catalog.
Job templates/2017-08-29/jobTemplates[/{name}]List/Get/Create/Update/Delete custom templates. Settings overrides merge at submission.
Queues/2017-08-29/queues[/{name}]List/Get Default, with standard list paging/sort arguments; CreateQueue accepts Default only. Queue updates, deletes and custom queues are refused.

Catalog lists use listBy=NAME, order=ASCENDING, maxResults and nextToken. Create uses POST on the collection; get/update/delete use GET/PUT/DELETE on the named resource. Dates use epoch seconds. silken statuses map to SUBMITTED, PROGRESSING, COMPLETE, ERROR and CANCELED. Unsupported operations return an AWS-shaped error, not an empty success.

Source and destination access

For the presigned path, FileInput is a full HTTPS GET URL. A single MP4 FILE group’s Destination is a full presigned HTTPS PUT URL for one object, not a bucket prefix. The adapter chooses durability: "best_effort"; it cannot obtain a separate verification URL from a standard MediaConvert job file. To check delivery explicitly, use the native API with durability: "verified" and verify_url.

Native HLS/CMAF ladders accept Destination: "s3://bucket/prefix/". Register your account role, then grant s3:PutObject, s3:AbortMultipartUpload, s3:GetObject and s3:GetBucketLocation for delivery and HEAD verification. silken appends the job ID to the prefix. Segments publish first, media playlists next, master last; every object is HEAD-verified. Billing stays unchanged.

Native API example: {"input_url":"s3://bucket/source.mp4","destination":"s3://bucket/vod/", "max_output_seconds":60,"renditions":[{"key":"large","profile":"sdr_1080p"},{"key":"small","profile":"sdr_720p"}]}. Returned ladder.master_url and rendition URLs name your S3 objects. Omit destination for authenticated downloads, retained seven days after completion by default. PUT /v1/settings/output-retention with {"days":7} sets account retention (1–30 days) for later completions. Expired held objects are deleted; customer bucket objects remain yours.

Registered role access for S3 sources and destinations

Initialize PUT /v1/settings/s3-input-role with an empty object to get your account’s ExternalId. Grant silken’s onboarding-supplied AWS principal access through a role trust policy requiring that exact ExternalId, then register role_arn and a probe_uri. Set the job’s Role to that registered ARN. Temporary credentials renew in memory. Large objects use multipart delivery.

For R2, Backblaze B2 and Wasabi, register endpoint (HTTPS), region, probe_uri, access_key_id and secret_access_key instead of role_arn. R2 uses region auto; B2 and Wasabi use the region matching the bucket endpoint. Grant a dedicated key read/HEAD, write and multipart-abort access to the intended bucket/prefix. Keys stay in private account storage; settings responses and workers never receive them. The same destination field and verified publication order apply.

SPEKE v2 DRM for CMAF

Production admission was unavailable on 15 October 2026. The contract below describes implemented SPEKE v2 / CENC cbcs packaging; use it only when your live GET /v1/job-options advertises DRM as available.

Register an HTTPS key server with POST /v1/drm-provider, using url and a complete Basic or Bearer authorization value. Credentials are private account data; reads return only whether authentication is configured.

Native VOD ladders accept drm: { content_id, systems, key_period }. The optional hls_system_ids and dash_system_ids select manifest signalling; by default HLS includes all requested systems and DASH excludes FairPlay. Supported systems are FairPlay, Widevine and PlayReady. Each rendition and shared AAC audio receive distinct key IDs. One immutable content-key period covers the complete VOD package. HLS uses SAMPLE-AES, key-provider SKD or data URIs and session keys; DASH carries cbcs ContentProtection and PSSH. Subtitle tracks stay clear. DRM adds 25% of the output base price to encrypted versions; source and clear versions receive no DRM charge.

MediaConvert CMAF groups accept encryption.type=SPEKE, encryption.encryptionMethod=SAMPLE_AES and the spekeKeyProvider object (AWS type SpekeKeyProviderCmaf). Supply encryptionContractConfiguration with PRESET_VIDEO_1 and PRESET_AUDIO_1: these share one video key and use a separate audio key. HLS and DASH system ID arrays are independent: FairPlay belongs in HLS; Widevine and PlayReady can be signalled in either manifest. The provider URL must match the account registration.

Requires a pinned engine with DRM qualification and an explicit worker grant for the hls2_cbcs_v1 pipeline. Older workers cannot claim encrypted jobs. H.264/AAC VOD ladders only. SPEKE v1, wrapped keys/certificates, other encryption presets, AES-CTR, TS DRM, custom audio variants and live rotation are refused by name. Vendor license playback is configured with your provider.

Check your job file

POST /v1/mediaconvert/validate accepts the same job JSON with native bearer authentication. It returns every field/schema refusal and the first value or group refusal from the admission translator. A supported field means it is recognized; the whole job must have valid: true. Validation creates no job, reserves no funds, and fetches no media. Source inspection, permissions and account admission still run at submission.

curl https://silken.io/v1/mediaconvert/validate \
  -H "Authorization: Bearer $SILKEN_API_KEY" \
  -H "Content-Type: application/json" --data-binary @job.json

The check sends this JSON, including any presigned URLs, to silken. This form keeps your key and file in memory only.

Supported settings matrix

Generated from the translator’s own schemas, including audio and caption selectors. The existing coverage test checks this page’s generated rows against code. The deployed revision’s table is also available at GET /v1/mediaconvert/settings. “Supported” remains conditional on values, output groups, engine qualification and account capabilities. No unsupported field is silently discarded.

SettingVerdictHandling
CreateJob.* (unlisted fields at any depth)rejectedClosed allowlist: every unknown field is rejected with its submitted JSON path. CMAF SPEKE v2 supports SAMPLE_AES and PRESET_VIDEO_1/PRESET_AUDIO_1; other encryption variants, userMetadata and unlisted codec settings are not accepted.
CreateJob.clientRequestTokensupportedNative idempotency key, in a separate MediaConvert namespace.
CreateJob.jobTemplatesupportedExpanded from the account's saved catalog; explicit settings override saved fields.
CreateJob.prioritysupportedInteger -50..50. Omitted/zero uses Standard; 1..50 buys Fast. Negative values select Economy, which rejects MediaConvert-compatible jobs; use Standard. Default queue identity is unchanged.
CreateJob.queuesupportedDefault or its AWS ARN only; other queues rejected.
CreateJob.rolesupportedRequired. HTTPS input: opaque identifier echoed on create. S3 input: must match the account's registered input role.
CreateJob.settings.inputs[].audioSelectors.*.languageCodesupportedTRACK (one track, stereo pair or six stems) or LANGUAGE_CODE. Every selector must be used.
CreateJob.settings.inputs[].audioSelectors.*.selectorTypesupportedTRACK (one track, stereo pair or six stems) or LANGUAGE_CODE. Every selector must be used.
CreateJob.settings.inputs[].audioSelectors.*.tracks[]supportedTRACK (one track, stereo pair or six stems) or LANGUAGE_CODE. Every selector must be used.
CreateJob.settings.inputs[].captionSelectors.*.sourceSettings.embeddedSourceSettings.source608ChannelNumbersupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.inputs[].captionSelectors.*.sourceSettings.fileSourceSettings.sourceFilesupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.inputs[].captionSelectors.*.sourceSettings.sourceTypesupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.inputs[].fileInputsupportedHTTPS GET or S3 URI under the registered account input role; source is not fetched by validation.
CreateJob.settings.outputGroups[].nameignoredSingle group: display label ignored. Composite jobs: maps to the output group name; does not name destination objects.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.destinationsupportedSingle FILE output: complete presigned HTTPS PUT URL. Native HLS/CMAF ladders accept an s3:// prefix using the registered account role; omit destination for expiring authenticated downloads.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.encryptionMethodsupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.dashSignaledSystemIds[]supportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.encryptionContractConfiguration.spekeAudioPresetsupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.encryptionContractConfiguration.spekeVideoPresetsupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.hlsSignaledSystemIds[]supportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.resourceIdsupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.spekeKeyProvider.urlsupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.cmafGroupSettings.encryption.typesupportedCMAF VOD ladder only: SPEKE v2, SAMPLE_AES/cbcs, PRESET_VIDEO_1/PRESET_AUDIO_1, independent HLS/DASH DRM sets and an account-registered HTTPS key provider. Other variants rejected by name.
CreateJob.settings.outputGroups[].outputGroupSettings.fileGroupSettings.destinationsupportedSingle FILE output: complete presigned HTTPS PUT URL. Native HLS/CMAF ladders accept an s3:// prefix using the registered account role; omit destination for expiring authenticated downloads.
CreateJob.settings.outputGroups[].outputGroupSettings.hlsGroupSettings.destinationsupportedSingle FILE output: complete presigned HTTPS PUT URL. Native HLS/CMAF ladders accept an s3:// prefix using the registered account role; omit destination for expiring authenticated downloads.
CreateJob.settings.outputGroups[].outputGroupSettings.typesupportedFILE_GROUP_SETTINGS, HLS_GROUP_SETTINGS or CMAF_GROUP_SETTINGS; native delivery requires qualification.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioNormalizationSettings.algorithmsupportedJob-wide gated BS.1770 correction; target -23, -24 or -27 LKFS. All outputs must agree.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioNormalizationSettings.algorithmControlsupportedJob-wide gated BS.1770 correction; target -23, -24 or -27 LKFS. All outputs must agree.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioNormalizationSettings.targetLkfssupportedJob-wide gated BS.1770 correction; target -23, -24 or -27 LKFS. All outputs must agree.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioNormalizationSettings.truePeakLimiterThresholdsupportedJob-wide gated BS.1770 correction; target -23, -24 or -27 LKFS. All outputs must agree.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioSourceNamesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioTypesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].audioTypeControlsupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].codecSettings.aacSettings.codingModesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].codecSettings.codecsupportedAAC, optionally paired with EAC3 for every selected mix; account/engine qualification applies.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].codecSettings.eac3Settings.codingModesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].customLanguageCodesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].languageCodesupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].audioDescriptions[].languageCodeControlsupportedSelected language/mix and AAC stereo or EAC3 5.1; audio settings are job-wide and must match all video outputs.
CreateJob.settings.outputGroups[].outputs[].captionDescriptions[].captionSelectorNamesupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.outputGroups[].outputs[].captionDescriptions[].destinationSettings.destinationTypesupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.outputGroups[].outputs[].captionDescriptions[].languageCodesupportedNative HLS VOD ladders only. Sidecar SRT/SCC/TTML/WEBVTT/STL or embedded CC1 to WEBVTT; selectors must be used and match outputs.
CreateJob.settings.outputGroups[].outputs[].captionDescriptions[].languageDescriptionrejectedNon-empty caption labels rejected: engine label overrides are unsupported.
CreateJob.settings.outputGroups[].outputs[].containerSettings.containersupportedMP4 for FILE, M3U8 for HLS, CMFC for CMAF; mismatches rejected.
CreateJob.settings.outputGroups[].outputs[].nameModifiersupportedUnique ladder rendition identifier; non-empty scalar modifiers rejected.
CreateJob.settings.outputGroups[].outputs[].presetsupportedExpanded from the account's saved catalog; explicit settings override saved fields.
CreateJob.settings.outputGroups[].outputs[].videoDescription.codecSettings.codecsupportedH_264 only; other video codecs rejected by name.
CreateJob.settings.outputGroups[].outputs[].videoDescription.codecSettings.h264Settings.maxBitratesupportedCap in bits/second. Native requires whole kbps; legacy rounds up. Single progressive output rejects caps.
CreateJob.settings.outputGroups[].outputs[].videoDescription.codecSettings.h264Settings.rateControlModesupportedLegacy QVBR maps to capped CRF. Native explicit QVBR is unqualified and rejected; CBR/VBR rejected.
CreateJob.settings.outputGroups[].outputs[].videoDescription.heightsupportedEven dimensions mapped to profile/tuning. Single progressive output uses fixed profile dimensions. Account capabilities still apply.
CreateJob.settings.outputGroups[].outputs[].videoDescription.widthsupportedEven dimensions mapped to profile/tuning. Single progressive output uses fixed profile dimensions. Account capabilities still apply.

Named rejection

This payload is asserted by the gateway test using an H.265 request. AWS SDKs read X-Amzn-Errortype and the message as a typed BadRequestException.

HTTP/1.1 400 Bad Request
X-Amzn-Errortype: BadRequestException
Content-Type: application/json

{"message":"unsupported field CreateJob.settings.outputGroups[0].outputs[0].videoDescription.codecSettings.codec: H_265","__type":"BadRequestException"}

Runnable SDK samples

Python and Go samples contain a native job and a MediaConvert job with a real endpoint override. They use SILKEN_API_KEY, default to https://silken.io, and submit only when explicitly passed --submit. Supply your own source, destination and verification URLs.

Download native.py, mediaconvert_job.py, Python requirements, Go source and Go module and Go checksums. The repository keeps the same files in examples/python and examples/go.

export SILKEN_API_KEY='your own key'
python3 native.py --input-url "$INPUT_GET_URL" --output-url "$OUTPUT_PUT_URL" --verify-url "$OUTPUT_VERIFY_URL"
python3 mediaconvert_job.py --input-url "$INPUT_GET_URL" --output-url "$OUTPUT_PUT_URL"
go run . -mode mediaconvert -input-url "$INPUT_GET_URL" -output-url "$OUTPUT_PUT_URL"

Python MediaConvert and Go MediaConvert commands validate by default. Native commands describe the request; add --submit to create billable work after reviewing it.

API changelog

Changes in the API source, with dates from commit history. A source release entry does not claim that every deployment already runs it. Download the deployed gateway’s OpenAPI contract for its current routes.

2026-10-13 — compatibility reference and validation

  • Added a MediaConvert field matrix generated from the admission translator, a job-file validator, and runnable Python and Go examples.
  • Added aggregate GET /v1/status and the embedded contract at GET /v1/openapi.yaml.
  • Documented existing endpoint discovery, account-scoped presets/templates, Default queue operations, list/cancel and usage APIs.
  • MediaConvert reads now represent a job being canceled as PROGRESSING until cancellation finishes. Embedded caption channel selection accepts the integer sent by AWS SDKs. Default queue lists accept standard SDK paging and sort arguments.

2026-10-06

d26ac735: price book v4 added marginal monthly volume pricing. Existing jobs retain their accepted pricing version.

2026-10-01

  • 7241ef94: extended MediaConvert operations and official SDK compatibility coverage.
  • 375d99ce: composite MediaConvert jobs use native output owners.
  • 4e3e0c7c: registered customer-role S3 input access landed.
  • 658a4b56 and 6fdc95d0: native audio track selection and subtitle input/publication contracts.

silken is operated by Velvet Software Limited, registered in Dublin, Ireland (company registration no. 633270), registered office 29 Earlsfort Terrace, Dublin 2, D02 AY28, Ireland.