> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tktchurch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List Files

> List files with optional filtering

<Note>
  This endpoint requires authentication.
</Note>

### Query Parameters

<ParamField query="search" type="string" required={false}>
  Search term to filter files by name or content type
</ParamField>

<ParamField query="uploadedBy" type="string" required={false}>
  Filter by UUID of the user who uploaded the files
</ParamField>

<ParamField query="contentType" type="string" required={false}>
  Filter by file content type (MIME type)
</ParamField>

<ParamField query="startDate" type="string" required={false}>
  Filter by upload date range start (ISO 8601 format)
</ParamField>

<ParamField query="endDate" type="string" required={false}>
  Filter by upload date range end (ISO 8601 format)
</ParamField>

<ParamField query="provider" type="string" required={false}>
  Filter by storage provider (s3 or local)
</ParamField>

<ParamField query="page" type="integer" required={false}>
  Page number for pagination (default: 1)
</ParamField>

<ParamField query="per" type="integer" required={false}>
  Items per page (default: 10, max: 100)
</ParamField>

### Response

<ResponseField name="items" type="array">
  Array of file objects

  <Expandable title="File Object">
    <ResponseField name="id" type="string">
      File's unique identifier (UUID)
    </ResponseField>

    <ResponseField name="originalName" type="string">
      Original filename
    </ResponseField>

    <ResponseField name="url" type="string">
      URL to access the file
    </ResponseField>

    <ResponseField name="key" type="string">
      Storage key/path of the file
    </ResponseField>

    <ResponseField name="contentType" type="string">
      MIME type of the file
    </ResponseField>

    <ResponseField name="size" type="integer">
      File size in bytes
    </ResponseField>

    <ResponseField name="provider" type="string">
      Storage provider used (s3 or local)
    </ResponseField>

    <ResponseField name="providerMetadata" type="object" required={false}>
      Provider-specific metadata
    </ResponseField>

    <ResponseField name="uploadedBy" type="string">
      UUID of the user who uploaded the file
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      Upload timestamp in ISO 8601 format
    </ResponseField>

    <ResponseField name="updatedAt" type="string">
      Last update timestamp in ISO 8601 format
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="metadata" type="object">
  Pagination metadata

  <Expandable title="Metadata Object">
    <ResponseField name="page" type="integer">
      Current page number
    </ResponseField>

    <ResponseField name="per" type="integer">
      Items per page
    </ResponseField>

    <ResponseField name="total" type="integer">
      Total number of items
    </ResponseField>

    <ResponseField name="pageCount" type="integer">
      Total number of pages
    </ResponseField>
  </Expandable>
</ResponseField>

### Error Responses

<ResponseField name="error" type="object">
  Error details when the request fails

  <Expandable title="Error Object">
    <ResponseField name="status" type="integer">
      HTTP status code
    </ResponseField>

    <ResponseField name="reason" type="string">
      Error message explaining why the request failed
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  Common error cases:

  * 401 Unauthorized: Missing or invalid access token
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://api.tktchurch.com/v1/files?search=example&provider=s3&page=1&per=10" \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
  ```

  ```javascript JavaScript theme={null}
  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);
  }
  ```

  ```swift Swift theme={null}
  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)
  }
  ```

  ```kotlin Kotlin theme={null}
  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}")
  }
  ```

  ```typescript React Native theme={null}
  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);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "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
    }
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error": {
      "status": 401,
      "reason": "Invalid or expired access token"
    }
  }
  ```
</ResponseExample>
