Skip to content

Admin Review

Endpoints for platform administrators to review, approve, and reject staged objects uploaded by tenants. All endpoints in this section require platform admin privileges.

Platform admin only

Every endpoint on this page requires the authenticated user to have is_platform_admin: true. Non-admin users will receive a 403 Forbidden response.


List Review Queue

Retrieve all objects currently pending admin review.

GET /v1/admin/review/queue

Authentication: Authorization: Bearer {token}

Scope: admin:*

Request

curl -X GET "https://api.ipto.ai/v1/admin/review/queue?limit=20" \
  -H "Authorization: Bearer {token}"
import requests

response = requests.get(
    "https://api.ipto.ai/v1/admin/review/queue",
    headers={"Authorization": "Bearer {token}"},
    params={"limit": 20},
)
data = response.json()
const response = await fetch(
  "https://api.ipto.ai/v1/admin/review/queue?limit=20",
  {
    headers: { Authorization: "Bearer {token}" },
  }
);
const data = await response.json();

Parameters

Field Type Required Description
cursor string No Opaque pagination cursor from a previous response.
limit integer No Maximum number of items to return. Default: 20.

Response

{
  "data": {
    "items": [
      {
        "object_id": "obj_x1y2z3w4v5u6",
        "tenant_id": "tnt_f6e5d4c3b2a1",
        "dataset_id": "dset_a1b2c3d4e5f6",
        "dataset_name": "AP Invoices 2025",
        "filename": "invoice-0425.pdf",
        "content_type": "application/pdf",
        "size_bytes": 812345,
        "uploaded_at": "2026-04-05T10:01:00Z",
        "review_expires_at": "2026-04-12T10:01:00Z"
      },
      {
        "object_id": "obj_m7n8o9p0q1r2",
        "tenant_id": "tnt_f6e5d4c3b2a1",
        "dataset_id": "dset_a1b2c3d4e5f6",
        "dataset_name": "AP Invoices 2025",
        "filename": "invoice-0426.pdf",
        "content_type": "application/pdf",
        "size_bytes": 524288,
        "uploaded_at": "2026-04-05T10:05:00Z",
        "review_expires_at": "2026-04-12T10:05:00Z"
      }
    ],
    "total": 2
  },
  "request_id": "req_arv001",
  "timestamp": "2026-04-05T12:00:00Z"
}

Response Fields

Field Type Description
items ReviewItem[] Array of objects pending review.
total integer Total number of objects in the review queue.

ReviewItem fields:

Field Type Description
object_id string Unique identifier for the object.
tenant_id string Identifier of the tenant that uploaded the object.
dataset_id string Identifier of the parent dataset.
dataset_name string Human-readable name of the parent dataset.
filename string Original filename.
content_type string MIME type of the file.
size_bytes integer File size in bytes.
uploaded_at string ISO 8601 timestamp when the upload was confirmed.
review_expires_at string ISO 8601 deadline for completing the review.

Get Staged Object Detail

Retrieve full metadata for a specific staged object.

GET /v1/admin/review/objects/{tenant_id}/{object_id}

Authentication: Authorization: Bearer {token}

Scope: admin:*

Request

curl -X GET https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6 \
  -H "Authorization: Bearer {token}"
import requests

response = requests.get(
    "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6",
    headers={"Authorization": "Bearer {token}"},
)
data = response.json()
const response = await fetch(
  "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6",
  {
    headers: { Authorization: "Bearer {token}" },
  }
);
const data = await response.json();

Parameters

Field Type Required Description
tenant_id string Yes The tenant ID (path parameter).
object_id string Yes The object ID (path parameter).

Response

{
  "data": {
    "object_id": "obj_x1y2z3w4v5u6",
    "tenant_id": "tnt_f6e5d4c3b2a1",
    "dataset_id": "dset_a1b2c3d4e5f6",
    "dataset_name": "AP Invoices 2025",
    "filename": "invoice-0425.pdf",
    "content_type": "application/pdf",
    "size_bytes": 812345,
    "checksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "status": "staged",
    "review_state": "pending",
    "uploaded_at": "2026-04-05T10:01:00Z",
    "review_expires_at": "2026-04-12T10:01:00Z",
    "reviewed_at": null
  },
  "request_id": "req_arv002",
  "timestamp": "2026-04-05T12:01:00Z"
}

Response Fields

