Skip to navigation

Gate uploads before publishing

Hold new uploads out of open playback until moderation clears them. Create media with private playback, moderate it once processing finishes, then issue a public playback ID only when the result meets your policy.

What you’re building

A publishing pipeline where playback is closed by default and opened by a decision rather than by the end of processing.

Media is created with a private access policy, so it can only be played through a short-lived signed URL that your application issues. Once processing finishes, your application starts moderation on the ready asset. When the result arrives, your rules decide what happens: media that meets your policy gets a public playback ID and becomes viewable, media that does not stays private while a reviewer looks at it or while the contributor is asked to re-cut it.

The pipeline is event-driven end to end. Two webhooks carry it: one says the media is ready to be moderated, the other says the moderation result is in.

The contributor never waits on a person for the common case, and no asset becomes publicly playable without passing your policy first.


Prerequisites


Create the media with playback closed

Set accessPolicy to private so the asset cannot be played without a signed token. Nothing about this asset is public yet, and nothing becomes public until you decide it should be.

curl --request POST \
--url https://api.fastpix.com/v1/on-demand \
--user '{Access_Token}:{Secret_Key}' \
--header 'Content-Type: application/json' \
--data '{
"inputs": [
{
"type": "video",
"url": "https://static.fastpix.com/fp-sample-video.mp4"
}
],
"metadata": {
"uploaderId": "user_8842",
"reviewState": "pending"
},
"accessPolicy": "private"
}'

Storing your own reviewState in metadata gives you a field to query later and keeps the publishing state with the asset rather than only in your database.

For uploads that come from a device rather than a URL, use Upload media from device and set the same accessPolicy inside pushMediaSettings.


Start moderation when the media is ready

Moderation runs on a processed asset, so it cannot start at upload time. Wait for the video.media.ready webhook, which fires once the media has finished processing and is playable, then trigger moderation on it.

The trigger takes an optional configuration body (see Moderation configuration). By default, with no body, both the visual and the spoken track are analyzed, and the result reports which of them produced findings in moderation.modalities.

curl --request POST \
--url https://api.fastpix.com/v1/ai/{mediaId}/moderation \
--user '{Access_Token}:{Secret_Key}'

The response confirms the job started:

{
"success": true,
"data": {
"id": "c695988b-ff84-42ae-bb21-10f284fedb0e"
}
}

Trigger this from your video.media.ready handler rather than from the upload response. The upload returning does not mean the asset is processed, and moderation on an unready asset will not run.


Read the moderation result

Moderation runs in the background. Subscribe to the video.media.ai.moderation.ready webhook rather than polling, so your pipeline reacts as soon as the analysis completes.

If you need to fetch the result directly, call Get video moderation results.

curl --request GET \
--url https://api.fastpix.com/v1/ai/{mediaId}/moderation \
--user '{Access_Token}:{Secret_Key}'

Apply your policy to the result

Read the result at two levels. Use moderation.scores for the whole-media decision, and moderation.segments when you want to know exactly which moments caused it. For the full response shape, see Understand the moderation response.

Map the outcome to one of three actions:

OutcomeAction
All category scores below your review thresholdPublish. Issue a public playback ID.
Any score inside your review bandHold. Keep the media private and create a review task.
Any score above your automatic-action thresholdReject. Keep the media private and notify the contributor.

Use separate thresholds for video and audio findings, since the two tracks do not carry equal confidence. Keep the policy in your own application rather than inferring it from the response, so you can retune thresholds later without changing your integration.


Open playback for approved media

Publishing is the act of creating a public playback ID. Until this call succeeds, the asset has no public route to a viewer.

curl --request POST \
--url https://api.fastpix.com/v1/on-demand/{mediaId}/playback-ids \
--user '{Access_Token}:{Secret_Key}' \
--header 'Content-Type: application/json' \
--data '{
"accessPolicy": "public"
}'

The response returns the playback ID your player uses:

{
"success": true,
"data": {
"id": "b331e0d8-bef4-4ad2-8760-757fdb2818b7",
"accessPolicy": "public"
}
}

Note: Once the access policy is public, play the video with its HLS URL https://stream.fastpix.com/{playback_id}.m3u8, replacing {playback_id} with the playback ID (id) returned above.


Hold, review, or revoke

Media that did not clear needs no further call. With no public playback ID it is already unavailable, which is why closing playback at creation rather than opening it at creation is the safer default.

For media in your review band, issue a short-lived signed playback URL so a reviewer can watch it without it becoming public. See Generate JWTs for secure media. Give the reviewer the flagged categories and the segment time ranges alongside the video, so they can jump to the moment instead of watching the whole asset.

If something was published and later needs pulling, delete the playback ID. The media and its moderation history stay intact, so the decision can be appealed or reversed.

curl --request DELETE \
--url 'https://api.fastpix.com/v1/on-demand/{mediaId}/playback-ids?playbackId={playbackId}' \
--user '{Access_Token}:{Secret_Key}'

What to watch for

  • Set a deadline on the pending state. Moderation runs in the background, so build a timeout into your own pipeline and route anything still pending when it expires to human review, rather than leaving it held.
  • Moderation runs on a ready asset. It cannot be enabled at upload time. Trigger it from your video.media.ready handler, not from the upload response, and build your pending state around media readiness.
  • Sampling favours shorter media. Accuracy is strongest on short-form video. Evaluate results against your own catalog before relying on automatic publishing for long assets.
  • Audio findings depend on language. Audio moderation runs on the transcript, so it covers the supported audio moderation languages. Content outside those languages is still screened visually.
  • Give contributors a specific reason. The segments carry start and end times. A contributor told which seconds failed usually re-cuts and resubmits, where a generic rejection tends to end the relationship.

Frequently asked questions

How do I stop a video from being playable until moderation finishes?

Create the media with accessPolicy set to private and do not create a public playback ID. The asset can then only be played through a signed URL that your application issues, so it has no public route to a viewer until you decide to publish it.

When should I trigger moderation on a new upload?

From your video.media.ready webhook handler. AI features run on processed media, so moderation cannot start at upload time and a trigger sent before the asset is ready will not run. The upload call returning is not the same signal as the media being ready.

How do I unpublish a video after it has gone live?

Delete its playback ID. The media and its moderation results are retained, so the decision can be reviewed or reversed later. Deleting the media itself removes that option.

Should I block or review a borderline result?

Route it to review. Reserve automatic rejection for scores above a high threshold, and use the review band for everything uncertain. Tune the width of that band against your own reviewer capacity.


What’s next