curl -X GET "https://api.tktchurch.com/v1/newsletters?page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listNewsletters = async (accessToken, page = 1, per = 10) => {
const response = await fetch(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletters = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', newsletters.items);
console.log('Pagination:', newsletters.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
struct NewsletterResponse: Codable {
let items: [Newsletter]
let metadata: PaginationMetadata
}
func listNewsletters(accessToken: String, page: Int = 1, per: Int = 10) async throws -> NewsletterResponse {
var urlComponents = URLComponents(string: "https://api.tktchurch.com/v1/newsletters")!
urlComponents.queryItems = [
URLQueryItem(name: "page", value: String(page)),
URLQueryItem(name: "per", value: String(per))
]
var request = URLRequest(url: urlComponents.url!)
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
return try JSONDecoder().decode(NewsletterResponse.self, from: data)
}
// Usage
do {
let response = try await listNewsletters(accessToken: "eyJhbGciOiJIUzI1NiIs...")
print("Newsletters:", response.items)
print("Pagination:", response.metadata)
} catch {
print("Failed to list newsletters:", error.localizedDescription)
}
data class NewsletterResponse(
val items: List<Newsletter>,
val metadata: PaginationMetadata
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun listNewsletters(
accessToken: String,
page: Int = 1,
per: Int = 10
): NewsletterResponse {
val url = HttpUrl.Builder()
.scheme("https")
.host("api.tktchurch.com")
.addPathSegments("v1/newsletters")
.addQueryParameter("page", page.toString())
.addQueryParameter("per", per.toString())
.build()
val request = Request.Builder()
.url(url)
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to list newsletters")
}
return response.body?.string()?.fromJson<NewsletterResponse>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val response = newsletterService.listNewsletters("eyJhbGciOiJIUzI1NiIs...")
println("Newsletters: ${response.items}")
println("Pagination: ${response.metadata}")
} catch (e: Exception) {
println("Failed to list newsletters: ${e.message}")
}
import axios from 'axios';
interface Newsletter {
id: string;
title: string;
content: string;
image?: {
id: string;
url: string;
};
imageUrl?: string;
pdf?: {
id: string;
url: string;
};
pdfUrl?: string;
hasPdf: boolean;
status: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
recipientCount: number;
createdAt: string;
updatedAt: string;
createdBy: string;
}
interface NewsletterResponse {
items: Newsletter[];
metadata: {
page: number;
per: number;
total: number;
};
}
const listNewsletters = async (
accessToken: string,
page: number = 1,
per: number = 10
): Promise<NewsletterResponse> => {
try {
const response = await axios.get(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to list newsletters');
}
throw error;
}
};
// Usage
try {
const response = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', response.items);
console.log('Pagination:', response.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"image": {
"id": "file-123",
"url": "https://cdn.tktchurch.com/files/newsletter-image.jpg"
},
"imageUrl": null,
"pdf": {
"id": "file-456",
"url": "https://cdn.tktchurch.com/files/newsletter.pdf"
},
"pdfUrl": null,
"hasPdf": true,
"status": "published",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 150,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 45
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: readNewsletter"
}
}
Newsletters
List Newsletters
Returns a paginated list of newsletters
GET
/
newsletters
curl -X GET "https://api.tktchurch.com/v1/newsletters?page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listNewsletters = async (accessToken, page = 1, per = 10) => {
const response = await fetch(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletters = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', newsletters.items);
console.log('Pagination:', newsletters.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
struct NewsletterResponse: Codable {
let items: [Newsletter]
let metadata: PaginationMetadata
}
func listNewsletters(accessToken: String, page: Int = 1, per: Int = 10) async throws -> NewsletterResponse {
var urlComponents = URLComponents(string: "https://api.tktchurch.com/v1/newsletters")!
urlComponents.queryItems = [
URLQueryItem(name: "page", value: String(page)),
URLQueryItem(name: "per", value: String(per))
]
var request = URLRequest(url: urlComponents.url!)
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
return try JSONDecoder().decode(NewsletterResponse.self, from: data)
}
// Usage
do {
let response = try await listNewsletters(accessToken: "eyJhbGciOiJIUzI1NiIs...")
print("Newsletters:", response.items)
print("Pagination:", response.metadata)
} catch {
print("Failed to list newsletters:", error.localizedDescription)
}
data class NewsletterResponse(
val items: List<Newsletter>,
val metadata: PaginationMetadata
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun listNewsletters(
accessToken: String,
page: Int = 1,
per: Int = 10
): NewsletterResponse {
val url = HttpUrl.Builder()
.scheme("https")
.host("api.tktchurch.com")
.addPathSegments("v1/newsletters")
.addQueryParameter("page", page.toString())
.addQueryParameter("per", per.toString())
.build()
val request = Request.Builder()
.url(url)
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to list newsletters")
}
return response.body?.string()?.fromJson<NewsletterResponse>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val response = newsletterService.listNewsletters("eyJhbGciOiJIUzI1NiIs...")
println("Newsletters: ${response.items}")
println("Pagination: ${response.metadata}")
} catch (e: Exception) {
println("Failed to list newsletters: ${e.message}")
}
import axios from 'axios';
interface Newsletter {
id: string;
title: string;
content: string;
image?: {
id: string;
url: string;
};
imageUrl?: string;
pdf?: {
id: string;
url: string;
};
pdfUrl?: string;
hasPdf: boolean;
status: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
recipientCount: number;
createdAt: string;
updatedAt: string;
createdBy: string;
}
interface NewsletterResponse {
items: Newsletter[];
metadata: {
page: number;
per: number;
total: number;
};
}
const listNewsletters = async (
accessToken: string,
page: number = 1,
per: number = 10
): Promise<NewsletterResponse> => {
try {
const response = await axios.get(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to list newsletters');
}
throw error;
}
};
// Usage
try {
const response = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', response.items);
console.log('Pagination:', response.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"image": {
"id": "file-123",
"url": "https://cdn.tktchurch.com/files/newsletter-image.jpg"
},
"imageUrl": null,
"pdf": {
"id": "file-456",
"url": "https://cdn.tktchurch.com/files/newsletter.pdf"
},
"pdfUrl": null,
"hasPdf": true,
"status": "published",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 150,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 45
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: readNewsletter"
}
}
This endpoint requires authentication and the
readNewsletter permission.Query Parameters
integer
default:"1"
Page number for pagination
integer
default:"10"
Number of newsletters per page
Response
array
Array of newsletter objects
Show Newsletter Object
Show Newsletter Object
string
Unique identifier for the newsletter (UUID)
string
Newsletter title
string
Newsletter content
string
External image URL if not using uploaded file
string
External PDF URL if not using uploaded file
boolean
Whether the newsletter has an associated PDF
string
Newsletter status. One of:
draft, scheduled, published, archivedstring
Scheduled or actual publication date (ISO 8601)
integer
Number of times the newsletter has been viewed/received
string
Creation timestamp (ISO 8601)
string
Last update timestamp (ISO 8601)
string
UUID of the user who created the newsletter
object
Error Responses
object
Common error cases:
- 401 Unauthorized: Missing or invalid access token
- 403 Forbidden: Missing required permission
curl -X GET "https://api.tktchurch.com/v1/newsletters?page=1&per=10" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const listNewsletters = async (accessToken, page = 1, per = 10) => {
const response = await fetch(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletters = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', newsletters.items);
console.log('Pagination:', newsletters.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
struct NewsletterResponse: Codable {
let items: [Newsletter]
let metadata: PaginationMetadata
}
func listNewsletters(accessToken: String, page: Int = 1, per: Int = 10) async throws -> NewsletterResponse {
var urlComponents = URLComponents(string: "https://api.tktchurch.com/v1/newsletters")!
urlComponents.queryItems = [
URLQueryItem(name: "page", value: String(page)),
URLQueryItem(name: "per", value: String(per))
]
var request = URLRequest(url: urlComponents.url!)
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
return try JSONDecoder().decode(NewsletterResponse.self, from: data)
}
// Usage
do {
let response = try await listNewsletters(accessToken: "eyJhbGciOiJIUzI1NiIs...")
print("Newsletters:", response.items)
print("Pagination:", response.metadata)
} catch {
print("Failed to list newsletters:", error.localizedDescription)
}
data class NewsletterResponse(
val items: List<Newsletter>,
val metadata: PaginationMetadata
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun listNewsletters(
accessToken: String,
page: Int = 1,
per: Int = 10
): NewsletterResponse {
val url = HttpUrl.Builder()
.scheme("https")
.host("api.tktchurch.com")
.addPathSegments("v1/newsletters")
.addQueryParameter("page", page.toString())
.addQueryParameter("per", per.toString())
.build()
val request = Request.Builder()
.url(url)
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to list newsletters")
}
return response.body?.string()?.fromJson<NewsletterResponse>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val response = newsletterService.listNewsletters("eyJhbGciOiJIUzI1NiIs...")
println("Newsletters: ${response.items}")
println("Pagination: ${response.metadata}")
} catch (e: Exception) {
println("Failed to list newsletters: ${e.message}")
}
import axios from 'axios';
interface Newsletter {
id: string;
title: string;
content: string;
image?: {
id: string;
url: string;
};
imageUrl?: string;
pdf?: {
id: string;
url: string;
};
pdfUrl?: string;
hasPdf: boolean;
status: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
recipientCount: number;
createdAt: string;
updatedAt: string;
createdBy: string;
}
interface NewsletterResponse {
items: Newsletter[];
metadata: {
page: number;
per: number;
total: number;
};
}
const listNewsletters = async (
accessToken: string,
page: number = 1,
per: number = 10
): Promise<NewsletterResponse> => {
try {
const response = await axios.get(
`https://api.tktchurch.com/v1/newsletters?page=${page}&per=${per}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to list newsletters');
}
throw error;
}
};
// Usage
try {
const response = await listNewsletters('eyJhbGciOiJIUzI1NiIs...');
console.log('Newsletters:', response.items);
console.log('Pagination:', response.metadata);
} catch (error) {
console.error('Failed to list newsletters:', error.message);
}
{
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"image": {
"id": "file-123",
"url": "https://cdn.tktchurch.com/files/newsletter-image.jpg"
},
"imageUrl": null,
"pdf": {
"id": "file-456",
"url": "https://cdn.tktchurch.com/files/newsletter.pdf"
},
"pdfUrl": null,
"hasPdf": true,
"status": "published",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 150,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
],
"metadata": {
"page": 1,
"per": 10,
"total": 45
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: readNewsletter"
}
}
