curl -X GET "https://api.tktchurch.com/v1/files/provider/s3/signed-url/uploads/abc123.jpg?expires=30" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const getSignedUrl = async (accessToken, provider, key, expiresInMinutes = 60) => {
const response = await fetch(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}?expires=${expiresInMinutes}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to get signed URL');
}
return response.text();
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
func getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
) async throws -> String {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files/provider/\(provider)/signed-url/\(key)")!
components.queryItems = [
URLQueryItem(name: "expires", value: String(expiresInMinutes))
]
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 String(decoding: data, as: UTF8.self)
}
// Usage
do {
let signedUrl = try await getSignedUrl(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
provider: "s3",
key: "uploads/abc123.jpg",
expiresInMinutes: 30
)
print("Signed URL:", signedUrl)
} catch {
print("Error:", error)
}
suspend fun getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
): String {
val url = buildString {
append("https://api.tktchurch.com/v1/files/provider/$provider/signed-url/$key")
append("?expires=$expiresInMinutes")
}
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}")
}
response.body?.string() ?: throw IOException("Empty response")
}
}
}
// Usage
try {
val signedUrl = getSignedUrl(
"eyJhbGciOiJIUzI1NiIs...",
"s3",
"uploads/abc123.jpg",
30
)
println("Signed URL: $signedUrl")
} catch (e: Exception) {
println("Error: ${e.message}")
}
const getSignedUrl = async (
accessToken: string,
provider: 's3' | 'local',
key: string,
expiresInMinutes: number = 60
): Promise<string> => {
try {
const response = await axios.get<string>(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params: {
expires: expiresInMinutes
}
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to get signed URL');
}
throw error;
}
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
https://storage.example.com/uploads/abc123.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
{
"error": {
"status": 400,
"reason": "Invalid provider specified"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: viewFiles"
}
}
{
"error": {
"status": 404,
"reason": "File not found"
}
}
Files
Get Signed URL
Get a signed URL for accessing a file
GET
/
files
/
provider
/
{provider}
/
signed-url
/
{key}
curl -X GET "https://api.tktchurch.com/v1/files/provider/s3/signed-url/uploads/abc123.jpg?expires=30" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const getSignedUrl = async (accessToken, provider, key, expiresInMinutes = 60) => {
const response = await fetch(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}?expires=${expiresInMinutes}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to get signed URL');
}
return response.text();
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
func getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
) async throws -> String {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files/provider/\(provider)/signed-url/\(key)")!
components.queryItems = [
URLQueryItem(name: "expires", value: String(expiresInMinutes))
]
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 String(decoding: data, as: UTF8.self)
}
// Usage
do {
let signedUrl = try await getSignedUrl(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
provider: "s3",
key: "uploads/abc123.jpg",
expiresInMinutes: 30
)
print("Signed URL:", signedUrl)
} catch {
print("Error:", error)
}
suspend fun getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
): String {
val url = buildString {
append("https://api.tktchurch.com/v1/files/provider/$provider/signed-url/$key")
append("?expires=$expiresInMinutes")
}
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}")
}
response.body?.string() ?: throw IOException("Empty response")
}
}
}
// Usage
try {
val signedUrl = getSignedUrl(
"eyJhbGciOiJIUzI1NiIs...",
"s3",
"uploads/abc123.jpg",
30
)
println("Signed URL: $signedUrl")
} catch (e: Exception) {
println("Error: ${e.message}")
}
const getSignedUrl = async (
accessToken: string,
provider: 's3' | 'local',
key: string,
expiresInMinutes: number = 60
): Promise<string> => {
try {
const response = await axios.get<string>(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params: {
expires: expiresInMinutes
}
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to get signed URL');
}
throw error;
}
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
https://storage.example.com/uploads/abc123.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
{
"error": {
"status": 400,
"reason": "Invalid provider specified"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: viewFiles"
}
}
{
"error": {
"status": 404,
"reason": "File not found"
}
}
This endpoint requires authentication and the
viewFiles permission.Path Parameters
string
required
The storage provider. One of:
s3: Amazon S3 storagelocal: Local file storage
string
required
The storage key/path of the file
Query Parameters
integer
Number of minutes until the signed URL expires (default: 60)
Response
Returns a string containing the signed URL that can be used to access the file.Error Responses
object
Common error cases:
- 400 Bad Request: Invalid provider or key
- 401 Unauthorized: Missing or invalid access token
- 403 Forbidden: Missing required permission
- 404 Not Found: File not found
curl -X GET "https://api.tktchurch.com/v1/files/provider/s3/signed-url/uploads/abc123.jpg?expires=30" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const getSignedUrl = async (accessToken, provider, key, expiresInMinutes = 60) => {
const response = await fetch(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}?expires=${expiresInMinutes}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.reason || 'Failed to get signed URL');
}
return response.text();
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
func getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
) async throws -> String {
var components = URLComponents(string: "https://api.tktchurch.com/v1/files/provider/\(provider)/signed-url/\(key)")!
components.queryItems = [
URLQueryItem(name: "expires", value: String(expiresInMinutes))
]
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 String(decoding: data, as: UTF8.self)
}
// Usage
do {
let signedUrl = try await getSignedUrl(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
provider: "s3",
key: "uploads/abc123.jpg",
expiresInMinutes: 30
)
print("Signed URL:", signedUrl)
} catch {
print("Error:", error)
}
suspend fun getSignedUrl(
accessToken: String,
provider: String,
key: String,
expiresInMinutes: Int = 60
): String {
val url = buildString {
append("https://api.tktchurch.com/v1/files/provider/$provider/signed-url/$key")
append("?expires=$expiresInMinutes")
}
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}")
}
response.body?.string() ?: throw IOException("Empty response")
}
}
}
// Usage
try {
val signedUrl = getSignedUrl(
"eyJhbGciOiJIUzI1NiIs...",
"s3",
"uploads/abc123.jpg",
30
)
println("Signed URL: $signedUrl")
} catch (e: Exception) {
println("Error: ${e.message}")
}
const getSignedUrl = async (
accessToken: string,
provider: 's3' | 'local',
key: string,
expiresInMinutes: number = 60
): Promise<string> => {
try {
const response = await axios.get<string>(
`https://api.tktchurch.com/v1/files/provider/${provider}/signed-url/${key}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
params: {
expires: expiresInMinutes
}
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.reason || 'Failed to get signed URL');
}
throw error;
}
};
// Usage
try {
const signedUrl = await getSignedUrl(
'eyJhbGciOiJIUzI1NiIs...',
's3',
'uploads/abc123.jpg',
30
);
console.log('Signed URL:', signedUrl);
} catch (error) {
console.error('Error:', error.message);
}
https://storage.example.com/uploads/abc123.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
{
"error": {
"status": 400,
"reason": "Invalid provider specified"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: viewFiles"
}
}
{
"error": {
"status": 404,
"reason": "File not found"
}
}
