Skip to main content
Glama
schemas.ts5.82 kB
/** * TimeEntry Zod Schemas * * Type-safe schemas for TimeEntry operations. * Maps directly to FreshBooks TimeEntry API. */ import { z } from 'zod'; /** * Timer schema (embedded in TimeEntry) */ export const TimerSchema = z.object({ id: z.number().optional(), isRunning: z.boolean().nullable().optional(), }); /** * Full TimeEntry entity schema */ export const TimeEntrySchema = z.object({ id: z.number().optional(), identityId: z.number().optional(), isLogged: z.boolean(), startedAt: z.string().datetime(), createdAt: z.string().datetime().optional(), clientId: z.number().nullable().optional(), projectId: z.number().nullable().optional(), pendingClient: z.string().nullable().optional(), pendingProject: z.string().nullable().optional(), pendingTask: z.string().nullable().optional(), taskId: z.number().nullable().optional(), serviceId: z.number().nullable().optional(), note: z.string().nullable().optional(), active: z.boolean().optional(), billable: z.boolean().optional(), billed: z.boolean().optional(), internal: z.boolean().optional(), retainerId: z.number().nullable().optional(), duration: z.number(), timer: TimerSchema.nullable().optional(), }); /** * Input schema for creating a time entry */ export const TimeEntryCreateInputSchema = z.object({ accountId: z.string().describe('FreshBooks account ID'), duration: z.number().min(0).describe('Duration in seconds (0 for active timer)'), isLogged: z.boolean().default(true).describe('Whether time is logged (false for active timer)'), startedAt: z .string() .datetime() .optional() .describe('Start time (ISO 8601). Defaults to now if not specified'), note: z.string().optional().describe('Description of work performed'), projectId: z.number().optional().describe('Associated project ID'), clientId: z.number().optional().describe('Associated client ID'), serviceId: z.number().optional().describe('Associated service ID'), taskId: z.number().optional().describe('Associated task ID'), billable: z.boolean().optional().describe('Whether time is billable'), active: z.boolean().default(false).describe('Whether this is an active timer'), internal: z.boolean().optional().describe('Whether this is internal work'), retainerId: z.number().optional().describe('Associated retainer ID'), }); /** * Input schema for updating a time entry */ export const TimeEntryUpdateInputSchema = z.object({ accountId: z.string().describe('FreshBooks account ID'), timeEntryId: z.number().describe('Time entry ID to update'), duration: z.number().min(0).optional().describe('Duration in seconds'), isLogged: z.boolean().optional().describe('Whether time is logged'), startedAt: z.string().datetime().optional().describe('Start time (ISO 8601)'), note: z.string().optional().describe('Description of work performed'), projectId: z.number().nullable().optional().describe('Associated project ID'), clientId: z.number().nullable().optional().describe('Associated client ID'), serviceId: z.number().nullable().optional().describe('Associated service ID'), taskId: z.number().nullable().optional().describe('Associated task ID'), billable: z.boolean().optional().describe('Whether time is billable'), active: z.boolean().optional().describe('Whether this is an active timer'), internal: z.boolean().optional().describe('Whether this is internal work'), retainerId: z.number().nullable().optional().describe('Associated retainer ID'), }); /** * Input schema for listing time entries */ export const TimeEntryListInputSchema = z.object({ accountId: z.string().describe('FreshBooks account ID'), page: z.number().int().min(1).default(1).optional().describe('Page number (1-indexed)'), perPage: z .number() .int() .min(1) .max(100) .default(30) .optional() .describe('Number of results per page (max 100)'), // Search filters projectId: z.number().optional().describe('Filter by project ID'), clientId: z.number().optional().describe('Filter by client ID'), taskId: z.number().optional().describe('Filter by task ID'), serviceId: z.number().optional().describe('Filter by service ID'), active: z.boolean().optional().describe('Filter by active status (running timers)'), billable: z.boolean().optional().describe('Filter by billable status'), billed: z.boolean().optional().describe('Filter by billed status'), startedAfter: z .string() .datetime() .optional() .describe('Filter entries started after this date (ISO 8601)'), startedBefore: z .string() .datetime() .optional() .describe('Filter entries started before this date (ISO 8601)'), }); /** * Input schema for getting a single time entry */ export const TimeEntrySingleInputSchema = z.object({ accountId: z.string().describe('FreshBooks account ID'), timeEntryId: z.number().describe('Time entry ID to retrieve'), }); /** * Input schema for deleting a time entry */ export const TimeEntryDeleteInputSchema = z.object({ accountId: z.string().describe('FreshBooks account ID'), timeEntryId: z.number().describe('Time entry ID to delete'), }); /** * Pagination metadata schema */ export const PaginationSchema = z.object({ page: z.number(), pages: z.number(), perPage: z.number(), total: z.number(), }); /** * Output schema for list operations */ export const TimeEntryListOutputSchema = z.object({ timeEntries: z.array(TimeEntrySchema), pagination: PaginationSchema, }); /** * Output schema for single/create/update operations */ export const TimeEntrySingleOutputSchema = TimeEntrySchema; /** * Output schema for delete operations */ export const TimeEntryDeleteOutputSchema = z.object({ success: z.boolean(), message: z.string(), timeEntryId: z.number(), });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Good-Samaritan-Software-LLC/freshbooks-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server