realpng
Docs

Check and optimize a video

Send a video to a check or an optimization, follow its job, then read each frame's reading or download the optimized MP4.

How a video runs

A video is a job on both endpoints. POST /audit and POST /optimize answer 202 at once with its id and media: "video", and you poll until its status is succeeded or failed.

CallPoll it with
Check a videoGET /audit/{id}
Optimize a videoGET /optimize/{id}

The statuses, the polling rhythm and the job's lifetime are an optimization's, described in Optimize an image. A video optimization also takes callback_url for a signed webhook.

Send exactly one of video_url or video_upload_id. A video on disk goes through an upload with its video content_type. A large video is faster that way than by URL.

Send the length

Pass seconds, the video's length, when you know it. Credits are held for that length and a video that runs longer is refused. Without it, credits for the longest video are held, and the real length is charged once the job finishes. Video limits has the numbers.

Check a video

Check a video by URL
curl -X POST "https://realpng.com/api/v1/audit" \
  -H "X-API-Key: $REALPNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://videos.example.com/drone.mp4",
    "seconds": 12
  }'
202 Accepted
{
  "id": "b8f2d6a4-3c1e-4f7a-9d5b-2e6c8a0f4b13",
  "status": "queued",
  "media": "video"
}

Then poll the check until it finishes.

Get the video's check
curl "https://realpng.com/api/v1/audit/b8f2d6a4-3c1e-4f7a-9d5b-2e6c8a0f4b13" \
  -H "X-API-Key: $REALPNG_API_KEY"
200 OK
{
  "id": "b8f2d6a4-3c1e-4f7a-9d5b-2e6c8a0f4b13",
  "status": "succeeded",
  "verdict": "ai",
  "score": 88,
  "decided_by": "pixels",
  "lanes": {
    "pixels": {
      "verdict": "ai",
      "score": 88
    },
    "watermark": {
      "verdict": "none",
      "score": 4
    },
    "provenance": {
      "verdict": "nothing",
      "issuer": null
    }
  },
  "media": "video",
  "video": {
    "seconds": 12,
    "fps": 30,
    "frames": 360,
    "width": 1280,
    "height": 720,
    "audio": "copied",
    "readings": [
      {
        "t": 0.75,
        "verdict": "ai",
        "score": 84
      },
      {
        "t": 2.25,
        "verdict": "ai",
        "score": 86
      },
      {
        "t": 3.75,
        "verdict": "ai",
        "score": 88
      },
      {
        "t": 5.25,
        "verdict": "ai",
        "score": 91
      },
      {
        "t": 6.75,
        "verdict": "ai",
        "score": 87
      },
      {
        "t": 8.25,
        "verdict": "ai",
        "score": 90
      },
      {
        "t": 9.75,
        "verdict": "ai",
        "score": 89
      },
      {
        "t": 11.25,
        "verdict": "ai",
        "score": 85
      }
    ]
  }
}

A video is read on 8 frames, one at the middle of each of 8 equal slices of the video. Each frame is checked as an image is, both detectors and the watermark check, and the video's reading is the median of the frames'. One scene cut or black frame does not decide it.

verdict, score, decided_by and lanes mean what they mean for an image, as Read the verdict describes. The provenance lane reads the video file's own C2PA manifest. video adds the file's facts and each frame's reading.

FieldDescription
video.secondsThe video's length in seconds.
video.fpsIts frame rate.
video.framesIts frame count.
video.widthIts width in pixels, as it plays.
video.heightIts height in pixels, as it plays.
video.audiocopied, encoded or none, what an optimization does with its first track.
video.readingsEach frame's time t in seconds, its verdict and its score.

The frames of one video can read far apart, so branch on the video's verdict, not on one frame's.

Optimize a video

Optimize an uploaded video
curl -X POST "https://realpng.com/api/v1/optimize" \
  -H "X-API-Key: $REALPNG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_upload_id": "6c3f8e1a-9d4b-4a7c-b2e5-1f8d3c6a9e40",
    "seconds": 12
  }'
202 Accepted
{
  "id": "4e7a1c9d-8b2f-4d6e-a3c5-7f0b9e2d6a81",
  "status": "queued",
  "media": "video"
}

Then poll the optimization until it finishes.

Get the video's optimization
curl "https://realpng.com/api/v1/optimize/4e7a1c9d-8b2f-4d6e-a3c5-7f0b9e2d6a81" \
  -H "X-API-Key: $REALPNG_API_KEY"
200 OK
{
  "id": "4e7a1c9d-8b2f-4d6e-a3c5-7f0b9e2d6a81",
  "status": "succeeded",
  "media": "video",
  "file_url": "https://realpng.com/api/v1/optimize/4e7a1c9d-8b2f-4d6e-a3c5-7f0b9e2d6a81/file",
  "expires_at": "2026-10-09T09:41:27+00:00",
  "optimization_score": {
    "score": 81,
    "zone": "high"
  },
  "video": {
    "seconds": 12,
    "fps": 30,
    "frames": 360,
    "width": 1280,
    "height": 720,
    "audio": "copied",
    "readings": [
      {
        "t": 0.75,
        "optimization_score": {
          "score": 78,
          "zone": "high"
        }
      },
      {
        "t": 2.25,
        "optimization_score": {
          "score": 80,
          "zone": "high"
        }
      },
      {
        "t": 3.75,
        "optimization_score": {
          "score": 83,
          "zone": "high"
        }
      },
      {
        "t": 5.25,
        "optimization_score": {
          "score": 85,
          "zone": "high"
        }
      },
      {
        "t": 6.75,
        "optimization_score": {
          "score": 79,
          "zone": "high"
        }
      },
      {
        "t": 8.25,
        "optimization_score": {
          "score": 82,
          "zone": "high"
        }
      },
      {
        "t": 9.75,
        "optimization_score": {
          "score": 84,
          "zone": "high"
        }
      },
      {
        "t": 11.25,
        "optimization_score": {
          "score": 77,
          "zone": "high"
        }
      }
    ]
  }
}

A succeeded video optimization has file_url, the MP4's download link, and no image_url. Its optimization_score is the median of the frames' readings, with the zones an image's has. The frames are read from the optimized MP4, the file you download. video.readings gives each frame's own optimization_score.

An optimization of a video takes about as long as the video runs. It applies an image's resample, grain and color passes to every frame. Those passes alone can leave a video's score in the low zone.

Download the MP4

Download the optimized MP4
curl -L -o optimized.mp4 "https://realpng.com/api/v1/optimize/4e7a1c9d-8b2f-4d6e-a3c5-7f0b9e2d6a81/file"
HTTP/1.1 200 OK

file_url needs no API key, and works until expires_at, 24 hours after the optimization started. It redirects to a short lived storage link that serves the MP4 as an attachment. That link takes a Range header, so a video player can play from it. Follow the redirect, as curl -L does.

The MP4 is H.264 with AAC sound, at the source's frame rate.

  • Its first audio track is copied as is when it is AAC, and encoded to AAC when it is not.
  • Rotation is applied, so a phone video plays upright. HDR comes back as SDR.
  • A video over 1920 px on its long edge comes back at 1920 px.
  • It is a new file that keeps none of the original's metadata: no container tags, chapters, subtitles, later audio tracks or C2PA manifest.

From an agent

The MCP tools audit_video and process_video take the same fields and wait for the job, as MCP tools describes. get_processing_result resumes either one.

Next steps