curl -X GET "https://api.tktchurch.com/v1/files?search=example&provider=s3&page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listFiles = async (accessToken, params = {}) => {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(
`https://api.tktchurch.com/v1/files?${queryString}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to list files');
}
return response.json();
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
struct FilesResponse: Codable {
let items: [File]
let metadata: PageMetadata
struct PageMetadata: Codable {
let page: Int
let per: Int
let total: Int
let pageCount: Int
}
}
func listFiles(
accessToken: String,
search: String? = nil,
provider: String? = nil,
page: Int? = nil,
per: Int? = nil
) async throws -> FilesResponse {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files")!
var queryItems: [URLQueryItem] = []
if let search = search {
queryItems.append(URLQueryItem(name: "search", value: search))
}
if let provider = provider {
queryItems.append(URLQueryItem(name: "provider", value: provider))
}
if let page = page {
queryItems.append(URLQueryItem(name: "page", value: String(page)))
}
if let per = per {
queryItems.append(URLQueryItem(name: "per", value: String(per)))
}
components.queryItems = queryItems
var urlRequest = URLRequest(url: components.url!)
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(FilesResponse.self, from: data)
}
// Usage
do {
let files = try await listFiles(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
search: "example",
provider: "s3",
page: 1,
per: 10
)
print("Files:", files)
} catch {
print("Error:", error)
}
data class FilesResponse(
val items: List<File>,
val metadata: PageMetadata
) {
data class PageMetadata(
val page: Int,
val per: Int,
val total: Int,
val pageCount: Int
)
}
suspend fun listFiles(
accessToken: String,
search: String? = null,
provider: String? = null,
page: Int? = null,
per: Int? = null
): FilesResponse {
val url = buildString {
append("https://api.tktchurch.com/v1/files")
val params = listOfNotNull(
search?.let { "search=$it" },
provider?.let { "provider=$it" },
page?.let { "page=$it" },
per?.let { "per=$it" }
)
if (params.isNotEmpty()) {
append("?${params.joinToString("&")}")
}
}
val request = Request.Builder()
.url(url)
.get()
.header("Authorization", "Bearer $accessToken")
.build()
return withContext(Dispatchers.IO) {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected response ${response.code}")
}
val body = response.body?.string() ?: throw IOException("Empty response")
Json.decodeFromString<FilesResponse>(body)
}
}
}
// Usage
try {
val files = listFiles(
"eyJhbGciOiJIUzI1NiIs...",
search = "example",
provider = "s3",
page = 1,
per = 10
)
println("Files: $files")
} catch (e: Exception) {
println("Error: ${e.message}")
}
interface File {
id: string;
originalName: string;
url: string;
key: string;
contentType: string;
size: number;
provider: 's3' | 'local';
providerMetadata?: Record<string, string>;
uploadedBy: string;
createdAt: string;
updatedAt: string;
}
interface PageMetadata {
page: number;
per: number;
total: number;
pageCount: number;
}
interface FilesResponse {
items: File[];
metadata: PageMetadata;
}
interface ListFilesParams {
search?: string;
provider?: 's3' | 'local';
page?: number;
per?: number;
}
const listFiles = async (
accessToken: string,
params: ListFilesParams = {}
): Promise<FilesResponse> => {
try {
const response = await axios.get<FilesResponse>(
'https://api.tktchurch.com/v1/files',
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to list files');
}
throw error;
}
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"originalName": "example.jpg",
"url": "https://storage.example.com/uploads/abc123.jpg",
"key": "uploads/abc123.jpg",
"contentType": "image/jpeg",
"size": 1048576,
"provider": "s3",
"providerMetadata": {
"bucket": "my-bucket",
"region": "us-east-1"
},
"uploadedBy": "123e4567-e89b-12d3-a456-426614174001",
"createdAt": "2024-01-20T15:00:00Z",
"updatedAt": "2024-01-20T15:00:00Z"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 1,
"pageCount": 1
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
Files
List Files
List files with optional filtering
GET
/
files
curl -X GET "https://api.tktchurch.com/v1/files?search=example&provider=s3&page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listFiles = async (accessToken, params = {}) => {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(
`https://api.tktchurch.com/v1/files?${queryString}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to list files');
}
return response.json();
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
struct FilesResponse: Codable {
let items: [File]
let metadata: PageMetadata
struct PageMetadata: Codable {
let page: Int
let per: Int
let total: Int
let pageCount: Int
}
}
func listFiles(
accessToken: String,
search: String? = nil,
provider: String? = nil,
page: Int? = nil,
per: Int? = nil
) async throws -> FilesResponse {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files")!
var queryItems: [URLQueryItem] = []
if let search = search {
queryItems.append(URLQueryItem(name: "search", value: search))
}
if let provider = provider {
queryItems.append(URLQueryItem(name: "provider", value: provider))
}
if let page = page {
queryItems.append(URLQueryItem(name: "page", value: String(page)))
}
if let per = per {
queryItems.append(URLQueryItem(name: "per", value: String(per)))
}
components.queryItems = queryItems
var urlRequest = URLRequest(url: components.url!)
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(FilesResponse.self, from: data)
}
// Usage
do {
let files = try await listFiles(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
search: "example",
provider: "s3",
page: 1,
per: 10
)
print("Files:", files)
} catch {
print("Error:", error)
}
data class FilesResponse(
val items: List<File>,
val metadata: PageMetadata
) {
data class PageMetadata(
val page: Int,
val per: Int,
val total: Int,
val pageCount: Int
)
}
suspend fun listFiles(
accessToken: String,
search: String? = null,
provider: String? = null,
page: Int? = null,
per: Int? = null
): FilesResponse {
val url = buildString {
append("https://api.tktchurch.com/v1/files")
val params = listOfNotNull(
search?.let { "search=$it" },
provider?.let { "provider=$it" },
page?.let { "page=$it" },
per?.let { "per=$it" }
)
if (params.isNotEmpty()) {
append("?${params.joinToString("&")}")
}
}
val request = Request.Builder()
.url(url)
.get()
.header("Authorization", "Bearer $accessToken")
.build()
return withContext(Dispatchers.IO) {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected response ${response.code}")
}
val body = response.body?.string() ?: throw IOException("Empty response")
Json.decodeFromString<FilesResponse>(body)
}
}
}
// Usage
try {
val files = listFiles(
"eyJhbGciOiJIUzI1NiIs...",
search = "example",
provider = "s3",
page = 1,
per = 10
)
println("Files: $files")
} catch (e: Exception) {
println("Error: ${e.message}")
}
interface File {
id: string;
originalName: string;
url: string;
key: string;
contentType: string;
size: number;
provider: 's3' | 'local';
providerMetadata?: Record<string, string>;
uploadedBy: string;
createdAt: string;
updatedAt: string;
}
interface PageMetadata {
page: number;
per: number;
total: number;
pageCount: number;
}
interface FilesResponse {
items: File[];
metadata: PageMetadata;
}
interface ListFilesParams {
search?: string;
provider?: 's3' | 'local';
page?: number;
per?: number;
}
const listFiles = async (
accessToken: string,
params: ListFilesParams = {}
): Promise<FilesResponse> => {
try {
const response = await axios.get<FilesResponse>(
'https://api.tktchurch.com/v1/files',
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to list files');
}
throw error;
}
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"originalName": "example.jpg",
"url": "https://storage.example.com/uploads/abc123.jpg",
"key": "uploads/abc123.jpg",
"contentType": "image/jpeg",
"size": 1048576,
"provider": "s3",
"providerMetadata": {
"bucket": "my-bucket",
"region": "us-east-1"
},
"uploadedBy": "123e4567-e89b-12d3-a456-426614174001",
"createdAt": "2024-01-20T15:00:00Z",
"updatedAt": "2024-01-20T15:00:00Z"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 1,
"pageCount": 1
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
This endpoint requires authentication.
Query Parameters
string
Search term to filter files by name or content type
string
Filter by UUID of the user who uploaded the files
string
Filter by file content type (MIME type)
string
Filter by upload date range start (ISO 8601 format)
string
Filter by upload date range end (ISO 8601 format)
string
Filter by storage provider (s3 or local)
integer
Page number for pagination (default: 1)
integer
Items per page (default: 10, max: 100)
Response
array
Array of file objects
Show File Object
Show File Object
string
File’s unique identifier (UUID)
string
Original filename
string
URL to access the file
string
Storage key/path of the file
string
MIME type of the file
integer
File size in bytes
string
Storage provider used (s3 or local)
object
Provider-specific metadata
string
UUID of the user who uploaded the file
string
Upload timestamp in ISO 8601 format
string
Last update timestamp in ISO 8601 format
object
Error Responses
object
Common error cases:
- 401 Unauthorized: Missing or invalid access token
curl -X GET "https://api.tktchurch.com/v1/files?search=example&provider=s3&page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listFiles = async (accessToken, params = {}) => {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(
`https://api.tktchurch.com/v1/files?${queryString}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to list files');
}
return response.json();
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
struct FilesResponse: Codable {
let items: [File]
let metadata: PageMetadata
struct PageMetadata: Codable {
let page: Int
let per: Int
let total: Int
let pageCount: Int
}
}
func listFiles(
accessToken: String,
search: String? = nil,
provider: String? = nil,
page: Int? = nil,
per: Int? = nil
) async throws -> FilesResponse {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files")!
var queryItems: [URLQueryItem] = []
if let search = search {
queryItems.append(URLQueryItem(name: "search", value: search))
}
if let provider = provider {
queryItems.append(URLQueryItem(name: "provider", value: provider))
}
if let page = page {
queryItems.append(URLQueryItem(name: "page", value: String(page)))
}
if let per = per {
queryItems.append(URLQueryItem(name: "per", value: String(per)))
}
components.queryItems = queryItems
var urlRequest = URLRequest(url: components.url!)
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(FilesResponse.self, from: data)
}
// Usage
do {
let files = try await listFiles(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
search: "example",
provider: "s3",
page: 1,
per: 10
)
print("Files:", files)
} catch {
print("Error:", error)
}
data class FilesResponse(
val items: List<File>,
val metadata: PageMetadata
) {
data class PageMetadata(
val page: Int,
val per: Int,
val total: Int,
val pageCount: Int
)
}
suspend fun listFiles(
accessToken: String,
search: String? = null,
provider: String? = null,
page: Int? = null,
per: Int? = null
): FilesResponse {
val url = buildString {
append("https://api.tktchurch.com/v1/files")
val params = listOfNotNull(
search?.let { "search=$it" },
provider?.let { "provider=$it" },
page?.let { "page=$it" },
per?.let { "per=$it" }
)
if (params.isNotEmpty()) {
append("?${params.joinToString("&")}")
}
}
val request = Request.Builder()
.url(url)
.get()
.header("Authorization", "Bearer $accessToken")
.build()
return withContext(Dispatchers.IO) {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected response ${response.code}")
}
val body = response.body?.string() ?: throw IOException("Empty response")
Json.decodeFromString<FilesResponse>(body)
}
}
}
// Usage
try {
val files = listFiles(
"eyJhbGciOiJIUzI1NiIs...",
search = "example",
provider = "s3",
page = 1,
per = 10
)
println("Files: $files")
} catch (e: Exception) {
println("Error: ${e.message}")
}
interface File {
id: string;
originalName: string;
url: string;
key: string;
contentType: string;
size: number;
provider: 's3' | 'local';
providerMetadata?: Record<string, string>;
uploadedBy: string;
createdAt: string;
updatedAt: string;
}
interface PageMetadata {
page: number;
per: number;
total: number;
pageCount: number;
}
interface FilesResponse {
items: File[];
metadata: PageMetadata;
}
interface ListFilesParams {
search?: string;
provider?: 's3' | 'local';
page?: number;
per?: number;
}
const listFiles = async (
accessToken: string,
params: ListFilesParams = {}
): Promise<FilesResponse> => {
try {
const response = await axios.get<FilesResponse>(
'https://api.tktchurch.com/v1/files',
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to list files');
}
throw error;
}
};
// Usage
try {
const files = await listFiles(
'eyJhbGciOiJIUzI1NiIs...',
{
search: 'example',
provider: 's3',
page: 1,
per: 10
}
);
console.log('Files:', files);
} catch (error) {
console.error('Error:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"originalName": "example.jpg",
"url": "https://storage.example.com/uploads/abc123.jpg",
"key": "uploads/abc123.jpg",
"contentType": "image/jpeg",
"size": 1048576,
"provider": "s3",
"providerMetadata": {
"bucket": "my-bucket",
"region": "us-east-1"
},
"uploadedBy": "123e4567-e89b-12d3-a456-426614174001",
"createdAt": "2024-01-20T15:00:00Z",
"updatedAt": "2024-01-20T15:00:00Z"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 1,
"pageCount": 1
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
