Obtaining a camera snapshot

Hi team,

We’re using the current Ring Partner API with:

  • GET /v1/history/devices/{device_id}/events

  • POST /v1/devices/{device_id}/media/image/download

What we’re doing right now is:

  1. calling Event History with event_types=motion,on_demand for cameras, or ding,on_demand,motion for doorbells

  2. taking the timestamps from those events

  3. calling Image Download with type: “latest_in_range”

That flow works, but the images we get back do not seem to match what we’re seeing in the Ring app.

In the Ring app, we can clearly see newer person-detection events and newer clips for the same device. But when we call Event History through the Partner API, we only get older events back. Because of that, the still image we get from Image Download is also older.

A few questions:

  1. If the Ring app is showing person-detection events, should those also show up in Event History through the Partner API? If so, should we be querying for motion.human, or something else?

  2. If the Ring app shows newer events and clips, but Event History only returns older ones, is that expected? Or does that suggest we’re filtering the events incorrectly?

  3. Is Event History + Image Download the right way to get the most recent still image?

  4. Is there any supported way to get a current still image without starting a WebRTC/WHEP session and grabbing a frame from that?

  5. Should we treat X-Media-Timestamp as the real capture time of the image returned by media/image/download?

One other detail: this is running on a very minimal IoT controller, so downloading a clip and extracting a frame is not really practical for us. We don’t have the storage or compute budget to install something like ffmpeg on the device. So if there is a lightweight way to get a recent still image directly, that would help a lot.

Mostly we’re trying to understand whether we should expect the Partner API to show the same recent events/images that we can already see in the Ring app, or whether those can differ.

Thanks!

Hello,

1. Should person-detection events show up in Event History?

Yes. The Event History API supports motion subtypes including motion.human, motion.vehicle, and motion.other_motion. If you’re querying with event_types=motion,on_demand, that returns all motion events regardless of subtype — person detections should be included. If you want to filter specifically for person detections, use event_types=motion.human.

2. Why might the Ring app show newer events than Event History?

A few possible reasons:

  • Time-gated access: The Event History API only returns events that occurred after the user granted consent to your app. If the user recently re-linked their account, the consent date resets and events before the new consent date become inaccessible.

  • Pagination: Results are ordered newest-first. If you’re not following links.next, you may only be seeing the first page of results.

  • Smart Alerts filtering: If the user has Smart Alerts configured in the Ring app to filter certain motion types, behavior may differ between the Ring app timeline and the Partner API.

3. Is Event History + Image Download the right way to get the most recent still image?

Yes, but you can simplify it. You don’t necessarily need Event History as an intermediate step. You can call Image Download directly with type: "latest_in_range" and a recent start_timestamp (e.g., a few hours ago). This returns the most recent available image in that window without needing to look up event timestamps first.

4. Is there a way to get a still image without WebRTC/WHEP?

Yes, the Image Download API (POST /v1/devices/{device_id}/media/image/download) does exactly this. It returns a JPEG or PNG via a pre-signed URL redirect. No WebRTC session, video download, or frame extraction required. This is lightweight and well-suited for IoT controllers:

{
  "type": "latest_in_range",
  "start_timestamp": <epoch_ms_from_a_few_hours_ago>,
  "image_options": {
    "format": "jpeg",
    "resolution": {"width": 1920, "height": 1080}
  }
}

Note that this endpoint retrieves existing images only, it does not trigger a new capture. Images are available when the device was recording (during a motion event or live session).

5. Should you trust X-Media-Timestamp?

Yes. The X-Media-Timestamp response header is the actual capture time of the image returned. It may differ slightly from your requested timestamp (the API applies a ±10 second tolerance for at_timestamp searches), so always use this header as the authoritative capture time.

General note on Event History returning stale results:

If you’re consistently seeing older events than expected, try calling Event History without any event_types filter to see if newer events appear with different types. Also confirm you’re not accidentally reusing a page[key] cursor from a previous request, which would skip newer events.

Hope that helps!

Thanks, that helps. I think I understand the issue better now.

In our case, we were not requesting an old range like days or weeks ago. We were requesting only the last few hours, but POST /v1/devices/{device_id}/media/image/download with type: “latest_in_range” would still return 403 TIME_RANGE_NOT_AUTHORIZED.

The account had likely just been linked or re-linked around that time, so my current theory is that the failure was because the requested start_timestamp was still earlier than the app’s newly authorized consent boundary, even though it was only a few hours back.

Is that the correct interpretation?

More specifically:

If a user has just linked or re-linked their Ring account, should we expect latest_in_range to return 403 TIME_RANGE_NOT_AUTHORIZED whenever the requested start_timestamp falls before that new consent boundary?

If so, is Event History effectively the supported way to discover an authorized lower bound for snapshot lookup, by finding the earliest event Ring is willing to return and then using that timestamp for latest_in_range?

Or is there another supported way to determine the currently authorized snapshot window without first calling Event History?

We’re asking because on a minimal IoT controller, the simplest flow would be to call Image Download directly with a recent window, but that seems fragile if the account was only just linked and the consent boundary is newer than our requested lookback.

Hi Darrell,

Your interpretation is correct.

1. Does latest_in_range return 403 TIME_RANGE_NOT_AUTHORIZED if start_timestamp is before the consent boundary?

Yes. If the user just linked (or re-linked) their account, the consent date is set to that moment. Any start_timestamp before that boundary will return TIME_RANGE_NOT_AUTHORIZED, even if it’s only a few hours back. The API enforces this server-side regardless of how recent the timestamp feels in absolute terms.

2. Is Event History the supported way to discover the authorized lower bound?

Effectively, yes. Event History only returns events after the consent date, so the earliest event it returns gives you a safe lower bound for media requests. If Event History returns an empty array, there are no authorized events yet and you should wait for new activity (a motion event or live session) before attempting an image download.

3. Is there another way to determine the authorized window without calling Event History?

No. The consent date is not exposed directly via any API endpoint. There’s no dedicated “get my consent date” call. Your options are:

  • Use Event History to find the earliest available event timestamp as your safe lower bound

  • Use the timestamp from a motion_detected webhook as your trigger (since webhooks only fire for post-consent events, any timestamp from a webhook is guaranteed to be within the authorized window)

  • Use start_timestamp = now minus a small window (e.g., last 5 minutes) and handle the 403 gracefully as a signal that no authorized media exists yet

Possible approach for your IoT controller:

Since you’re on a minimal device, the most robust lightweight flow would be:

  1. Listen for motion_detected webhooks

  2. Use the webhook’s timestamp as your start_timestamp for Image Download

  3. This guarantees the timestamp is post-consent and that a recording exists at that time

This avoids the Event History call entirely and eliminates the TIME_RANGE_NOT_AUTHORIZED edge case, since webhook timestamps are always within the authorized window.

If you need to poll without waiting for a webhook, call Image Download with start_timestamp set to a very recent time (e.g., 60 seconds ago) and handle 403 as “no authorized media yet try again later.”

1 Like

Thank you, that clears it up nicely