Find, browse, copy, and move objects
Find and rearrange files: list with filters, browse as folders, search, and copy or move. Choose an interface below. REST examples use a server-side API key; keep it out of browser code.
Configure client with the JavaScript SDK setup or
the synchronous Python client setup. For
Refine, register the named storage provider
and initialize these hooks inside a React component or custom hook under
<Refine>. Browser examples use the signed-in user session; keep API keys in server code. Replace BUCKET_SLUG with your bucket slug.
List and filter#
The list endpoint accepts a rich filter grammar. Every parameter is optional.
Both SDKs return objects in the response’s data field and their count in
total.
Return only PDFs in a folder, largest first:
- JavaScript SDK
- Python SDK
- Refine
- REST API
import {Storage} from '@taruvi/sdk';
import type {StorageListResponse} from '@taruvi/sdk';
await new Storage(client).from('BUCKET_SLUG')
.filter({prefix: 'reports/', mimetype: 'application/pdf', ordering: '-size', page_size: 50}).execute<StorageListResponse>();
client.storage.from_("BUCKET_SLUG").filter(
prefix="reports/", mimetype="application/pdf", ordering="-size", page_size=50,
).list()
import {useList} from '@refinedev/core';
import type {StorageObject} from '@taruvi/sdk';
useList<StorageObject>({
dataProviderName: 'storage',
resource: 'BUCKET_SLUG',
filters: [
{field: 'prefix', operator: 'eq', value: 'reports/'},
{field: 'mimetype', operator: 'eq', value: 'application/pdf'},
],
sorters: [{field: 'size', order: 'desc'}],
pagination: {currentPage: 1, pageSize: 50},
});
The hook’s result.data contains storage objects; result.total is the
matching object count.
Each object's file_path identifies it for download, update, or delete.
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/Headers
AuthorizationApi-Key $TARUVI_API_KEY
Query parameters
prefixreports/mimetypeapplication/pdfordering-sizepage_size50
View cURL
curl --silent --show-error -G "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
--data-urlencode 'prefix=reports/' \
--data-urlencode 'mimetype=application/pdf' \
--data-urlencode 'ordering=-size' \
--data-urlencode 'page_size=50'
200
Return objects the caller created since a date:
- JavaScript SDK
- Python SDK
- Refine
- REST API
import {Storage} from '@taruvi/sdk';
import type {StorageListResponse} from '@taruvi/sdk';
await new Storage(client).from('BUCKET_SLUG')
.filter({created_by_me: true, created_after: '2026-09-01'}).execute<StorageListResponse>();
client.storage.from_("BUCKET_SLUG").filter(
created_by_me=True, created_after="2026-09-01",
).list()
import {useList} from '@refinedev/core';
import type {StorageObject} from '@taruvi/sdk';
useList<StorageObject>({
dataProviderName: 'storage',
resource: 'BUCKET_SLUG',
filters: [
{field: 'created_by_me', operator: 'eq', value: true},
{field: 'created_after', operator: 'eq', value: '2026-09-01'},
],
});
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/Headers
AuthorizationApi-Key $TARUVI_API_KEY
Query parameters
created_by_metruecreated_after2026-09-01
View cURL
curl --silent --show-error -G "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
--data-urlencode 'created_by_me=true' \
--data-urlencode 'created_after=2026-09-01'
200
Search filename or path substring:
- JavaScript SDK
- Python SDK
- Refine
- REST API
import {Storage} from '@taruvi/sdk';
import type {StorageListResponse} from '@taruvi/sdk';
await new Storage(client).from('BUCKET_SLUG')
.filter({search: 'invoice'}).execute<StorageListResponse>();
client.storage.from_("BUCKET_SLUG").filter(
search="invoice",
).list()
import {useList} from '@refinedev/core';
import type {StorageObject} from '@taruvi/sdk';
useList<StorageObject>({
dataProviderName: 'storage',
resource: 'BUCKET_SLUG',
filters: [{field: 'search', operator: 'eq', value: 'invoice'}],
});
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/Headers
AuthorizationApi-Key $TARUVI_API_KEY
Query parameters
searchinvoice
View cURL
curl --silent --show-error -G "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
--data-urlencode 'search=invoice'
200
Combine visibility with pagination:
- JavaScript SDK
- Python SDK
- Refine
- REST API
import {Storage} from '@taruvi/sdk';
import type {StorageListResponse} from '@taruvi/sdk';
await new Storage(client).from('BUCKET_SLUG')
.filter({visibility: 'public', page: 2, page_size: 50, ordering: '-created_at'}).execute<StorageListResponse>();
client.storage.from_("BUCKET_SLUG").filter(
visibility="public", page=2, page_size=50, ordering="-created_at",
).list()
import {useList} from '@refinedev/core';
import type {StorageObject} from '@taruvi/sdk';
useList<StorageObject>({
dataProviderName: 'storage',
resource: 'BUCKET_SLUG',
filters: [{field: 'visibility', operator: 'eq', value: 'public'}],
sorters: [{field: 'created_at', order: 'desc'}],
pagination: {currentPage: 2, pageSize: 50},
});
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/Headers
AuthorizationApi-Key $TARUVI_API_KEY
Query parameters
visibilitypublicpage2page_size50ordering-created_at
View cURL
curl --silent --show-error -G "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
--data-urlencode 'visibility=public' \
--data-urlencode 'page=2' \
--data-urlencode 'page_size=50' \
--data-urlencode 'ordering=-created_at'
200
Refine combines these filters with AND. Use operator: 'eq' for named query
parameters such as search or prefix.
The full filter grammar — range filters, MIME categories, path lookups, ordering — is on the Filter grammar reference.
Browse as folders#
GET /objects/browse/ treats paths as folders and returns one level at a time. It requires sign-in, even for public buckets.
- JavaScript SDK
- Python SDK
- Refine
- REST API
import {Storage} from '@taruvi/sdk';
import type {StorageBrowseResponse} from '@taruvi/sdk';
await new Storage(client).from('BUCKET_SLUG').browse({
prefix: 'documents/2024/', sort: 'name', order: 'asc', page: 1, page_size: 50,
}).execute<StorageBrowseResponse>();
The response’s data contains folders, objects, and has_next.
client.storage.from_("BUCKET_SLUG").browse(
prefix="documents/2024/", sort="name", order="asc", page=1, page_size=50,
)
The returned dictionary contains folders, objects, and has_next.
import {useList} from '@refinedev/core';
import type {StorageBrowseItem} from '@taruvi/refine-providers';
useList<StorageBrowseItem>({
dataProviderName: 'storage',
resource: 'BUCKET_SLUG',
meta: {mode: 'browse', prefix: 'documents/2024/'},
sorters: [{field: 'name', order: 'asc'}],
pagination: {currentPage: 1, pageSize: 50},
});
The hook’s result.data combines folders and files. Use a folder's path
as the next prefix, or a file's path to download it. The hook’s
result.total is a pagination estimate derived from has_next.
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/browse/Headers
AuthorizationApi-Key $TARUVI_API_KEY
Query parameters
prefixdocuments/2024/sortnameorderascpage1page_size50
View cURL
curl --silent --show-error -G "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/browse/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
--data-urlencode 'prefix=documents/2024/' \
--data-urlencode 'sort=name' \
--data-urlencode 'order=asc' \
--data-urlencode 'page=1' \
--data-urlencode 'page_size=50'
200
Response body:
{
"status": "success",
"message": "…",
"data": {
"prefix": "documents/2024/",
"folders": [{ "type": "folder", "name": "Q1", "path": "documents/2024/Q1/" }],
"objects": [{
"type": "file", "id": 1, "uuid": "…", "name": "report.pdf",
"path": "documents/2024/report.pdf", "size": 12345, "mimetype": "application/pdf",
"visibility": "private", "is_office_editable": false,
"created_at": "…", "updated_at": "…", "download_url": "…"
}],
"page": 1, "page_size": 50, "has_next": false
}
}
Navigate deeper by passing a folder's path back as prefix. Sort field is one of name, size, created_at, updated_at; order is asc or desc. page_size is bounded at 100.
Advanced search#
POST /objects/search/ accepts a JSON body for structured filtering with a bounded result limit.
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/search/Headers
AuthorizationApi-Key $TARUVI_API_KEYContent-Typeapplication/json
Request body
{
"prefix": "users/123/",
"search": "profile",
"sortBy": {
"column": "created_at",
"order": "desc"
},
"limit": 100,
"offset": 0
}
View cURL
curl --silent --show-error -X POST "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/search/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"prefix": "users/123/",
"search": "profile",
"sortBy": {
"column": "created_at",
"order": "desc"
},
"limit": 100,
"offset": 0
}
JSON
200
limit defaults to 100; a value above 1000 is rejected with 400. sortBy.column is one of filename, size, created_at, updated_at, path, mimetype; any other value falls back to created_at. The response envelope contains objects (the list) and bucket (the slug); total rides on the envelope.
Copy an object#
Copy leaves the source in place and creates a new object at the destination. Same-app operation — the destination bucket must live under the same app_slug as the source.
- Python SDK
- REST API
client.storage.from_("BUCKET_SLUG").copy_object(
"users/user-123/avatar.png",
"users/user-123/avatar.png",
destination_bucket="user-thumbnails",
)
user-thumbnails is an existing destination bucket in the same app. The
result is the copied object.
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/copy/Headers
AuthorizationApi-Key $TARUVI_API_KEYContent-Typeapplication/json
Request body
{
"source_path": "users/user-123/avatar.png",
"destination_bucket": "user-thumbnails",
"destination_path": "users/user-123/avatar.png"
}
View cURL
curl --silent --show-error -X POST "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/copy/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"source_path": "users/user-123/avatar.png",
"destination_bucket": "user-thumbnails",
"destination_path": "users/user-123/avatar.png"
}
JSON
201
destination_bucket is optional and defaults to the current bucket. Copy returns 201 Created. The caller needs read access to the source and upload access to the destination.
Move or rename#
Move rewrites the object. Same-bucket moves become a path rename; cross-bucket moves copy then delete.
Rename in place:
- Python SDK
- REST API
client.storage.from_("BUCKET_SLUG").move_object(
"temp/upload-1234.pdf",
"invoices/2024/Q3/INV-1234.pdf",
)
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/move/Headers
AuthorizationApi-Key $TARUVI_API_KEYContent-Typeapplication/json
Request body
{
"source_path": "temp/upload-1234.pdf",
"destination_path": "invoices/2024/Q3/INV-1234.pdf"
}
View cURL
curl --silent --show-error -X POST "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/move/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"source_path": "temp/upload-1234.pdf",
"destination_path": "invoices/2024/Q3/INV-1234.pdf"
}
JSON
200
Move to a different bucket in the same app:
/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/move/Headers
AuthorizationApi-Key $TARUVI_API_KEYContent-Typeapplication/json
Request body
{
"source_path": "drafts/report.docx",
"destination_bucket": "published-reports",
"destination_path": "2024/Q3/report.docx"
}
View cURL
curl --silent --show-error -X POST "$TARUVI_SITE_URL/api/apps/APP_SLUG/storage/buckets/BUCKET_SLUG/objects/move/" \
-H "Authorization: Api-Key $TARUVI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"source_path": "drafts/report.docx",
"destination_bucket": "published-reports",
"destination_path": "2024/Q3/report.docx"
}
JSON
200
Move failure modes:
409 Conflict— destination path is occupied. Rename the source or clear the destination first.400with"Cross-provider move is not supported"— source and destination buckets use differentstorage_providervalues. Download the object, upload it to the target bucket, and delete the source separately.404with"Source object 'PATH' not found"— thesource_pathdoes not match any object in the resolved source bucket.
Moving within a bucket needs update access. Moving to another bucket needs delete access on the source and upload access on the destination.
Related pages#
- Filter grammar for every filter parameter.
- Work with objects for upload, download, metadata, and single delete.
- Batch and SharePoint access for batch operations across many objects.