Field Type Description
object_id string Unique identifier for the object.
tenant_id string Identifier of the owning tenant.
dataset_id string Identifier of the parent dataset.
dataset_name string Human-readable name of the parent dataset.
filename string Original filename.
content_type string MIME type of the file.
size_bytes integer File size in bytes.
checksum_sha256 string SHA-256 checksum of the uploaded file.
status string Object pipeline status.
review_state string Admin review state (pending, approved, rejected).
uploaded_at string ISO 8601 upload confirmation timestamp.
review_expires_at string ISO 8601 review deadline.
reviewed_at string \| null ISO 8601 review timestamp, or null if not yet reviewed.

Approve Object

Approve a staged object. This transitions the object to active status and enqueues it for indexing.

POST /v1/admin/review/objects/{tenant_id}/{object_id}/approve

Authentication: Authorization: Bearer {token}

Scope: admin:*

Request

curl -X POST https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/approve \
  -H "Authorization: Bearer {token}"
import requests

response = requests.post(
    "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/approve",
    headers={"Authorization": "Bearer {token}"},
)
data = response.json()
const response = await fetch(
  "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/approve",
  {
    method: "POST",
    headers: { Authorization: "Bearer {token}" },
  }
);
const data = await response.json();

Parameters

Field Type Required Description
tenant_id string Yes The tenant ID (path parameter).
object_id string Yes The object ID (path parameter).

Response

{
  "data": {
    "object_id": "obj_x1y2z3w4v5u6",
    "status": "active",
    "review_state": "approved",
    "reviewed_at": "2026-04-05T14:00:00Z"
  },
  "request_id": "req_arv003",
  "timestamp": "2026-04-05T14:00:00Z"
}

Response Fields

Field Type Description
object_id string Unique identifier for the approved object.
status string Updated object status (now active).
review_state string Updated review state (approved).
reviewed_at string ISO 8601 timestamp of the approval.

Indexing starts automatically

After approval, the object is automatically enqueued for normalization and indexing. It will appear in search results once indexing completes.


Reject Object

Reject a staged object. The object will not be indexed and can be purged.

POST /v1/admin/review/objects/{tenant_id}/{object_id}/reject

Authentication: Authorization: Bearer {token}

Scope: admin:*

Request

curl -X POST https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/reject \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "File contains personally identifiable information that must be redacted before upload."
  }'
import requests

response = requests.post(
    "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/reject",
    headers={"Authorization": "Bearer {token}"},
    json={
        "reason": "File contains personally identifiable information that must be redacted before upload."
    },
)
data = response.json()
const response = await fetch(
  "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/reject",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer {token}",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      reason:
        "File contains personally identifiable information that must be redacted before upload.",
    }),
  }
);
const data = await response.json();

Parameters

Field Type Required Description
tenant_id string Yes The tenant ID (path parameter).
object_id string Yes The object ID (path parameter).

Request Body

Field Type Required Description
reason string Yes Human-readable explanation for why the object was rejected. Visible to the uploading tenant.

Response

{
  "data": {},
  "request_id": "req_arv004",
  "timestamp": "2026-04-05T14:05:00Z"
}

Response Fields

Returns an empty object on success.


Preview Staged Object

Get a time-limited preview URL for a staged object. Allows admins to inspect the file contents before making a review decision.

GET /v1/admin/review/objects/{tenant_id}/{object_id}/preview

Authentication: Authorization: Bearer {token}

Scope: admin:*

Request

curl -X GET https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/preview \
  -H "Authorization: Bearer {token}"
import requests

response = requests.get(
    "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/preview",
    headers={"Authorization": "Bearer {token}"},
)
data = response.json()
const response = await fetch(
  "https://api.ipto.ai/v1/admin/review/objects/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6/preview",
  {
    headers: { Authorization: "Bearer {token}" },
  }
);
const data = await response.json();

Parameters

Field Type Required Description
tenant_id string Yes The tenant ID (path parameter).
object_id string Yes The object ID (path parameter).

Response

{
  "data": {
    "preview_url": "https://storage.ipto.ai/previews/tnt_f6e5d4c3b2a1/obj_x1y2z3w4v5u6?X-Amz-Signature=...",
    "expires_at": "2026-04-05T15:00:00Z"
  },
  "request_id": "req_arv005",
  "timestamp": "2026-04-05T14:00:00Z"
}

Response Fields

Field Type Description
preview_url string Pre-signed URL to view or download the staged file.
expires_at string ISO 8601 timestamp after which the preview URL expires.

Preview URL expiry

Preview URLs are valid for a limited time (typically one hour). Generate a new URL if the previous one has expired.