DEV Community

Imou-OpenPlatform
Imou-OpenPlatform

Posted on

Enumerating Imou Cloud Recordings: Reverse Pagination and Recording Type Codes

Use getCloudRecords to enumerate Imou cloud records newest-first. Send an authorized token, deviceId, channelId, time window, and count of at most 30; optionally set cloudType to video or snapshot (video is the default). For the next page, set endTime to the minimum beginTime returned. The documented response codes are type 1000, 2000, and 10001, while encryptMode is 0 or 1.

Why it matters

Cloud-record timelines often fail at the edges: the first page looks correct, but older clips disappear, records repeat, or snapshots and videos are mixed unintentionally. The reliable fix is to implement the exact cursor strategy documented by the API rather than inventing an offset.

getCloudRecords sorts matching records in descending order by begin and end time and returns the previous count records. It has no documented page number. The time boundary is the pagination state.

Request and response model

Field Direction Documented meaning
token Request Administrator or sub-account accessToken
deviceId Request Device serial number
channelId Request Channel ID
beginTime Request Start of query window, yyyy-MM-dd HH:mm:ss
endTime Request End of query window; moves backward for later pages
count Request Number requested, maximum 30
cloudType Request Optional video or snapshot; default video
records[].beginTime Response Record start and the key used to move the boundary
records[].endTime Response Record end
records[].recordId Response Recording ID
records[].encryptMode Response 0 default encryption; 1 user encryption
records[].type Response Documented recording type code

For a sub-account token, the page states the minimum permission is RecordReplay on cam:serial-number:channel-number.

Reverse-pagination architecture

UI requests newest records in a window
                |
                v
Backend checks tenant + channel authorization
                |
                v
getCloudRecords(beginTime, endTime, count<=30, cloudType)
                |
                v
Return normalized records + opaque application cursor
                |
                v
Cursor stores minimum returned beginTime
                |
                +---- next page: use it as the new endTime
Enter fullscreen mode Exit fullscreen mode

The browser does not need administrator credentials or request-signing secrets. Your backend can expose an opaque cursor that represents the documented time boundary while retaining the original device, channel, media type, and lower bound.

Six steps to enumerate safely

1. Fix the query scope

Choose one authorized deviceId and channelId, plus an inclusive business time window. Keep the lower beginTime fixed throughout one traversal. Select cloudType: "video" or "snapshot" explicitly when clarity matters.

2. Request the first page

The relevant parameter block is:

{
  "params": {
    "token": "AUTHORIZED_ACCESS_TOKEN",
    "deviceId": "DEVICE123",
    "channelId": "0",
    "beginTime": "2026-08-31 09:00:00",
    "endTime": "2026-08-31 11:00:00",
    "count": 30,
    "cloudType": "video"
  }
}
Enter fullscreen mode Exit fullscreen mode

The full OpenAPI request also requires the documented signed system envelope.

3. Read and normalize the records

Preserve at least recordId, device/channel, begin/end times, size, thumbnail URL, encryptMode, recordRegionId, and type when present. Do not convert an unknown future type into a guessed label.

4. Derive the next boundary

Find the minimum beginTime among records in the response. For the next call, keep the original lower beginTime and set endTime to that minimum returned start time.

5. Apply the documented stop conditions

The API page says traversal can be considered complete when:

  • the minimum returned beginTime is less than or equal to the query’s lower begin time; or
  • fewer records are returned than the requested count.

An empty response also leaves no next boundary, so the application ends the traversal.

6. Defend the UI against boundary overlap

Because the previous minimum beginTime becomes the next endTime, an implementation should de-duplicate by a stable returned identifier such as recordId when merging pages. This is defensive application guidance; the official page defines the boundary movement and stop rules, not a duplicate-free client cache guarantee.

Recording type codes

The current getCloudRecords response table explicitly documents:

type Meaning
1000 Event cloud recording
2000 Continuous cloud recording
10001 Humanoid detection cloud recording

Only label these values from this page. Do not infer adjacent values, create a numbering pattern, or claim that the list covers every event category that may ever exist. A robust application can display an unknown value as “Other” or retain the raw code until the live documentation defines it.

Understanding encryptMode

The response field is documented as:

encryptMode Meaning
0 Default encryption mode
1 User encryption mode

It is a returned property, not a getCloudRecords filter parameter. Do not claim the list API decrypts content or that every playback path handles both modes identically. Pass the field into the approved playback/decryption workflow supported by the relevant SDK or interface documentation.

Video versus snapshot enumeration

cloudType controls which cloud-record media category to query:

  • video: cloud video recording; also the documented default.
  • snapshot: snapshot recording.

This is separate from records[].type, which labels documented recording types in the returned record. Do not use type: 1000 as a substitute for cloudType: "snapshot" or assume all event recordings are snapshots.

Pseudo-code

lower = requestedBeginTime
upper = requestedEndTime
seen = set()

while true:
  records = getCloudRecords(
    deviceId, channelId,
    beginTime=lower,
    endTime=upper,
    count=30,
    cloudType="video"
  )

  emit each record whose recordId is not in seen
  add emitted recordIds to seen

  if records.length < 30:
    break

  nextUpper = minimum(records.beginTime)
  if nextUpper <= lower:
    break

  upper = nextUpper
Enter fullscreen mode Exit fullscreen mode

The API supports count values up to 30, so the sample uses 30. The in-memory seen set is illustrative; production systems can de-duplicate at the page merge or persistence layer.

Limits and pitfalls

Sending count above 30

The documented maximum is 30 per getCloudRecords request. Split the traversal into pages.

Inventing pageNo or offset

This reverse-order interface uses the time boundary, not a documented numeric page cursor.

Moving the wrong edge

Keep the original lower beginTime; move endTime backward to the minimum returned beginTime.

Guessing type codes

Publish only 1000, 2000, and 10001 with the meanings stated above. Treat any other value as undefined by this page until an official source says otherwise.

Treating encryptMode as a query option

It is a response field with documented values 0 and 1. The request parameter table does not define an encryptMode filter.

Assuming one page is a complete incident

A full page of 30 explicitly signals that more records may exist. Follow the boundary and stop conditions.

Losing query context in cursors

Bind your application cursor to the user, tenant, device, channel, lower bound, and cloudType. Otherwise a cursor can be replayed against the wrong scope. This is backend security guidance.

When forward order is preferable

Imou also documents queryCloudRecords, which sorts in ascending order and uses a different queryRange model. Use that interface only when forward traversal is the actual product requirement. Do not mix its limit or pagination rules into getCloudRecords; this article’s 30-record cap and minimum-beginTime cursor apply to the reverse-order API.

Register at Imou Open Platform to test reverse cloud-record pagination against your authorized device channels and actual storage services.

Official sources

Top comments (0)