curl -X POST "https://api.tktchurch.com/v1/newsletters" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"imageId": "file-123",
"pdfId": "file-456",
"status": "draft",
"publishDate": "2024-01-01T12:00:00Z"
}'
const createNewsletter = async (accessToken, newsletter) => {
const response = await fetch(
'https://api.tktchurch.com/v1/newsletters',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(newsletter)
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletter = await createNewsletter('eyJhbGciOiJIUzI1NiIs...', {
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
});
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
struct CreateNewsletterRequest: Codable {
let title: String
let content: String
let imageId: String?
let imageUrl: String?
let pdfId: String?
let pdfUrl: String?
let status: String?
let publishDate: Date?
}
func createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest) async throws -> Newsletter {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/newsletters")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
urlRequest.httpBody = try encoder.encode(newsletter)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
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
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(Newsletter.self, from: data)
}
// Usage
do {
let request = CreateNewsletterRequest(
title: "January Church Updates",
content: "Welcome to our first newsletter of 2024...",
imageId: "file-123",
imageUrl: nil,
pdfId: "file-456",
pdfUrl: nil,
status: "draft",
publishDate: ISO8601DateFormatter().date(from: "2024-01-01T12:00:00Z")
)
let newsletter = try await createNewsletter(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
newsletter: request
)
print("Created newsletter:", newsletter)
} catch {
print("Failed to create newsletter:", error.localizedDescription)
}
data class CreateNewsletterRequest(
val title: String,
val content: String,
val imageId: String? = null,
val imageUrl: String? = null,
val pdfId: String? = null,
val pdfUrl: String? = null,
val status: String? = null,
val publishDate: String? = null
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest): Newsletter {
val requestBody = newsletter.toJson()
.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/newsletters")
.post(requestBody)
.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 create newsletter")
}
return response.body?.string()?.fromJson<Newsletter>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val request = CreateNewsletterRequest(
title = "January Church Updates",
content = "Welcome to our first newsletter of 2024...",
imageId = "file-123",
pdfId = "file-456",
status = "draft",
publishDate = "2024-01-01T12:00:00Z"
)
val newsletter = newsletterService.createNewsletter(
"eyJhbGciOiJIUzI1NiIs...",
request
)
println("Created newsletter: $newsletter")
} catch (e: Exception) {
println("Failed to create newsletter: ${e.message}")
}
import axios from 'axios';
interface CreateNewsletterRequest {
title: string;
content: string;
imageId?: string;
imageUrl?: string;
pdfId?: string;
pdfUrl?: string;
status?: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
}
const createNewsletter = async (
accessToken: string,
newsletter: CreateNewsletterRequest
): Promise<Newsletter> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/newsletters',
newsletter,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to create newsletter');
}
throw error;
}
};
// Usage
try {
const newsletter = await createNewsletter(
'eyJhbGciOiJIUzI1NiIs...',
{
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
}
);
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
{
"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": "draft",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 0,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2023-12-30T15:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
{
"error": {
"status": 400,
"reason": "Title is required"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: createNewsletter"
}
}
Newsletters
Create Newsletter
Create a new newsletter
POST
/
newsletters
curl -X POST "https://api.tktchurch.com/v1/newsletters" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"imageId": "file-123",
"pdfId": "file-456",
"status": "draft",
"publishDate": "2024-01-01T12:00:00Z"
}'
const createNewsletter = async (accessToken, newsletter) => {
const response = await fetch(
'https://api.tktchurch.com/v1/newsletters',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(newsletter)
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletter = await createNewsletter('eyJhbGciOiJIUzI1NiIs...', {
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
});
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
struct CreateNewsletterRequest: Codable {
let title: String
let content: String
let imageId: String?
let imageUrl: String?
let pdfId: String?
let pdfUrl: String?
let status: String?
let publishDate: Date?
}
func createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest) async throws -> Newsletter {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/newsletters")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
urlRequest.httpBody = try encoder.encode(newsletter)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
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
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(Newsletter.self, from: data)
}
// Usage
do {
let request = CreateNewsletterRequest(
title: "January Church Updates",
content: "Welcome to our first newsletter of 2024...",
imageId: "file-123",
imageUrl: nil,
pdfId: "file-456",
pdfUrl: nil,
status: "draft",
publishDate: ISO8601DateFormatter().date(from: "2024-01-01T12:00:00Z")
)
let newsletter = try await createNewsletter(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
newsletter: request
)
print("Created newsletter:", newsletter)
} catch {
print("Failed to create newsletter:", error.localizedDescription)
}
data class CreateNewsletterRequest(
val title: String,
val content: String,
val imageId: String? = null,
val imageUrl: String? = null,
val pdfId: String? = null,
val pdfUrl: String? = null,
val status: String? = null,
val publishDate: String? = null
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest): Newsletter {
val requestBody = newsletter.toJson()
.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/newsletters")
.post(requestBody)
.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 create newsletter")
}
return response.body?.string()?.fromJson<Newsletter>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val request = CreateNewsletterRequest(
title = "January Church Updates",
content = "Welcome to our first newsletter of 2024...",
imageId = "file-123",
pdfId = "file-456",
status = "draft",
publishDate = "2024-01-01T12:00:00Z"
)
val newsletter = newsletterService.createNewsletter(
"eyJhbGciOiJIUzI1NiIs...",
request
)
println("Created newsletter: $newsletter")
} catch (e: Exception) {
println("Failed to create newsletter: ${e.message}")
}
import axios from 'axios';
interface CreateNewsletterRequest {
title: string;
content: string;
imageId?: string;
imageUrl?: string;
pdfId?: string;
pdfUrl?: string;
status?: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
}
const createNewsletter = async (
accessToken: string,
newsletter: CreateNewsletterRequest
): Promise<Newsletter> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/newsletters',
newsletter,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to create newsletter');
}
throw error;
}
};
// Usage
try {
const newsletter = await createNewsletter(
'eyJhbGciOiJIUzI1NiIs...',
{
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
}
);
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
{
"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": "draft",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 0,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2023-12-30T15:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
{
"error": {
"status": 400,
"reason": "Title is required"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: createNewsletter"
}
}
This endpoint requires authentication and the
createNewsletter permission.Request Body
string
required
Newsletter title
string
required
Newsletter content
string
ID of the uploaded image file
string
External image URL if not using uploaded file
string
ID of the uploaded PDF file
string
External PDF URL if not using uploaded file
string
default:"draft"
Newsletter status. One of:
draft, scheduled, published, archivedstring
Scheduled publication date (ISO 8601)
Response
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 (starts at 0)
string
Creation timestamp (ISO 8601)
string
Last update timestamp (ISO 8601)
string
UUID of the user who created the newsletter
Error Responses
object
Common error cases:
- 400 Bad Request: Invalid request body or validation error
- 401 Unauthorized: Missing or invalid access token
- 403 Forbidden: Missing required permission
curl -X POST "https://api.tktchurch.com/v1/newsletters" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"title": "January Church Updates",
"content": "Welcome to our first newsletter of 2024...",
"imageId": "file-123",
"pdfId": "file-456",
"status": "draft",
"publishDate": "2024-01-01T12:00:00Z"
}'
const createNewsletter = async (accessToken, newsletter) => {
const response = await fetch(
'https://api.tktchurch.com/v1/newsletters',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(newsletter)
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.json();
};
// Usage
try {
const newsletter = await createNewsletter('eyJhbGciOiJIUzI1NiIs...', {
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
});
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
struct CreateNewsletterRequest: Codable {
let title: String
let content: String
let imageId: String?
let imageUrl: String?
let pdfId: String?
let pdfUrl: String?
let status: String?
let publishDate: Date?
}
func createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest) async throws -> Newsletter {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/newsletters")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
urlRequest.httpBody = try encoder.encode(newsletter)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
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
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(Newsletter.self, from: data)
}
// Usage
do {
let request = CreateNewsletterRequest(
title: "January Church Updates",
content: "Welcome to our first newsletter of 2024...",
imageId: "file-123",
imageUrl: nil,
pdfId: "file-456",
pdfUrl: nil,
status: "draft",
publishDate: ISO8601DateFormatter().date(from: "2024-01-01T12:00:00Z")
)
let newsletter = try await createNewsletter(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
newsletter: request
)
print("Created newsletter:", newsletter)
} catch {
print("Failed to create newsletter:", error.localizedDescription)
}
data class CreateNewsletterRequest(
val title: String,
val content: String,
val imageId: String? = null,
val imageUrl: String? = null,
val pdfId: String? = null,
val pdfUrl: String? = null,
val status: String? = null,
val publishDate: String? = null
)
class NewsletterService(private val client: OkHttpClient) {
suspend fun createNewsletter(accessToken: String, newsletter: CreateNewsletterRequest): Newsletter {
val requestBody = newsletter.toJson()
.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/newsletters")
.post(requestBody)
.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 create newsletter")
}
return response.body?.string()?.fromJson<Newsletter>()
?: throw Exception("Empty response")
}
}
}
// Usage
try {
val request = CreateNewsletterRequest(
title = "January Church Updates",
content = "Welcome to our first newsletter of 2024...",
imageId = "file-123",
pdfId = "file-456",
status = "draft",
publishDate = "2024-01-01T12:00:00Z"
)
val newsletter = newsletterService.createNewsletter(
"eyJhbGciOiJIUzI1NiIs...",
request
)
println("Created newsletter: $newsletter")
} catch (e: Exception) {
println("Failed to create newsletter: ${e.message}")
}
import axios from 'axios';
interface CreateNewsletterRequest {
title: string;
content: string;
imageId?: string;
imageUrl?: string;
pdfId?: string;
pdfUrl?: string;
status?: 'draft' | 'scheduled' | 'published' | 'archived';
publishDate?: string;
}
const createNewsletter = async (
accessToken: string,
newsletter: CreateNewsletterRequest
): Promise<Newsletter> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/newsletters',
newsletter,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
}
);
return response.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to create newsletter');
}
throw error;
}
};
// Usage
try {
const newsletter = await createNewsletter(
'eyJhbGciOiJIUzI1NiIs...',
{
title: 'January Church Updates',
content: 'Welcome to our first newsletter of 2024...',
imageId: 'file-123',
pdfId: 'file-456',
status: 'draft',
publishDate: '2024-01-01T12:00:00Z'
}
);
console.log('Created newsletter:', newsletter);
} catch (error) {
console.error('Failed to create newsletter:', error.message);
}
{
"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": "draft",
"publishDate": "2024-01-01T12:00:00Z",
"recipientCount": 0,
"createdAt": "2023-12-30T15:00:00Z",
"updatedAt": "2023-12-30T15:00:00Z",
"createdBy": "user-123e4567-e89b-12d3-a456-426614174000"
}
{
"error": {
"status": 400,
"reason": "Title is required"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Missing required permission: createNewsletter"
}
}
