Reference

Types Reference

Complete TypeScript type definitions for the Nexa Ed SDK.

All types are exported from @nexa-ed/sdk (and re-exported from @nexa-ed/next).

File types

type FileProgressEvent =
  | { type: "progress"; stage: string; progress: number; message: string }
  | { type: "complete"; records: StudentRecord[] }
  | { type: "error"; message: string };
 
type DocumentSummary = {
  fileId: string;
  documentTitle: string;
  status: "queued" | "processing" | "complete" | "failed";
  pageCount: number;
  recordCount: number;
  createdAt: string;
};
 
type StudentRecord = {
  recordId: string;
  fileId: string;
  pageNumber: number;
  studentName: string;
  subjects: Record<string, number | null>;
  total: number | null;
  grade: string | null;
  position: number | null;
  rawText: string;
};

Payment types

type PaymentMetadata = {
  userId?: string;
  studentName?: string;
  category?: "enrollment" | "exam" | "tuition" | "other";
  [key: string]: string | undefined;
};
 
type PaymentTransaction = {
  reference: string;
  tenantId: string;
  customerEmail: string;
  amount: number;
  amountPaid: number;
  status: "success" | "failed" | "pending" | "abandoned";
  fees: number;
  platformFee: number;
  netAmount: number;
  paidAt: string | null;
  channel: string;
  failureReason: string | null;
  createdAt: string;
  updatedAt: string;
};
 
type PaymentConfig = {
  platformFeePercent: number;
  platformFeeFixed: number;
  currency: string;
  bankDetails?: {
    bankName: string;
    accountNumber: string;
    accountName: string;
  };
};
 
type PaymentStats = {
  totalTransactions: number;
  successCount: number;
  failedCount: number;
  totalRevenue: number;
  totalNetRevenue: number;
  averageAmount: number;
};
 
type PaymentError = {
  code: string;
  message: string;
};

Email provisioning types

type EmailTier = "tier-1-nexa" | "tier-2-stalwart" | "tier-3-google";
 
type EmailCreateOptions = {
  studentId: string;
  firstName: string;
  lastName: string;
  email?: string;           // Generated from name if omitted
  gradeLevel?: string;      // e.g. "SS2" — used for Google Workspace OU
  recoveryEmail?: string;
};
 
type EmailCreateResult = {
  email: string;
  temporaryPassword: string;
  providerUserId: string;
  tier: EmailTier;
};
 
type StudentEmailAccount = {
  email: string;
  studentId: string;
  firstName: string;
  lastName: string;
  status: "active" | "suspended" | "deleted";
  tier: EmailTier;
  provider: "nexa" | "stalwart" | "google";
  providerUserId: string;
  gradeLevel?: string;
  passwordResetRequired: boolean;
  createdAt: number;
  updatedAt: number;
};
 
type EmailBulkCreateOptions = {
  students: EmailCreateOptions[];
};
 
type EmailBulkCreateResult = {
  jobId: string;
  tier: EmailTier;
  totalStudents: number;
  message: string;
};
 
type EmailJobStatus = {
  jobId: string;
  status: "pending" | "processing" | "completed" | "failed";
  type: string;
  totalStudents: number;
  processedCount: number;
  successCount: number;
  failedCount: number;
  results?: Array<{
    studentId: string;
    email?: string;
    status: "created" | "failed";
    error?: string;
  }>;
  error?: string;
  createdAt: number;
  startedAt?: number;
  completedAt?: number;
};

Webhook types

All variants discriminate on event, not type.

type WebhookFileCompleteEvent = {
  event: "file.completed";
  fileId: string;
  userId: string;
  tenantId: string;
  timestamp: string;
};
 
type WebhookPaymentEvent = {
  event: "payment.completed";
  reference: string;
  tenantId: string;
  status: "success" | "pending" | "failed" | "abandoned";
  amount: number; // smallest currency unit (kobo for NGN)
  customerEmail: string;
  amountPaid?: number;
  fees?: number;
  platformFee?: number;
  netAmount?: number;
  paidAt?: string;
  channel?: string;
  failureReason?: string;
  createdAt: number;  // Unix ms
  updatedAt: number;  // Unix ms
  timestamp?: string; // ISO 8601 — webhook delivery time
};
 
