Q&A
Shared-session-per-date Q&A blocks with free or paid registration, per-session language, and a vetted bilingual acknowledgement at sign-up.
Download PDFWhat Q&A is
Q&A (Questions-Réponses) is a shared-session-per-date module that lets you offer informational group blocks the public can register for. Anyone visiting your booking page picks a date inside the 15-day window; the first registrant on a given date sets the start time, and every later registrant on that same date joins the same session. Sessions can be free (no payment, just registration) or paid (Stripe Connect collects the per-attendee fee). Q&A is the right tool when you want to talk to several prospects at once, surface the same answers to the same recurring questions, and stay clear of one-on-one advice.
Internally a Q&A session is an event row tied to a service that has format='qa'. Tenant Events (Phase 20/21) use the same events table without a service link, so the platform distinguishes the two everywhere by filtering on whether service_id is null. The result: Q&A and tenant Events live side by side without leaking into each other's lists, dashboards, or reminder crons.
Note: Q&A is informational only. The vetted bilingual acknowledgement every attendee accepts on sign-up explicitly disclaims a consultant-client relationship and explicitly directs anyone who wants advice on their own matter to book a paid consultation instead. The legal framing is part of the registration flow, not an optional add-on.
When to use Q&A vs. other modules
Q&A overlaps superficially with Bookings and Events, but the model is genuinely different. Bookings are 1:1 — one client, one private slot. Events are 1:N where you (the tenant) own the time — you publish a session at a specific date and time, and people register against it. Q&A is N:date — you publish only the days you are willing to host on, and the prospect community coordinates itself by self-selecting onto the same date and inheriting whatever start time the first person picked.
Pick Bookings when the conversation must be private (consultation, file review, signing).
Pick Events when you want full control over the date and time, and you want to sell tickets at a fixed schedule (a webinar series, an information evening, a workshop).
Pick Q&A when you are open to several days but want the community to self-organise on which days run, and you want the same vetted acknowledgement to apply to every attendee.
Create a Q&A service
A Q&A session is configured as a service of format='qa' on Services. On the service form, pick 'Q&A (shared session per date)' as the format. The form then reveals four Q&A-specific fields: available days of the week, session language, capacity cap, and tenant notification opt-out. Standard service fields (name, description, duration in minutes, price, currency, meeting modes) work the same way as live Bookings — duration is the length of each Q&A session, price is per attendee, meeting modes can be online (Google Meet auto-created) or in-person at your address.
Note: Set the price to zero if you want a free Q&A block (the registration still records the acknowledgement, the meeting URL still appears in the confirmation email, but no payment is collected). Set a positive price to run paid Q&A — Stripe Connect collects per attendee on the same checkout flow as live Bookings.
Available days of the week
The Available Days picker is a weekly recurrence — pick any combination of weekdays (Sun, Mon, Tue, Wed, Thu, Fri, Sat) you are willing to host Q&A on. The picker defaults to empty so the first-time setup is a deliberate choice; saving with zero days selected is blocked at the validator. A live counter under the row tells you how many days you have selected.
Public visitors see only those weekdays as bookable in the 15-day window. Combined with your existing weekly availability rules and off-days, the same constraints that gate live booking slots gate Q&A slots — an off-day blocks Q&A on that date, weekly availability rules define which start-time slots are even candidates for the first booker, and existing booked time on your connected calendar (Google or Microsoft 365) hides the colliding slots with the same 15-minute buffer Bookings uses.
Session language
Each Q&A service carries one session language. Basic-tier tenants pick from English or Quebec French. Premium tenants additionally unlock Spanish, Arabic, Mandarin Chinese, Portuguese, Russian, Persian (Farsi), Hindi, and Urdu — ten codes total, aligned to the same Phase 10C language set the public booking page supports through runtime translation. The picker on the Services form disables the locked options inline for Basic tenants so the gate is visible up front, and the server re-validates at save time so the gate cannot be bypassed from the form.
The session language is the language you commit to running the actual session in. The booking page renders a bilingual EN+FR notice at the top of the Q&A flow stating in both languages which language the session will be conducted in, so a visitor whose interface language differs from the session language sees the commitment clearly. Confirmation emails, reminder emails, and cancellation emails default to English or Quebec French based on the registrant's interface locale; the session language itself is named inside the body of every email so there is no ambiguity once the registrant arrives on the call.
Premium: If a single Q&A topic legitimately needs to run in multiple languages, create one service per language with the same name plus the language as a suffix (for example: 'Family Sponsorship Q&A — English' and 'Family Sponsorship Q&A — Mandarin'). Visitors pick by language up front; each language runs as its own shared-session-per-date pool.
Capacity cap
The Capacity field is an integer cap on how many attendees can register against a single Q&A session. Leave it blank for unlimited (the public picker will accept everyone), or set a positive integer to cap. The cap is enforced as a sum of attendee_count across non-cancelled registrations, the same way tenant Events cap. When a session reaches the cap, the date appears on the public picker with a 'full' indicator and the join-existing option is hidden; a fresh date with no materialised session yet remains bookable.
Tenant notifications
By default, every new Q&A registration triggers a notification email to your tenant address so you can see who registered, when, and for which session. If the Q&A is high-volume (a free community block running every week, an outreach session on social media) you can disable per-registration notifications by unticking 'Notify me on each registration' on the service form. The dashboard list page still shows every session, the per-session detail page still lists every attendee, and the reminder crons still fire — the toggle only suppresses the per-registration email so your inbox stays clean.
The public registration flow
When a visitor picks a Q&A service from your booking page, the page mounts a dedicated Q&A flow with four sub-steps: date picker (15-day grid), time picker (only shown if the visitor is the first booker on that date), registration form, and a confirmation screen. A bilingual EN+FR session-language notice sits at the top of every step so the visitor knows up front which language the session will run in.
Date — the visitor sees the 15-day window starting tomorrow; dates outside your available weekdays render disabled, off-days render disabled, dates with an existing session show a 'join existing' badge with the count and capacity, dates with a full session render disabled with a 'full' badge.
Time — only shown for first-booker dates. The picker lists every start time that fits your weekly availability for that day of the week, after subtracting your tenant's confirmed live bookings, any existing Q&A sessions on other services on the same date, and your connected calendar's busy intervals — all with a 15-minute buffer.
Form — name, email, meeting mode (if your service offers both online and in-person), the bilingual disclosure with type-to-confirm, and an optional discount code. The form is gated on the disclosure being ticked AND the typed name matching the registration name (case-insensitive).
Success — for free Q&A, an immediate confirmation screen. For paid Q&A, the form redirects to Stripe Checkout and the success screen renders after Stripe sends the visitor back, carrying the human-readable reference, session date, amount, and currency in the redirect URL so the screen reads cleanly without waiting on the confirmation email.
First-booker-sets-the-time
The defining model of Q&A is that the first registrant on a given date picks the start time within your weekly availability, and every subsequent registrant on that date inherits the same start time. The first registrant therefore controls scheduling for everyone who joins on that date. The platform materialises an event row + creates the Google Meet (online) or stamps the in-person address (in-person) the moment the first registration succeeds, so the join URL or location is available to every later registrant inside their own confirmation email.
Note: If the first registrant cancels their registration and they were the only attendee on that date, the platform tears down the materialised event row and the Google Meet block, freeing the date for someone else to start fresh with a new start time. The date is never permanently locked by a cancelled registrant.
The bilingual acknowledgement
Every Q&A registration is gated by a five-clause bilingual acknowledgement: purpose (informational only, not a regulated consultation), no professional relationship, not advice (book a paid consultation for your own situation), confidentiality of other attendees (no recording, no redistribution, no sharing of what others say), and session language (the session runs in the language stated on the page; if the registrant needs a different language, do not register — contact the licensee separately). The text is system-supplied and not editable per tenant — uniform legal framing across the platform is a deliberate design choice.
The registration record stamps the disclosure version (a date-stamped string like 'v1-2026-05-22'), the typed name the visitor confirmed with, and the acceptance timestamp on the event_registrations row. If the platform ever updates the acknowledgement text in a future release, the version bumps; older registrations keep their original version on file so a future legal action can reconstruct exactly which version each attendee agreed to. Mirror of the demo NDA versioning pattern.
Confirmation, calendar invite, and Google Meet
Free Q&A registrations send the confirmation email immediately and attach the calendar invite (including the Google Meet URL for online sessions). The host's calendar event carries a 10-minute pre-start popup reminder so you have a short window to prepare. For first-booker registrations, the platform creates the calendar event at the moment of registration; for join-existing registrations, the platform best-effort patches the existing calendar event to add the new attendee, so everyone who joins the same date shows up on the host's calendar.
If your tenant has Google Calendar or Microsoft 365 connected, the platform routes calendar writes through that provider. If neither is connected, registration still succeeds — the confirmation email carries the session date, time, language, and (for online sessions) the host's posted meeting URL or (for in-person) the company address. The Q&A flow degrades gracefully on a missing calendar connection; it does not block the registration.
Paid Q&A and discount codes
If your Q&A service has a positive price, the form does not finalise the registration on submit — instead it creates a pending registration row, opens a Stripe Checkout session for the per-attendee amount, and redirects the visitor. The Stripe checkout collects the platform's commission as an application fee on top of the per-attendee amount (consistent with Bookings); the rest settles to your connected Stripe account. The registration only flips to confirmed when Stripe's webhook fires payment-succeeded.
Booking-side discount codes from the existing Bookings discount system apply to Q&A. On the registration form, the visitor types a discount code, the server validates it against your tenant's discount_codes table, and applies either a percentage or a fixed amount to the per-attendee price. A 100%-off code (free with a code) takes the Stripe Checkout out of the loop entirely and flips the registration straight to confirmed on the free path, incrementing the discount's usage counter the same way the live booking path does.
Note: Calendar invites for paid Q&A are deliberately deferred until payment confirms. If a visitor opens Stripe Checkout and abandons it without paying, the registration sits pending and no calendar invite is sent — the visitor does not receive a confirmation email or a Google Meet URL for a session they did not pay for. The post-payment webhook attaches the attendee to the existing calendar block once Stripe confirms.
Reminder emails
Two independent reminder sweeps fire against every confirmed Q&A registration. The 24-hour sweep runs daily at 12:02 UTC (staggered from the demo reminder cron at the same hour to flatten the SMTP burst) and emails every registrant whose session is between 1 and 25 hours away. The 30-minute sweep runs every 5 minutes and emails every registrant whose session is between 25 and 35 minutes away. The two columns on the registration row are stamped independently, so a registrant who arrives both sweep windows gets both reminders.
Late registrants who sign up inside the 30-minute lower bound (less than 25 minutes before the session starts) never enter the imminent sweep window; their confirmation email is their only nudge. This is a documented limitation, not a bug. If you want to widen the gap (e.g. send an immediate 'starts very soon' email for late sign-ups), the change is small but not yet shipped.
Cancellation by the registrant
Every Q&A confirmation email carries a one-click cancel link unique to that registration. Clicking the link renders a small confirmation page; the registrant confirms, the registration flips to cancelled, and a cancellation email is sent to confirm receipt. If the cancelled registrant was the only non-cancelled attendee on that date, the platform deletes the materialised event row + tears down the Google Meet block — the date frees up and the next visitor to pick that date becomes the new first booker with a fresh start time.
Note: The cancel link is the capability — there is no separate password or OTP. The token rotates on the registration row at registration time and never appears in any other surface. A revoked token (after cancellation) cannot be re-used.
Cancellation by the tenant (with refund)
On the session-detail page (under Q&A on the dashboard), Owner and Admin members see a 'Cancel Q&A session' card. Clicking it cancels every non-cancelled registration on that session in one pass, refunds every paid registration via Stripe Connect (refund failures are collected and surfaced for operator follow-up), sends a cancellation email to every affected registrant explaining the cancellation came from your side, then tears down the calendar block and deletes the events row so the date frees up. Assistants do not see the button — the route returns 403 if they call it directly. The card label and copy adjust based on attendee count, so a zero-attendee orphan session reads as 'Delete Q&A session' instead of 'Cancel Q&A session'.
The Q&A list page
Sidebar → Q&A opens the Q&A list page (/dashboard/q-and-a). The page is always visible to all members regardless of seat type — Q&A is on the same always-visible footing as Store and the dashboard Overview. The list shows every materialised Q&A session for your tenant in two tabs (Upcoming and Past), with the title, scheduled date and time, language, attendee count, capacity, status, meeting mode, and the URL or address. Each row is clickable through to the session detail page.
Sessions that have not yet been materialised (a Q&A service you created, but on dates no one has registered for yet) do not appear in the list. The list shows actuals — rows that exist in the events table — not the abstract schedule of potential dates. If no one has registered yet on any date, the list reads as empty. This is intentional: it keeps the page honest about which sessions you actually have to prepare for.
The session detail page
Each row on the list opens a session detail page (/dashboard/q-and-a/<id>) that shows the session title, scheduled date, language, capacity vs attendees, the meeting URL or address, and a table of every registration on that session: name, email, attendee count, payment status, paid amount (if any), registration timestamp, and cancellation timestamp (if applicable). Each registration row carries a one-click cancel button (Owner/Admin only) that cancels that single registration without affecting the rest of the session.
The cancel-session card sits at the bottom of the detail page (Owner/Admin only). For sessions with active paid attendees, the card warns that cancellation triggers refunds. For zero-attendee orphan sessions (often left behind by a single registrant who cancelled), the card reads 'Delete Q&A session' so you can clean up dead rows without going through the refund flow.
Ownership in Team Mode
If you are a Premium tenant with multiple team members, each Q&A service carries an owner_user_id pointing at the member who hosts that Q&A. The owner's connected calendar is the one the platform writes the calendar block to (with the same three-branch resolver Bookings uses: per-service owner first, company-level fallback, Owner member fallback). Bookings list pages and assignment dropdowns honour the owner. On a non-Team Mode tenant or a Q&A service with no assigned owner, calendar writes resolve through the company-wide calendar or the Owner member.
Q&A vs. tenant Events
Q&A reuses the same underlying events and event_registrations tables that the tenant Events module (Phase 20 + 21) uses, but the two never collide. Every Q&A event row has a non-null service_id pointing at the format='qa' service that hosts it; every tenant Event row has a null service_id. Every list, dashboard, reminder cron, and admin metric in the platform filters one way or the other so the two streams stay isolated.
The tenant Events list at /dashboard/events filters service_id IS NULL — Q&A sessions never leak in.
The Q&A list at /dashboard/q-and-a filters service_id IS NOT NULL — tenant Events never leak in.
Reminder crons branch on the same discriminator, so Q&A reminders never fire against Event tickets and Event ticket reminders never fire against Q&A registrations.
Subscription tier and pricing
Q&A is available on every tier — Basic and Premium tenants both see the module in the sidebar and the dashboard from day one. The only tier-gated feature is session language: Basic tenants pick English or Quebec French, Premium tenants additionally unlock the other eight Phase 10C languages. There is no per-session fee or per-attendee platform charge beyond the standard Stripe Connect application fee that already applies to live Bookings — Q&A inherits the same commission structure.
Interactions with other modules
Q&A is a pull surface — it brings prospects in, gives them a vetted informational session, and signals to anyone who wants advice for their own matter that they should book a paid consultation. The natural downstream module is Bookings: in the acknowledgement, in the email body, and in the way you frame the session live, you redirect anyone with a specific situation to book a one-on-one through your public booking page. The session itself stays clear of advising on individual files.
If a Q&A attendee ends up booking a real consultation afterward, the booking goes through Bookings; from there, the standard flow continues — Initial Consultation Agreement on the booking page, Service Agreement if the matter proceeds, Transfer Room when the Service Agreement is fully signed. Q&A's job ends at the handoff. The platform does not track 'Q&A attendee → became a client' attribution today; that mapping is downstream of the tenant's CRM (if any).
Troubleshooting
'No times available on this date' on the public picker — the first booker's slot generator subtracts live bookings, other Q&A sessions on the same date across services, and your connected calendar's busy intervals with a 15-minute buffer. If every slot collides, the date renders with that message. Free up busy time on your calendar OR add weekly availability windows you have not yet enabled.
Paid Q&A registration that never confirms — the visitor opened Stripe Checkout and abandoned. The registration row remains in pending state until either the visitor completes payment OR the pending row stays orphan indefinitely. The dashboard list does not surface pending registrations; clean them up by ignoring them (they do not count toward capacity), or contact the visitor directly if you want to recover the sale.
Calendar invite missing on a confirmed registration — most often a calendar disconnect on your end (Google or Microsoft 365 revoked your refresh token; the dashboard banner will say 'Reconnect'). The confirmation email still went out, but it carries a manually-entered meeting URL or no URL if neither was set. Reconnect the calendar, then for future registrations the invite will land cleanly. Existing registrations on that date were already emailed; resend manually if needed.
Tenant inbox flooded by per-registration emails — disable the 'Notify me on each registration' toggle on the service form. The list page, the detail page, and the reminder crons keep working; only the per-registration email is suppressed.
Wrong start time on the materialised session — the start time is whatever the first booker picked from your weekly availability. If the time is wrong for you, cancel every registration on that session from the detail page (refunds fire automatically for paid ones); deleting the last registration tears down the event row, freeing the date for a new first booker. Adjust your weekly availability if the wrong-time pattern is recurring.
