Reference
Plugin options, environment variables, endpoints, and exports for payload-mux in one place.
Every option, environment variable, endpoint, and export for @pro-laico/payload-mux.
Plugin options
muxPlugin(options?) is the single entry point. One call registers the mux-video collection,
the upload + webhook endpoints, and the admin uploader. It's zero-config: every option falls back to a
MUX_* env var or a sensible default.
Pass options to customize. The plugin's own knobs live under options; the mux-video collection is
reshaped under collections.muxVideo (slug renames it, overrides is the Payload passthrough,
options its own knobs). The Reference tab is the interactive view (each group expands to its
nested fields); TypeScript is the same shape in code, every option at its default.
enabledbooleandefault trueWhen false, the plugin registers nothing: no collection, endpoints, or hooks.
collections{ muxVideo? }
The collections the plugin registers, one key each.
muxVideoCollectionOption<MuxVideoCollectionOptions>
The one collection the plugin registers — always registered, there is no false.
slugstringdefault 'mux-video'Rename it; the plugin follows the new slug everywhere — the webhook's lookup, ingestMuxVideo's default, and the muxVideoSlug on the marker.
overridesOmit<Partial<CollectionConfig>, 'slug'>Payload config merged onto the plugin's by the shared merge rules. Add your own fields under overrides.fields. Rename with the sibling slug key, not here. Don't redeclare a field the plugin injects (muxUploader, source, title, assetId, status, error, duration, posterTimestamp, aspectRatio, maxWidth, maxHeight, playbackOptions) — that's a named boot error.
optionsMuxVideoCollectionOptions
This collection's own knobs.
thumbnail'gif' | 'image' | 'none'default 'gif'List-view thumbnail style: animated gif, static image, or none.
optionsMuxOptions
The plugin's own domain knobs: credentials, upload / playback settings, and the access gates.
initSettingsMuxVideoInitSettingsdefault MUX_* env vars
Mux credentials and secrets. Every field is optional; an omitted field is read from its MUX_* env var (the plugin resolves these itself, which is what lets it accept the alias names below and warn at boot when a credential is missing). Pass a field only to override it (e.g. a non-standard env var name).
tokenIdstringdefault process.env.MUX_TOKEN_IDMux API token ID.
tokenSecretstringdefault process.env.MUX_TOKEN_SECRETMux API token secret.
webhookSecretstringdefault MUX_WEBHOOK_SECRET ?? MUX_WEBHOOK_SIGNING_SECRETSecret used to verify incoming Mux webhooks. Falls back to MUX_WEBHOOK_SIGNING_SECRET (the @oversightstudio/mux-video name) when the first is unset.
jwtSigningKeystringdefault MUX_SIGNING_KEY ?? MUX_JWT_KEY_IDJWT signing key ID, for signed playback. Falls back to MUX_JWT_KEY_ID.
jwtPrivateKeystringdefault MUX_PRIVATE_KEY ?? MUX_JWT_KEYJWT private key, for signed playback. Falls back to MUX_JWT_KEY.
uploadSettingsMuxVideoUploadSettings
Settings applied to every upload.
cors_originstringdefault process.env.NEXT_PUBLIC_SERVER_URL ?? '*'CORS origin for the direct-upload URL, usually your site URL. On POST /mux/upload (the browser uploader) it resolves to options.uploadSettings.cors_origin ?? process.env.NEXT_PUBLIC_SERVER_URL ?? '*'. Server-side ingest never reads the env var: it takes the source's own corsOrigin, then this option, then '*'.
new_asset_settingsMuxVideoNewAssetSettingsExtra new_asset_settings forwarded to Mux when the asset is created. Includes playback_policy; the options.playbackPolicy knob is the shorthand, and an explicit value here wins.
playbackPolicy'public' | 'signed'default 'public'Playback policy for newly uploaded videos. Shorthand for uploadSettings.new_asset_settings.playback_policy; set 'signed' (plus MUX_SIGNING_KEY / MUX_PRIVATE_KEY) for JWT-signed URLs.
accessMuxAccessOptions
Per-endpoint gates for the plugin's HTTP endpoints — one EndpointAccess ((req) => boolean | Promise<boolean>) per endpoint. Collection reads and writes are gated the Payload way, under collections.muxVideo.overrides.access — the collection ships read: authd (any logged-in user). Keep it closed under a signed playback policy: playback URLs are JWT-signed on read, so an anonymous read hands out a working signed URL. See Gating endpoints.
uploadEndpointAccessdefault any logged-in userGates the direct-upload endpoints (POST / GET /mux/upload).
webhookEndpointAccessdefault Mux signature verificationGates POST /mux/webhook. Defaults to verifying the Mux webhook signature; override only if you terminate that check upstream.
refreshEndpointAccessdefault any logged-in userGates GET /mux/refresh, which asks Mux whether a document's asset finished encoding. The admin uploader polls it while a video is preparing, so a doc whose ready webhook never arrived still resolves itself.
signedUrlOptions{ expiration?: string }default { expiration: '1d' }Lifetime of the JWT-signed playback / poster / gif URLs under a signed policy.
posterExtension'webp' | 'jpg' | 'png'default 'png'Image format for the poster (posterUrl).
animatedGifExtension'gif' | 'webp'default 'gif'Format for the animated preview (gifUrl).
autoCreateOnWebhookbooleandefault falseWhen true, the webhook backfills a Payload doc for an asset uploaded directly in Mux (on created / ready / updated for an asset Payload doesn't have yet). Off by default: one Mux account shared across dev / staging / prod would cross-backfill every environment's assets into the others.
import { muxPlugin } from '@pro-laico/payload-mux'
// Every option at its default — this is the zero-config behaviour, written out.
muxPlugin({
enabled: true,
collections: {
muxVideo: {
// slug: 'mux-video', // optional — renames the collection; the plugin follows the rename
// overrides: { /* … */ }, // optional — Payload CollectionConfig keys merged onto the plugin's
options: { thumbnail: 'gif' }, // list-view thumbnail: 'gif' | 'image' | 'none'
},
},
options: {
// initSettings: { /* … */ }, // optional, no default — all fields fall back to MUX_* env vars
// uploadSettings: { /* … */ }, // optional — on POST /mux/upload, cors_origin defaults to process.env.NEXT_PUBLIC_SERVER_URL ?? '*'
// access: { // per-endpoint gates for the plugin's HTTP endpoints
// upload: ({ user }) => Boolean(user), // default: any logged-in user
// webhook: () => true, // default: Mux signature verification — override only if terminated upstream
// },
playbackPolicy: 'public', // 'signed' issues JWT-signed URLs
signedUrlOptions: { expiration: '1d' },
posterExtension: 'png',
animatedGifExtension: 'gif',
autoCreateOnWebhook: false,
},
})Environment variables
The plugin and the Mux SDK read these automatically. Pass the matching initSettings / uploadSettings
option only to override a value or point at a non-standard variable name.
| Variable | Default | What |
|---|---|---|
MUX_TOKEN_ID | — | Mux API token ID. Required. |
MUX_TOKEN_SECRET | — | Mux API token secret. Required. |
MUX_WEBHOOK_SECRET | — | Verifies incoming Mux webhook signatures. Required for the webhook. Also accepts MUX_WEBHOOK_SIGNING_SECRET. |
MUX_SIGNING_KEY | — | JWT signing key ID. Required when playbackPolicy: 'signed'. Also accepts MUX_JWT_KEY_ID. |
MUX_PRIVATE_KEY | — | JWT private key. Required when playbackPolicy: 'signed'. Also accepts MUX_JWT_KEY. |
NEXT_PUBLIC_SERVER_URL | '*' | Your site URL — becomes the cors_origin for the browser upload endpoint (POST /api/mux/upload). Falls back to '*' when unset; server-side ingest doesn't read it. |
Migrating from @oversightstudio/mux-video? Keep your env as-is. The three names above where
the two plugins disagree — MUX_WEBHOOK_SIGNING_SECRET, MUX_JWT_KEY_ID, MUX_JWT_KEY — are
read as fallbacks, so nothing needs renaming. If both names are set, the Mux-SDK name wins.
Endpoints
The plugin registers three endpoints under Payload's API route. The upload pair is gated by
options.access.upload (default any logged-in user) and the webhook by options.access.webhook
(default Mux signature verification) — see Gating endpoints. See
Endpoints & webhooks for the webhook setup and
what breaks without it.
| Endpoint | What it does |
|---|---|
POST /api/mux/upload | Mint a Mux direct-upload. The admin uploader posts files to it. |
GET /api/mux/upload?id=… | Read a direct-upload, to pick up its asset_id. |
GET /api/mux/refresh?id=… | Ask Mux whether that document's asset is done, and write the answer. Only writes when the status actually changed, so polling it is cheap. The admin uploader polls it while a video encodes — which is what makes a missed webhook, or local development Mux can't reach, recover on its own. |
POST /api/mux/webhook | Verify and apply Mux events: set metadata on ready/updated, delete on deleted, mark the doc errored (with the Mux message) on errored, and (with autoCreateOnWebhook) backfill assets uploaded in Mux. |
Exports
| Export | From | What |
|---|---|---|
muxPlugin (default + named) | @pro-laico/payload-mux | The plugin factory. |
muxVideoPlugin | @pro-laico/payload-mux | Deprecated alias for muxPlugin — still exported, slated for removal in an upcoming release. |
MuxVideoPluginOptions | @pro-laico/payload-mux | The plugin options type (for typing a wrapper / shared factory). |
MuxOptions, MuxVideoCollectionOptions | @pro-laico/payload-mux | The nested option groups: the plugin's own domain knobs (options) and the mux-video collection's own knobs (collections.muxVideo.options). |
readMuxMarker | @pro-laico/payload-mux | The typed view of config.custom.payloadMux: { options, muxVideoSlug, uploadPath, webhookPath, refreshPath }. The supported way to discover the managed slug — it follows collections.muxVideo.slug. Returns undefined when the plugin isn't registered. |
PayloadMuxMarker | @pro-laico/payload-mux | The marker's type. |
ingestMuxVideo | @pro-laico/payload-mux | Create a video doc from a local file / URL (seeding, imports, migrations). collection defaults to the slug on the marker, so a renamed collection needs no argument. |
IngestMuxVideoOptions | @pro-laico/payload-mux | Options for ingestMuxVideo: { source, title, playbackPolicy?, posterTimestamp?, collection? }. |
MuxAccessOptions | @pro-laico/payload-mux | The options.access gate-map shape: { upload?, webhook?, refresh? }. |
EndpointAccess | @pro-laico/payload-mux | The endpoint-gate function type (req) => boolean | Promise<boolean>; see Gating endpoints. |
MuxVideoInitSettings, MuxVideoUploadSettings, MuxVideoNewAssetSettings, MuxVideoSignedUrlOptions | @pro-laico/payload-mux | The nested settings types. |
MuxPlaybackPolicy, MuxPosterExtension, MuxAnimatedGifExtension, MuxAdminThumbnail | @pro-laico/payload-mux | The option value unions. |
MuxUploaderField | @pro-laico/payload-mux/components/MuxUploaderField | Admin uploader + player field (wired via the import map). |
MuxVideoGifCell | @pro-laico/payload-mux/components/MuxVideoGifCell | List-view animated-gif thumbnail cell (selected by collections.muxVideo.options.thumbnail). |
MuxVideoImageCell | @pro-laico/payload-mux/components/MuxVideoImageCell | List-view static-image thumbnail cell (selected by collections.muxVideo.options.thumbnail). |
Collections & globals
The plugin registers one collection, mux-video. Reshape it with collections.muxVideo — including
slug, which renames it and takes the plugin's own references with it. See
Using video for its playback fields and how to relate to it.
It ships closed to anonymous traffic: access: { read: authd }, so a read needs a logged-in user —
an anonymous mux-video fetch gets a 403. Open or narrow it under
collections.muxVideo.overrides.access, but keep read closed under a signed playback policy, since
an anonymous read would hand out a working signed URL.