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 course and to the chosen offer of that course. It stores progress, intake answers, and the status. It is the only record that grants — or withholds — access. A paid enrollment also points to the exact purchase currently backing it; free and comped enrollments keep purchaseId null.
  • Purchase: the permanent financial record for a paid course and the exact offer sold. It is only written after the connected provider proves the payment. It records money and payment lifecycle, but never grants course reading by itself.
  • 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

Every course is born with an offer (the default "Standard" one, free until priced), so a published course is always enrollable — only materials, which never carry offers, are not. When several offers exist, the learner picks one before entering; that choice follows the request, purchase, and enrollment. The entry path depends on how that offer is configured — whether it is free or paid and whether it requires approval.

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 team has 30 days to decide (declining or expiry 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 and, after a decision, remains as history with status: approved, rejected, or expired. On approval, the answers also travel to the learner's row.
  • Purchase: Cursiva never talks directly to a concrete payment SDK in the core — the purchase is recorded only when the provider proves the checkout paid. Stripe is re-read server-side; an external checkout confirms through a signed webhook. 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, or does not decide within 30 calendar days, the buyer is refunded automatically. Approval is blocked after the deadline; free requests do not expire.
  • 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.

Decision deadline for a paid request

This rule applies only when the person has already paid and the offer requires approval:

StateWhat the team can doWhat happens to the payment
Less than 30 daysApprove or rejectApproval creates the enrollment; rejection refunds
30 full days or moreNo manual decisionApproval is blocked and the refund waits for the daily job
Refund confirmedThe request leaves the operational queue but stays in historyThe purchase receives refundedAt and the buyer is notified
Provider failureThe request remains Refund pendingCursiva retries the next day

The 30 days start at the paid request's createdAt. The learner has no access while waiting: only approval creates an active enrollment. A free request has no purchaseId, never enters this job, and remains available for approval or rejection without automatic expiry.

The persistent learnerRequest lifecycle is deliberately small:

StatusMeaning
pendingOpen decision; the only state that accepts manual approval or rejection
approvedThe decision created/activated the enrollment; the request stays as history
rejectedStaff or a cancellation closed the request; when paid, purchase.refundedAt says whether money has returned
expiredThe 30-day paid window ended; the worker returns the money idempotently

Terminal states keep resolvedAt; resolvedBy identifies the person who decided when there is one, and rejectionReason stores the optional decline note. None of these fields grants access or proves a refund.

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.

learner.status is the single access source. Payment events may change it only when their exact purchase.id still equals the learner's purchaseId. Repurchasing rebinds the same learner row to the new purchase, so a delayed refund or installment webhook from an older sale cannot revoke the current enrollment. Paid approval requests carry the same exact pointer until they become learners; free requests keep it null.

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.
  • If the new offer requires approval, the refunded learner may open a new pay-first request; approval reuses that same row and changes only its current offer, purchase, and cohort.

Intake forms (enrollment questions)

Intake forms collect information before the learner begins. The questions live in one place only: reusable forms (Settings → Intakes) — a named set of questions that the organization attaches to an offer by live reference. The content editor only picks a form from that list; there are no per-content custom questions. Any member can pick a form; creating, editing, or deleting one requires organization admin.

Deleting a reusable form does not delete the offers that referenced it — the reference is ON DELETE SET NULL. Those offers are left with no intake questions at all and enrollment keeps working without collecting anything, so point them at another form before deleting the old one.

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

Each offer can have its own seat limit. The course page shows the selected offer's remaining seats before the enroll click (in the style of "3 seats left"), and the limit is enforced in a serialized way at enrollment time so concurrent sign-ups cannot exceed capacity.

  • The limit counts only active enrollments bound to that offer. A refund frees a seat; reactivation consumes one again.
  • In dated courses, the cohort may have its own limit in addition to the offer-wide limit.
  • 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 the connected provider supports an active installment plan, requests its cancellation — removing access never intentionally leaves billing running.

Refunding is distinct from removing. Its provider-specific operation must be confirmed before Cursiva records the refund, 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 pricing rights: an organization owner or admin, the content's owner, or a member of the owning team carrying the finance role. 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

Your privacy choices

Necessary cookies keep Cursiva working. Analytics and marketing technologies are optional and stay off until you choose them. Privacy Policy.