/** Fired after a single student email account is provisioned */
type WebhookEmailCreatedEvent = {
  event: "email.created";
  tenantId: string;
  studentId: string;
  email: string;
  firstName: string;
  lastName: string;
  gradeLevel?: string;
  provider: "nexa" | "stalwart" | "google";
  providerUserId: string;
  tier: EmailTier;
  createdAt: number; // Unix ms
};
 
/** Fired when an account is suspended or restored */
type WebhookEmailStatusChangedEvent = {
  event: "email.status_changed";
  tenantId: string;
  email: string;
  studentId: string;
  previousStatus: "active" | "suspended";
  status: "active" | "suspended";
  changedAt: number; // Unix ms
};
 
/** Fired when a bulk email provisioning job finishes — lean counts only */
type WebhookEmailBulkCompletedEvent = {
  event: "email.bulk_completed";
  tenantId: string;
  jobId: string;
  status: "completed" | "failed";
  totalStudents: number;
  successCount: number;
  failedCount: number;
  completedAt: number; // Unix ms
};
 
type WebhookEvent =
  | WebhookFileCompleteEvent
  | WebhookPaymentEvent
  | WebhookEmailCreatedEvent
  | WebhookEmailStatusChangedEvent
  | WebhookEmailBulkCompletedEvent;

file.completed and payment.completed are auto-verified and dispatched by createRouteHandler (to onFileComplete/onPaymentComplete). The three email.* events have no built-in dispatch — verify them yourself with nexa.webhooks.verify(request) in a route you write. See Webhooks.

Analysis types

type AnalysisJob = {
  jobId: string;
  fileId: string;
  status: "pending" | "running" | "complete" | "failed";
  chunkId: string;
  pageNumber: number;
  createdAt: string;
  completedAt: string | null;
};
 
type ChunkSummary = {
  chunkId: string;
  fileId: string;
  pageStart: number;
  pageEnd: number;
  recordCount: number;
  status: "pending" | "complete" | "failed";
};

Convex integration

@nexa-ed/convex adds these schema fragments and types:

// nexaFilesSchema — spread into defineSchema()
const nexaFilesSchema = {
  nexaFileResults: defineTable({
    fileId: v.string(),
    userId: v.string(),
    tenantId: v.string(),
    status: v.union(v.literal("success"), v.literal("failed")),
    completedAt: v.string(),
  })
    .index("by_fileId", ["fileId"])
    .index("by_userId", ["userId"]),
};
 
// nexaPaymentsSchema — spread into defineSchema()
const nexaPaymentsSchema = {
  paymentTransactions: defineTable({
    reference: v.string(),
    tenantId: v.string(),
    customerEmail: v.string(),
    amount: v.number(),
    status: v.string(),
    // ... all PaymentTransaction fields
  })
    .index("by_reference", ["reference"])
    .index("by_email", ["customerEmail"]),
};
 
// nexaStudentEmailsSchema — spread into defineSchema() when using email provisioning
const nexaStudentEmailsSchema = {
  studentEmails: defineTable({
    tenantId: v.string(),
    studentId: v.string(),
    email: v.string(),
    firstName: v.string(),
    lastName: v.string(),
    provider: v.optional(v.union(v.literal("nexa"), v.literal("stalwart"), v.literal("google"))),
    tier: v.optional(v.union(v.literal("tier-1-nexa"), v.literal("tier-2-stalwart"), v.literal("tier-3-google"))),
    status: v.union(v.literal("active"), v.literal("suspended"), v.literal("deleted")),
    passwordResetRequired: v.optional(v.boolean()),
    createdAt: v.number(),
    updatedAt: v.number(),
  })
    .index("by_email",   ["email"])
    .index("by_tenant",  ["tenantId"])
    .index("by_student", ["tenantId", "studentId"])
    .index("by_status",  ["tenantId", "status"]),
};

On this page