The Alga PSA REST API is easy to call from TypeScript with a small fetch wrapper. This guide shows a practical pattern for tickets: one request helper, typed payloads, and explicit error handling.
const API_BASE = 'https://algapsa.com';
const API_KEY = process.env.ALGA_API_KEY!;
type AlgaError = {
error?: {
code?: string;
message?: string;
details?: unknown;
};
};
async function algaFetch<T>(path: string, init?: RequestInit): Promise<T> {
const response = await fetch(API_BASE + path, {
...init,
headers: {
'X-API-Key': API_KEY,
...(init?.body ? { 'Content-Type': 'application/json' } : {}),
...(init?.headers ?? {}),
},
});
const payload = (await response.json()) as T & AlgaError;
if (!response.ok) {
throw new Error(payload.error?.message ?? 'Request failed');
}
return payload;
}export type CreateTicketInput = {
title: string;
board_id: string;
client_id: string;
status_id: string;
priority_id: string;
assigned_to?: string;
category_id?: string;
tags?: string[];
};
export type TicketRecord = {
ticket_id: string;
ticket_number: string;
title: string;
board_id: string;
client_id: string;
status_id: string;
priority_id: string;
};export async function listTickets(page = 1, limit = 25) {
return algaFetch<{
data: TicketRecord[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
};
}>('/api/v1/tickets?page=' + page + '&limit=' + limit);
}export async function createTicket(input: CreateTicketInput) {
return algaFetch<{ data: TicketRecord }>('/api/v1/tickets', {
method: 'POST',
body: JSON.stringify(input),
});
}
export async function updateTicket(ticketId: string, updates: Partial<CreateTicketInput>) {
return algaFetch<{ data: TicketRecord }>('/api/v1/tickets/' + ticketId, {
method: 'PUT',
body: JSON.stringify(updates),
});
}