Skip to main content

Overview

This guide will walk you through creating your first event on EventPalour, from signing up to publishing your event.
You’ll need a valid email address to get started. OAuth authentication with Google is also supported.

Step 1: Create Your Account

EventPalour offers multiple ways to sign up:
1

Visit the Sign Up Page

Navigate to /auth/sign-up to create your account
2

Choose Your Sign Up Method

  • Email & Password: Traditional signup with email verification
  • Google OAuth: Sign up with your Google account
3

Verify Your Email

If using email/password, check your inbox for a 6-digit verification code

Sign Up Implementation

Here’s how the signup process works under the hood:
// From app/(auth)/auth/sign-up/action.ts
export async function signupAction({
  email,
  password,
}: {
  email: string;
  password: string;
}): Promise<ActionResult> {
  // Validate email format
  if (!verifyEmailInput(email)) {
    return {
      errorMessage: "Please enter a valid email address!",
      message: null,
    };
  }

  // Check email availability
  const emailAvailable = await checkEmailAvailability(email);
  if (emailAvailable) {
    return {
      errorMessage: "This email address is already registered.",
      message: null,
    };
  }

  // Verify password strength
  const strongPassword = await verifyPasswordStrength(password);
  if (!strongPassword) {
    return {
      errorMessage: "Password is too weak. Use at least 8 characters.",
      message: null,
    };
  }

  // Create user and send verification email
  const user = await createUser({
    email,
    username: generateRandomUsername(),
    avatar: "/images/one.svg",
    email_verified: false,
    passwordHash: await hashPassword(password),
  });

  // Create verification request
  const emailVerificationRequest = await createEmailVerificationRequest(
    user.id,
    user.email
  );

  return {
    errorMessage: null,
    message: "Account created! Check your email for verification code.",
  };
}
For production deployments, ensure you configure the email service properly. EventPalour uses Resend for transactional emails.

Step 2: Choose Your Role

After verifying your email, you’ll be asked to select your role:

Event Organizer

Create and manage events, sell tickets, and engage attendees

Attendee

Discover events, purchase tickets, and join experiences

Role Selection Process

// From app/(auth)/auth/onboarding/action.ts
export async function updateUserRoleAction({
  role,
}: {
  role: "organizer" | "attendee";
}): Promise<ActionResult> {
  // Update user's platform role
  await db
    .update(user)
    .set({
      platform_role:
        role === "organizer" ? PlatformRole.ORGANIZER : PlatformRole.ATTENDEE,
    })
    .where(eq(user.id, currentUser.id));

  return {
    errorMessage: null,
    message: `Role updated to ${role} successfully!`,
    data: {
      userRole: role,
      redirectPath:
        role === "attendee" ? "/dashboard" : "/auth/onboarding/organizer",
    },
  };
}
You can always change your role later from your account settings.

Step 3: Create Your Workspace (Organizers Only)

If you selected “Event Organizer”, you’ll need to create a workspace:
1

Enter Business Details

Provide your organization name, description, and contact information
2

Add Social Links (Optional)

Connect your social media profiles (X/Twitter, Facebook, LinkedIn, Instagram)
3

Create Workspace

Click “Create Workspace” to complete the setup

Workspace Creation

// From app/(auth)/auth/onboarding/organizer/action.ts
export async function createWorkspaceAction({
  businessName,
  description,
  website,
  phone,
  social_x,
  social_facebook,
  social_linkedin,
  social_instagram,
  social_github,
}: WorkspaceData): Promise<ActionResult> {
  // Validate input
  if (businessName.length < 2) {
    return {
      errorMessage: "Business name must be at least 2 characters!",
      message: null,
    };
  }

  // Generate unique invite code
  const inviteCode =
    Math.random().toString(36).substring(2, 15) +
    Math.random().toString(36).substring(2, 15);

  // Create workspace
  const [newWorkspace] = await db
    .insert(tables.workspace)
    .values({
      name: businessName,
      description: description || undefined,
      website: website || undefined,
      phone: phone || undefined,
      social_x: social_x || undefined,
      social_facebook: social_facebook || undefined,
      social_linkedin: social_linkedin || undefined,
      social_instagram: social_instagram || undefined,
      social_github: social_github || undefined,
      image_url: "",
      invite_code: inviteCode,
      user_id: currentUser.id,
    })
    .returning({ id: tables.workspace.id });

  // Add creator as admin
  await db.insert(tables.workspace_members).values({
    user_id: currentUser.id,
    workspace_id: newWorkspace.id,
    role: WorkspaceRole.ADMIN,
  });

  return {
    errorMessage: null,
    message: "Workspace created successfully!",
    data: {
      workspaceId: newWorkspace.id,
      redirectPath: `/workspace/${newWorkspace.id}`,
    },
  };
}
Workspace invite codes are automatically generated and should be kept secure. Share them only with team members you want to invite.

Step 4: Create Your First Event

Now you’re ready to create your first event!
1

Navigate to Event Creation

Go to your workspace and click “Create Event”
2

Enter Event Details

Fill in the basic information:
  • Event title
  • Description (minimum 10 characters)
  • Event type (Physical, Online, or Hybrid)
  • Start and end dates
3

Configure Event Type

Physical Events: Add venue, country, and cityOnline Events: Add meeting link (Google Meet, Zoom, Teams, or custom)Hybrid Events: Add both venue and meeting link
4

Set Up Pricing

Choose between free or paid events:
  • Free: No charge for attendees
  • Paid: Requires KYC verification (ticket types, pricing, currency)
