Skip to main content
When a camera detects motion or a doorbell is pressed, Seam sends an event that lists the IDs of the media captured for it: usually a short video clip and a thumbnail image. You pass each ID to /media/get to get the media’s status and a short-lived signed URL for downloading or playing it.
Camera event media is in beta. For Arlo and Tapo, Seam turns on camera events and event media for each workspace separately, so contact Seam and ask for them to be turned on for yours. Ring events include media_ids without extra setup. The request and response shapes on this page may change before general availability.

How It Works

  1. Seam creates a camera.activated or device.doorbell_rang event. The event’s media_ids array lists one ID for each piece of media Seam expects for the event.
  2. You call /media/get with a media_id. Seam returns a media object with a status and, once the media is ready, a signed url.
  3. You download or play the media from url right away. The URL expires within minutes, so call /media/get again whenever you need a new one.
Store the media_id, not the url. Signed URLs expire within minutes, while a media ID stays valid for about 30 days. After that, /media/get returns media_not_found for it.

Supported Providers

For Arlo and Tapo, Seam copies the clip into Seam’s private storage and extracts a JPEG thumbnail from it. Seam converts clips to MP4 with H.264 video so that browsers can play them. Ring media stays with Ring: Seam requests a signed URL from Ring each time you call /media/get.

Before You Begin

To retrieve event media, you need:
  • For Arlo and Tapo, a workspace with camera events and event media turned on. Ring event media doesn’t need to be turned on.
  • A connected account with a supported camera or doorbell.
  • A webhook subscribed to camera.activated and, for Ring doorbells, device.doorbell_rang.
  • An API key, or a client session token that has access to the device.

Step 1: Receive a Camera Event

Subscribe your webhook to camera.activated and device.doorbell_rang. Verify the webhook signature, then store the event’s media_ids along with its event_id and device_id. Example camera.activated event:
  • media_ids doesn’t guarantee any order. Call /media/get for each ID and read media_type to find the clip (video) and the thumbnail (image).
  • media_ids is missing when Seam isn’t capturing media for the event. For example, event media might not be turned on for an Arlo or Tapo workspace, or the provider might not supply media for that event type.
  • motion_sub_type (human, vehicle, package, or other) is included when the provider reports it.
  • video_url and image_url are still included for compatibility. They point to /media/get with format=redirect, and requests to them need the same authentication as any other Seam API request. New integrations should use media_ids.
For Arlo and Tapo, media usually isn’t ready when the event arrives. Seam sends the event first, and then retrieves the recording in the background. Ring media is available as soon as the event arrives.

Step 2: Get the Media

Call /media/get with a media_id. The default format is json, which returns the media object. Request:
Response:

Media Object

See the media object reference for the complete property list. The response has no field for when url expires, and the lifetime varies by provider. Treat every URL as valid for only a few minutes, and call /media/get again for a new one rather than caching it.

Media Statuses

pending is the only status that changes. After the media’s expires_at passes, /media/get returns a media_not_available error for it. About 30 days after the event, Seam deletes the media record entirely, and /media/get returns media_not_found.

Step 3: Wait for Pending Media

Seam can’t retrieve an Arlo or Tapo recording until the provider finishes it, so media often stays pending for a minute or more after the event. Seam doesn’t send an event when media becomes available, so poll /media/get with backoff:
  • Wait about 15 seconds after the event before the first request.
  • Double the delay after each pending response, up to 30 seconds between requests.
  • Stop after about 10 minutes and treat the media as unavailable.
  • Poll from a background job, not from the webhook handler. Return a 2xx from the webhook handler as soon as you store the event.
JavaScript

Step 4: Use the Signed URL

The url is a signed, short-lived link to the media file. It expires within minutes, and the exact lifetime varies by provider. The response doesn’t say when: expires_at is when the media itself stops being available, not when the URL expires.
  • Don’t store the URL. Store the media_id and call /media/get when you need a URL.
  • Request a new URL when playback fails. A video player can request byte ranges from the URL long after the page loads, for example when the user seeks. If the player reports an error, call /media/get again and set the new URL as the source.
  • Keep the URL private. Anyone who has the URL can download the media until it expires. Don’t log it or put it in analytics events.
  • Keep your own copy if you need it longer. Seam keeps stored Arlo and Tapo media for 7 days, and expires_at tells you when. After that, /media/get returns media_not_available. Ring media has no expires_at: it’s available for up to 30 days, subject to the retention of the Ring account’s Ring Protect plan.

JSON vs. Redirect

/media/get accepts a format parameter: Browsers can’t add an Authorization header to an <img> or <video> element’s request, so you can’t point one straight at /media/get. In a browser, request the JSON format with your client session token, then set the returned url as the element’s src. This works for media that Seam stores, such as Arlo clips:
JavaScript
To download a clip on a server:
cURL
Ring video URLs may not play directly in a browser <video> element. When a Ring clip is shorter than the window Seam requests, Ring’s servers answer with a partial-content response that browsers reject. For Ring clips, download the file on your server and serve it to the browser yourself.
If the media isn’t available yet, the redirect format returns an error instead of a 302. See Errors.

Authorization

/media/get accepts the same credentials as other Seam read endpoints: an API key, a personal access token with a workspace, or a client session token. A client session can only get media for the devices it has access to. That is, devices in the connected accounts, Connect Webviews, or user identity that you associated with the client session when you created it, or, for a client session created with a customer_key, that customer’s devices. For any other device’s media, Seam returns media_not_found, the same error it returns for an ID that doesn’t exist, so a client can’t probe for media in other accounts. Use client sessions to show media in your users’ browsers or mobile apps without exposing your API key.

Errors


Provider Notes

  • Seam retrieves the clip from the camera’s microSD card through the paired Seam Bridge, so the Bridge and the camera must stay online after the event.
  • Seam needs the Tapo account password, which is the password for the Tapo app, not the Camera Account password. Enter it in the optional Tapo account password field of the Connect Webview. For a camera connected without it, media ends up unavailable. To add it, reconnect the camera. Recordings start with the next motion event. See Tapo event recordings.
  • Without a microSD card, or when the card has no recording that contains the event, the media ends up unavailable.
  • The sandbox Tapo camera has no microSD recordings.

Arlo

  • Seam retrieves the clip from the Arlo cloud library. Without a subscription that includes cloud recording, Arlo stores no recording, and the media ends up unavailable.
  • Arlo clips are often recorded in HEVC. Seam converts them to H.264 so that browsers can play them.

Ring

  • Ring media is available for both camera.activated and device.doorbell_rang events.
  • Ring only keeps clips for accounts with an active Ring Protect subscription.
  • Seam requests a new signed URL from Ring on each /media/get call. Ring media is available as soon as the event arrives, and its expires_at is null. If Ring no longer has the recording, /media/get returns media_not_available.
  • Ring video URLs may not play directly in a browser. See JSON vs. Redirect.

Next Steps