CursivaDocs
Learners

Learners and enrollments

An enrollment is the link between a person and a piece of content: it is born from a self-enrollment, an approved request, a purchase, or a grant from the team, and its state controls who has access to the course. This page explains each entry path, the enrollment lifecycle, intake forms, and how to track, restart, and refund learners in Cursiva.

Learner, enrollment, and purchase

Three records work together, and it's worth telling them apart:

  • Learner (enrollment): the row that ties a user to a piece of content. It stores progress, intake answers, and the status. It is what grants — or withholds — access.
  • Purchase: a financial record for paid content. It is only written after the Stripe checkout is confirmed. It outlives the content and has no foreign key to the enrollment.
  • Member: someone on the organization's staff. Don't confuse them with a learner — members produce and manage content; learners consume it. See /docs/teams for the staff roles.

Ways to enroll

The entry path depends on how the content is configured — whether it is free or paid and whether it requires approval. Price is always the access boundary: content with a price requires a verified purchase before enrollment.

PathWhen it appliesHow it happens
Self-enrollment (free and open)Free content, no approvalThe learner clicks enroll and joins instantly; intake is validated on the spot
Request + approvalFree content marked "requires approval"The learner submits a request with their intake answers; the team approves or declines
Purchase (checkout)Content with a priceThe learner pays first; the enrollment is created after the charge is confirmed
Purchase + approval (pay first)Priced content with "requires approval"Pays first; the payment becomes a request the team approves (declining triggers a refund)
Grant by the team/APIAny published contentAn admin enrolls another person without requiring a purchase, respecting the seat limit

A few important details for each path:

  • Free self-enrollment: only works when the content is free and doesn't require approval. If the content requires approval, self-enrollment is blocked and the person must submit a request.
  • Enrollment request: learner-initiated requests are for free courses that require approval. The request holds the intake answers until the team decides. On approval, the answers travel to the learner's row and the request is removed.
  • Purchase: Cursiva never talks directly to Stripe in the core — the purchase is recorded only when the checkout returns verified as paid. Only then is the enrollment created. Details on pricing, coupons, and seats live in /docs/pricing-checkout.
  • Purchase + approval (pay first): the checkout creates the request after the charge. This path skips both the "free only" lock and intake validation — for the buyer, the payment is the form. If the team declines, the buyer must be refunded.
  • Grant by the team/API: an admin with edit rights on the content can enroll another person (comp), without requiring a purchase. The content must be published, and the seat limit still applies.

Enrollment lifecycle (status)

Every enrollment carries a status. Only active grants access — the refunded and past_due rows are kept to preserve history and progress, but every access predicate excludes them.

StatusGrants access?Meaning
activeYesValid enrollment. It's the only status that unlocks the content
refundedNoThe purchase was refunded. The row remains (history and progress), but access is revoked
past_dueNoDelinquent installment plan. Access freezes after a failed charge and returns on the next paid invoice

Transitions are driven by payment events and by team actions:

  • A refund moves the enrollment to refunded and revokes access, but keeps the row and the progress.
  • A failed installment moves the enrollment to past_due (frozen); the next paid invoice returns it to active; a canceled plan becomes refunded.
  • Repurchasing after a refund reactivates the same row instead of creating another — the previous enrollment and progress are restored.

Intake forms (enrollment questions)

Intake forms collect information before the learner begins. There are two ways to define the questions:

  • Questions embedded in the content: configured directly in the content editor.
  • Reusable forms (Settings → Intakes): a named set of questions that the organization attaches to multiple pieces of content by live reference. Any member can pick a form; creating, editing, or deleting one requires organization admin.

When a reusable form is deleted, the content that referenced it automatically falls back to its embedded questions — the reference is ON DELETE SET NULL, so no content is left without a form.

Field types

An intake form accepts the field types below. Each answer is normalized (trimmed) and validated according to its type before being stored.

TypeFieldValidation applied
textShort textFree text, up to 2000 characters
textareaLong textFree multi-line text, up to 2000 characters
emailEmailMust be a valid email format
phonePhonePermissive: digits plus the usual separators (formats vary by country)
numberNumberInteger or decimal (negatives allowed)
dateDateISO format YYYY-MM-DD
selectChoice (list)The value must be one of the options; 2 to 20 options per field
fileFileThe answer is the upload URL (/uploads/… or an http(s) address)

Any field can be marked required, and an optional description appears as help text under the label. The form limits protect the enrollment flow:

LimitValue
Questions per form10
Options per choice field2 to 20
Question label200 characters
Help text (description)300 characters
Learner answer2000 characters
Reusable form name80 characters

Who fills it in and where the answers show up

Not every learner goes through intake — whoever pays is excused from the form, because the payment is already the approval.

Entry pathFills in the intake?Note
Free self-enrollmentYesRequired fields are enforced before joining
Free request + approvalYes, when submitting the requestThe answers stay with the request and migrate to the enrollment on approval
Purchase (checkout)NoThe buyer skips the intake; required fields don't block a paid enrollment
Grant by the team/APINoStaff don't fill it in; answers from an approved request travel along

Answers are written to the learner's enrollment (or to the request, while it's pending). The team consults them in the Learners tab of the content editor and in the pending-request queue. Only ask for data with a clear use, and explain why each piece of information is needed.

Seat limits

A piece of content can have a seat limit. The course page shows the remaining seats before the enroll click (in the style of "3 seats left"), and the limit is enforced in a serialized way at the moment of enrollment, so that concurrent sign-ups don't blow past capacity.

  • The limit only counts new, active enrollments. A reactivated row (one that was refunded or past_due) already occupied a seat and doesn't count again.
  • In dated courses, the seat limit is per cohort, not per content.
  • Team grants also respect the seat limit.

Tracking learners

There are two main places to keep track of who is enrolled:

  • The content's Learners tab: lists that content's learners with who they are, their progress on the path (steps completed out of the total, including referenced modules), the result of the last quiz, and the active purchase (which enables the refund).
  • The organization's learners page: a paginated view of all enrollments, newest to oldest. Search matches by name or email directly in the database (not just the loaded page), and there's a filter by status (in progress or completed).

Tags and teams help segment the operation. Prefer stable criteria — role, cohort, or program — over temporary groups created for each task. For aggregate metrics (enrollments, completions, and quiz performance), see /docs/insights.

Restarting the course

Restarting resets a learner's progress on a piece of content. It's a team action that requires edit rights on the content.

  • Erases the entire progress map of the enrollment — the root and every referenced module — and reopens completion.
  • Quiz history is kept: it feeds the mastery model and the insights, so it isn't erased on restart.
  • It doesn't change the enrollment's status or the purchase link — only the progress.

Removing an enrollment and refunds

Removing the enrollment (unenroll) is a team action with edit rights. It removes the learner's row and their membership in any cohort at the same time and, if there is an active installment plan, signals a cancellation of the Stripe subscription — removing access never leaves the billing running.

Refunding is distinct from removing. The refund is executed after the Stripe reversal is confirmed, and then it:

  • Marks the purchase as refunded (a purchase refunds only once).
  • Revokes access by moving the enrollment to refunded — the row and the progress remain for history.
  • Uncounts the coupon that the sale had consumed, so that a limited-use code isn't eroded by refunded purchases.

Refunding moves money, so it requires billing rights (finance/admin on the owning team, or owner/admin on the organization). The rules for amounts, installments, and coupons — including the automatic refund when an upfront payment is declined at approval — are in /docs/payments-payouts.

Next steps