API Response Types

This document describes the API response type definitions and validation for the GP3MixMedia TrailMix platform.


Overview

The API provides:

  • Type Safety: Full TypeScript types for requests and responses
  • Runtime Validation: Zod schemas for input validation
  • API Documentation: OpenAPI 3.0 specification
  • Client Generation: OpenAPI spec for generating client libraries

Type Definitions Location

All type definitions are in the /types directory:

FileContents
/types/api-responses.tsCommon API response types
/types/campaign-types.tsCampaign-specific types
/types/api-schemas.tsZod validation schemas

Common Response Types

Pagination

Cursor-based pagination:

interface PaginationInfo {
  cursor: number | null;
  nextCursor: number | null;
  hasNextPage: boolean;
  limit: number;
}

Offset-based pagination:

interface OffsetPaginationInfo {
  page: number;
  limit: number;
  total: number;
  totalPages: number;
}

Error Responses

// Single error
interface ErrorResponse {
  error: string;
}

// Multiple errors
interface ErrorsResponse {
  errors: string[];
}

// Success message
interface SuccessResponse {
  message: string;
}

Health Check

interface HealthCheckResponse {
  status: 'healthy' | 'unhealthy';
  timestamp: string;
  checks?: {
    database: boolean;
    redis?: boolean;
    s3?: boolean;
  };
}

Campaign Types

Campaign Status

type CampaignStatus = 'draft' | 'active' | 'paused' | 'completed' | 'archived';

Campaign Summary

interface CampaignSummary {
  id: number;
  candidateNames: string;
  campaignName: string;
  status: CampaignStatus;
  lastUpdatedAt: string;
  lastStationRefreshAt: string | null;
  stationCount: number;
  markets: string[];
  lastIngestionAt: string | null;
  ingestionRecordCount: number;
}

Campaign List Response

interface CampaignListResponse {
  campaigns: CampaignSummary[];
  pageInfo: PaginationInfo;
}

Using Types in API Routes

Typed GET Handler

import { NextRequest, NextResponse } from 'next/server';
import type { CampaignListResponse } from '@/types/campaign-types';

export async function GET(request: NextRequest): Promise<NextResponse<CampaignListResponse>> {
  // ... implementation
  return NextResponse.json({
    campaigns: summaries,
    pageInfo: { cursor, nextCursor, limit, hasNextPage },
  });
}

Typed POST Handler

import { NextRequest, NextResponse } from 'next/server';
import type { CampaignCreationResponse } from '@/types/campaign-types';

export async function POST(request: NextRequest): Promise<NextResponse<CampaignCreationResponse>> {
  // ... implementation
  return NextResponse.json(result, { status: 201 });
}

Validation with Zod

Request Validation

import { CampaignCreationRequestSchema } from '@/types/campaign-schemas';

export async function POST(request: NextRequest) {
  const payload = await request.json();

  const result = CampaignCreationRequestSchema.safeParse(payload);

  if (!result.success) {
    return NextResponse.json(
      { errors: result.error.errors.map((e) => e.message) },
      { status: 400 }
    );
  }

  const validatedData = result.data;
  // ... continue with validated data
}

OpenAPI Specification

Generating the Spec

npm run generate:openapi

Creates: /public/api-docs/openapi.json

Viewing Documentation

  1. Swagger UI: Upload to Swagger Editor
  2. Redoc: Use Redoc
  3. Local Preview:
npx @redocly/cli preview-docs public/api-docs/openapi.json

Data Type Enums

Medium Types

type MediumType =
  | 'broadcast'
  | 'cable'
  | 'radio'
  | 'digital'
  | 'ott'
  | 'ctv'
  | 'mail'
  | 'phones'
  | 'social'
  | 'other'
  | 'unknown';

Dedupe Status

type DedupeStatus = 'pending' | 'resolved' | 'skipped';

Email Send Status

type EmailSendStatus = 'queued' | 'scheduled' | 'sent' | 'delivered' | 'bounced' | 'failed';

Alert Channels

type AlertChannel = 'email' | 'push' | 'in_app';

Notification Types

type NotificationType = 'info' | 'success' | 'warning' | 'error';

Frontend Usage

Fetching with Types

import type { CampaignListResponse } from '@/types/campaign-types';

async function fetchCampaigns(cursor?: number): Promise<CampaignListResponse> {
  const params = new URLSearchParams();
  if (cursor) params.set('cursor', cursor.toString());

  const response = await fetch(`/api/v1/campaigns?${params}`);
  if (!response.ok) throw new Error('Failed to fetch');

  return response.json();
}

Best Practices

  1. Always use types for API route handlers
  2. Validate input with Zod schemas
  3. Generate OpenAPI spec after adding new endpoints
  4. Keep types in sync with actual responses
  5. Use strict TypeScript settings

Adding New Endpoints

  1. Define TypeScript types in /types/
  2. Create Zod schemas with OpenAPI extensions
  3. Register schemas in /scripts/generate-openapi.ts
  4. Register paths in OpenAPI generator
  5. Generate spec: npm run generate:openapi
  6. Update route handlers to use typed responses

Last Updated: March 2026

Was this helpful? If you have feedback or questions, please contact your administrator.