5

Add Optional Details

  • Event category
  • Event image
  • Speakers
  • Partners/Sponsors
  • Ticket types (for paid events)
6

Publish Event

Review and publish your event to make it live

Event Creation Schema

// Event validation schema from app/actions/events.ts
const createEventSchema = z
  .object({
    title: z
      .string()
      .min(1, "Title is required")
      .max(255, "Title must be 255 characters or less"),
    description: z
      .string()
      .refine(
        (val) => getPlainTextLength(val) >= 10,
        { message: "Description must be at least 10 characters" }
      ),
    workspaceId: z.string().min(1, "Workspace ID is required"),
    type: z.nativeEnum(EventType).default(EventType.PHYSICAL),
    pricing: z.nativeEnum(EventPricing).default(EventPricing.FREE),
    venue: z.string().optional(),
    country: z.string().optional(),
    city: z.string().optional(),
    startDate: z.date(),
    endDate: z.date(),
    meetingLink: z.string().optional(),
  })
  .refine((data) => data.endDate > data.startDate, {
    message: "End date must be after start date",
    path: ["endDate"],
  });

Event Data Model

// From lib/db/schema/events.ts
export const events = pgTable("events", {
  id: varchar("id", { length: 16 }).primaryKey(),
  short_id: varchar("short_id", { length: 6 }).notNull().unique(),
  title: varchar("title", { length: 255 }).notNull(),
  status: event_status_enum("status").notNull().default(EventStatus.ACTIVE),
  description: text("description").notNull(),
  workspace_id: varchar("workspace_id", { length: 16 }).notNull(),
  category_id: varchar("category_id", { length: 16 }).notNull(),
  type: event_type_enum("type").notNull().default(EventType.PHYSICAL),
  pricing: event_pricing_enum("pricing").notNull().default(EventPricing.FREE),
  venue: text("venue"),
  country: text("country"),
  city: text("city"),
  online_link: text("online_link"),
  start_date: timestamp("start_date", { withTimezone: true }).notNull(),
  end_date: timestamp("end_date", { withTimezone: true }).notNull(),
  is_recurring: boolean("is_recurring").notNull().default(false),
});
const physicalEvent = {
  title: "Tech Conference 2026",
  description: "<p>Join us for an amazing tech conference featuring industry leaders.</p>",
  type: EventType.PHYSICAL,
  pricing: EventPricing.FREE,
  venue: "Convention Center",
  country: "Kenya",
  city: "Nairobi",
  startDate: new Date("2026-06-01T09:00:00Z"),
  endDate: new Date("2026-06-01T17:00:00Z"),
};
KYC Requirement for Paid EventsBefore creating paid events, organizers must complete KYC verification. This ensures compliance and builds trust with attendees.

Step 5: Manage Your Event

Once your event is published, you can:
  • View Event Dashboard: See registrations, ticket sales, and analytics
  • Manage Attendees: Track who’s registered and check-in status
  • Send Announcements: Communicate updates to registered attendees
  • Add Speakers: Showcase speakers with bios and social links
  • Monitor Sales: Track ticket sales and revenue (for paid events)

Event Management Features

Attendee Management

Track registrations, send check-in codes, and manage attendee lists

Announcements

Send important updates to all registered attendees

Speaker Management

Add speakers with profiles, topics, and scheduled times

Analytics

View event performance metrics and attendee insights

Next Steps

1

Customize Your Event

Add speakers, partners, and detailed schedules
2

Set Up Ticketing

Create multiple ticket tiers with different pricing
3

Promote Your Event

Share your event link and leverage social media
4

Monitor Registrations

Track attendee signups and send reminders

Common Operations

Update Event Status

// Event can have different statuses
export enum EventStatus {
  DRAFT = "draft",
  ACTIVE = "active",
  CANCELLED = "cancelled",
  COMPLETED = "completed"
}

Add Event Speakers

// From lib/db/schema/events.ts
export const events_speakers = pgTable("events_speakers", {
  id: varchar("id", { length: 16 }).primaryKey(),
  event_id: varchar("event_id", { length: 16 }).notNull(),
  name: varchar("name", { length: 255 }).notNull(),
  email: varchar("email", { length: 255 }),
  title: varchar("title", { length: 255 }),
  talk: text("talk"),
  bio: text("bio"),
  image_url: text("image_url"),
  twitter_handle: varchar("twitter_handle", { length: 255 }),
  linkedin_url: text("linkedin_url"),
  status: speaker_status_enum("status").notNull().default(SpeakerStatus.PENDING),
  scheduled_time: timestamp("scheduled_time", { withTimezone: true }),
});

Add Partners/Sponsors

// From lib/db/schema/events.ts
export const events_partners = pgTable("events_partners", {
  id: varchar("id", { length: 16 }).primaryKey(),
  event_id: varchar("event_id", { length: 16 }).notNull(),
  name: varchar("name", { length: 255 }).notNull(),
  logo_url: text("logo_url"),
  website_url: text("website_url"),
  type: varchar("type", { length: 50 }).notNull().default("sponsor"),
});

Troubleshooting

Check your spam folder. The verification email is sent from the configured email service. If you still don’t see it, you can request a new code from the verification page.
Paid events require KYC verification. Complete the KYC process in your workspace settings before creating paid events.
Ensure your end date is after the start date. Both dates must be in the future when creating a new event.
You need at least Moderator permissions in the workspace to create events. Contact your workspace admin to update your role.
For more detailed API documentation and advanced features, check out the API Reference section.

Build docs developers (and LLMs) love