GET
/
api
/
v1
/
admin
/
tenancy-queue
Tenancy verification queue
curl --request GET \
  --url https://api.example.com/api/v1/admin/tenancy-queue
import requests

url = "https://api.example.com/api/v1/admin/tenancy-queue"

response = requests.get(url)

print(response.text)
const options = {method: 'GET'};

fetch('https://api.example.com/api/v1/admin/tenancy-queue', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/admin/tenancy-queue",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"net/http"
"io"
)

func main() {

url := "https://api.example.com/api/v1/admin/tenancy-queue"

req, _ := http.NewRequest("GET", url, nil)

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.get("https://api.example.com/api/v1/admin/tenancy-queue")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.example.com/api/v1/admin/tenancy-queue")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)

response = http.request(request)
puts response.read_body

Overview

The moderation queue for tenancy verifications. Defaults to status=PENDING, ordered by createdAt DESC. Each row embeds a fresh, 15-minute signed download URL for the private tenancy document so a moderator can view the evidence without the file being publicly accessible. Available to any admin role — listing the queue is read-only. The decisions (approve / reject) are role-gated.

Authentication

Bearer <accessToken> with scope: 'admin' required (requireAdmin).
Read-only — all admin roles (SUPER, MODERATOR, FINANCE) may list the queue.

Path parameters

None.

Query parameters

NameTypeRequiredNotesExample
statusenumnoPENDING (default), APPROVED, REJECTED.PENDING
cursorstringnoOpaque base64url pagination cursor, 1..512 chars.eyJjcmVhdGVkQXQ…
limitintegernoPage size, 1..100. Default 25.50

Request body

None.

Response — 200 OK

FieldTypeNotes
itemsarrayArray of tenancy verification rows (below).
nextCursorstring | nullCursor for the next page, or null on the last page.

Tenancy verification row

FieldTypeNotes
idstringVerification row ObjectId.
userIdstringThe submitting user.
landlordNamestringName supplied during onboarding.
documentTypeenumTENANCY_AGREEMENT | RENT_STATEMENT | LANDLORD_LETTER.
uploadIdstringThe backing upload row id.
reviewStatusenumPENDING | APPROVED | REJECTED.
reviewedBystring | nullAdmin id who last decided, or null.
reviewedAtstring | nullISO timestamp of the decision, or null.
reviewNotesstring | nullRejection reason, or null.
createdAtstringISO timestamp.
userobject | null{ id, email, firstName, lastName } summary, or null.
uploadobject | null{ id, fileKey, mimeType, fileSizeBytes }, or null.
documentDownloadUrlstring | null15-minute signed URL to view the document, or null if the upload is missing. Re-issued on every request — do not cache.
{
  "items": [
    {
      "id": "66400a8f1c2b4d5e6f7ab000",
      "userId": "66400a8f1c2b4d5e6f7a8b01",
      "landlordName": "Acme Lettings",
      "documentType": "TENANCY_AGREEMENT",
      "uploadId": "66400a8f1c2b4d5e6f7ac000",
      "reviewStatus": "PENDING",
      "reviewedBy": null,
      "reviewedAt": null,
      "reviewNotes": null,
      "createdAt": "2026-05-20T08:30:00.000Z",
      "user": {
        "id": "66400a8f1c2b4d5e6f7a8b01",
        "email": "jane@example.com",
        "firstName": "Jane",
        "lastName": "Doe"
      },
      "upload": {
        "id": "66400a8f1c2b4d5e6f7ac000",
        "fileKey": "tenancy/66400a8f1c2b4d5e6f7a8b01/agreement.pdf",
        "mimeType": "application/pdf",
        "fileSizeBytes": 284913
      },
      "documentDownloadUrl": "https://swappr-private.fra1.digitaloceanspaces.com/tenancy/…?X-Amz-Expires=900&…"
    }
  ],
  "nextCursor": null
}
documentDownloadUrl expires 15 minutes after the response is generated. Surface it to the moderator immediately; if it expires, re-fetch the queue page to mint a new one.

Error responses

StatusCodeMeaning
400VALIDATION_FAILEDlimit out of 1..100 or status unknown.
401UNAUTHENTICATEDMissing, malformed, expired, or non-admin-scope token.

See also

curl

curl "https://api.swappr.co.uk/api/v1/admin/tenancy-queue?status=PENDING&limit=50" \
  -H "Authorization: Bearer $ADMIN_ACCESS_TOKEN"

Postman

See docs/postman/swappr.postman_collection.jsonAdmin Tenancy → Queue.